diff options
Diffstat (limited to 'source4/lib/events/events_standard.c')
-rw-r--r-- | source4/lib/events/events_standard.c | 366 |
1 files changed, 183 insertions, 183 deletions
diff --git a/source4/lib/events/events_standard.c b/source4/lib/events/events_standard.c index 77797eec64..96f938c78e 100644 --- a/source4/lib/events/events_standard.c +++ b/source4/lib/events/events_standard.c @@ -1,7 +1,8 @@ /* Unix SMB/CIFS implementation. main select loop and event handling - Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Tridgell 2003-2005 + Copyright (C) Stefan Metzmacher 2005 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,47 +20,19 @@ */ /* - PLEASE READ THIS BEFORE MODIFYING! - - This module is a general abstraction for the main select loop and - event handling. Do not ever put any localised hacks in here, instead - register one of the possible event types and implement that event - somewhere else. - - There are 2 types of event handling that are handled in this module: - - 1) a file descriptor becoming readable or writeable. This is mostly - used for network sockets, but can be used for any type of file - descriptor. You may only register one handler for each file - descriptor/io combination or you will get unpredictable results - (this means that you can have a handler for read events, and a - separate handler for write events, but not two handlers that are - both handling read events) - - 2) a timed event. You can register an event that happens at a - specific time. You can register as many of these as you - like. They are single shot - add a new timed event in the event - handler to get another event. - - To setup a set of events you first need to create a event_context - structure using the function event_context_init(); This returns a - 'struct event_context' that you use in all subsequent calls. - - After that you can add/remove events that you are interested in - using event_add_*() and talloc_free() - - Finally, you call event_loop_wait() to block waiting for one of the - events to occor. In normal operation event_loop_wait() will loop - forever. + This is SAMBA's default event loop code + - we try to use epoll if configure detected support for it + otherwise we use select() + - if epoll is broken on the system or the kernel doesn't support it + at runtime we fallback to select() */ #include "includes.h" -#include "system/time.h" -#include "system/select.h" #include "system/filesys.h" #include "dlinklist.h" #include "lib/events/events.h" +#include "lib/events/events_internal.h" /* use epoll if it is available */ #if defined(HAVE_EPOLL_CREATE) && defined(HAVE_SYS_EPOLL_H) @@ -70,25 +43,12 @@ #include <sys/epoll.h> #endif -struct event_context { +struct std_event_context { /* list of filedescriptor events */ - struct fd_event { - struct event_context *event_ctx; - struct fd_event *next, *prev; - int fd; - uint16_t flags; /* see EVENT_FD_* flags */ - event_fd_handler_t handler; - void *private; - } *fd_events; + struct fd_event *fd_events; /* list of timed events */ - struct timed_event { - struct event_context *event_ctx; - struct timed_event *next, *prev; - struct timeval next_event; - event_timed_handler_t handler; - void *private; - } *timed_events; + struct timed_event *timed_events; /* the maximum file descriptor number in fd_events */ int maxfd; @@ -110,54 +70,57 @@ struct event_context { #endif }; - /* destroy an event context */ -static int event_context_destructor(void *ptr) +static int std_event_context_destructor(void *ptr) { #if WITH_EPOLL struct event_context *ev = talloc_get_type(ptr, struct event_context); - if (ev->epoll_fd != -1) { - close(ev->epoll_fd); - ev->epoll_fd = -1; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + if (std_ev->epoll_fd != -1) { + close(std_ev->epoll_fd); + std_ev->epoll_fd = -1; } #endif return 0; } /* - create a event_context structure. This must be the first events - call, and all subsequent calls pass this event_context as the first - element. Event handlers also receive this as their first argument. + create a std_event_context structure. */ -struct event_context *event_context_init(TALLOC_CTX *mem_ctx) +static int std_event_context_init(struct event_context *ev, void *privata_data) { - struct event_context *ev; + struct std_event_context *std_ev; - ev = talloc_zero(mem_ctx, struct event_context); - if (!ev) return NULL; + std_ev = talloc_zero(ev, struct std_event_context); + if (!std_ev) return -1; #if WITH_EPOLL - ev->epoll_fd = epoll_create(64); + std_ev->epoll_fd = epoll_create(64); #endif - talloc_set_destructor(ev, event_context_destructor); + ev->additional_data = std_ev; - return ev; -} + talloc_set_destructor(ev, std_event_context_destructor); + return 0; +} /* recalculate the maxfd */ static void calc_maxfd(struct event_context *ev) { - struct fd_event *e; - ev->maxfd = 0; - for (e=ev->fd_events; e; e=e->next) { - if (e->fd > ev->maxfd) { - ev->maxfd = e->fd; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct fd_event *fde; + + std_ev->maxfd = 0; + for (fde = std_ev->fd_events; fde; fde = fde->next) { + if (fde->fd > std_ev->maxfd) { + std_ev->maxfd = fde->fd; } } } @@ -176,9 +139,11 @@ static void calc_maxfd(struct event_context *ev) */ static void epoll_fallback_to_select(struct event_context *ev, const char *reason) { + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); DEBUG(0,("%s (%s) - falling back to select()\n", reason, strerror(errno))); - close(ev->epoll_fd); - ev->epoll_fd = -1; + close(std_ev->epoll_fd); + std_ev->epoll_fd = -1; } #endif @@ -199,23 +164,25 @@ static uint32_t epoll_map_flags(uint16_t flags) /* destroy an fd_event */ -static int event_fd_destructor(void *ptr) +static int std_event_fd_destructor(void *ptr) { struct fd_event *fde = talloc_get_type(ptr, struct fd_event); struct event_context *ev = fde->event_ctx; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); - if (ev->maxfd == fde->fd) { - ev->maxfd = EVENT_INVALID_MAXFD; + if (std_ev->maxfd == fde->fd) { + std_ev->maxfd = EVENT_INVALID_MAXFD; } - DLIST_REMOVE(ev->fd_events, fde); - ev->destruction_count++; + DLIST_REMOVE(std_ev->fd_events, fde); + std_ev->destruction_count++; #if WITH_EPOLL - if (ev->epoll_fd != -1) { + if (std_ev->epoll_fd != -1) { struct epoll_event event; ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); event.data.ptr = fde; - epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); + epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); } #endif return 0; @@ -225,50 +192,53 @@ static int event_fd_destructor(void *ptr) add a fd based event return NULL on failure (memory allocation error) */ -struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, - int fd, uint16_t flags, event_fd_handler_t handler, - void *private) +static struct fd_event *std_event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data) { - struct fd_event *e = talloc(ev, struct fd_event); - if (!e) return NULL; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct fd_event *fde; - e->event_ctx = ev; - e->fd = fd; - e->flags = flags; - e->handler = handler; - e->private = private; + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; - DLIST_ADD(ev->fd_events, e); + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_data = NULL; - if (e->fd > ev->maxfd) { - ev->maxfd = e->fd; - } + DLIST_ADD(std_ev->fd_events, fde); - talloc_set_destructor(e, event_fd_destructor); - if (mem_ctx) { - talloc_steal(mem_ctx, e); + if (fde->fd > std_ev->maxfd) { + std_ev->maxfd = fde->fd; } + talloc_set_destructor(fde, std_event_fd_destructor); + #if WITH_EPOLL - if (ev->epoll_fd != -1) { + if (std_ev->epoll_fd != -1) { struct epoll_event event; ZERO_STRUCT(event); event.events = epoll_map_flags(flags); - event.data.ptr = e; - if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_ADD, e->fd, &event) != 0) { + event.data.ptr = fde; + if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_ADD, fde->fd, &event) != 0) { epoll_fallback_to_select(ev, "EPOLL_CTL_ADD failed"); } } #endif - return e; + return fde; } /* return the fd event flags */ -uint16_t event_fd_flags(struct fd_event *fde) +static uint16_t std_event_get_fd_flags(struct fd_event *fde) { return fde?fde->flags:0; } @@ -276,21 +246,23 @@ uint16_t event_fd_flags(struct fd_event *fde) /* set the fd event flags */ -void event_fd_setflags(struct fd_event *fde, uint16_t flags) +static void std_event_set_fd_flags(struct fd_event *fde, uint16_t flags) { #if WITH_EPOLL struct event_context *ev; + struct std_event_context *std_ev; if (fde == NULL || fde->flags == flags) { return; } ev = fde->event_ctx; - if (ev->epoll_fd != -1) { + std_ev = talloc_get_type(ev->additional_data, struct std_event_context); + if (std_ev->epoll_fd != -1) { struct epoll_event event; ZERO_STRUCT(event); event.events = epoll_map_flags(flags); event.data.ptr = fde; - if (epoll_ctl(ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { + if (epoll_ctl(std_ev->epoll_fd, EPOLL_CTL_MOD, fde->fd, &event) != 0) { epoll_fallback_to_select(ev, "EPOLL_CTL_MOD failed"); } } @@ -303,10 +275,12 @@ void event_fd_setflags(struct fd_event *fde, uint16_t flags) /* destroy a timed event */ -static int event_timed_destructor(void *ptr) +static int std_event_timed_destructor(void *ptr) { struct timed_event *te = talloc_get_type(ptr, struct timed_event); - DLIST_REMOVE(te->event_ctx->timed_events, te); + struct std_event_context *std_ev = talloc_get_type(te->event_ctx->additional_data, + struct std_event_context); + DLIST_REMOVE(std_ev->timed_events, te); return 0; } @@ -314,56 +288,63 @@ static int event_timed_destructor(void *ptr) add a timed event return NULL on failure (memory allocation error) */ -struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, - struct timeval next_event, - event_timed_handler_t handler, - void *private) +static struct timed_event *std_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) { - struct timed_event *te, *e; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + struct timed_event *te, *last_te, *cur_te; - e = talloc(mem_ctx?mem_ctx:ev, struct timed_event); - if (e == NULL) return NULL; + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + if (te == NULL) return NULL; - e->event_ctx = ev; - e->next_event = next_event; - e->handler = handler; - e->private = private; + te->event_ctx = ev; + te->next_event = next_event; + te->handler = handler; + te->private_data = private_data; + te->additional_data = NULL; /* keep the list ordered */ - if (ev->timed_events == NULL || - timeval_compare(&e->next_event, &ev->timed_events->next_event) > 0) { - DLIST_ADD(ev->timed_events, e); - } else { - for (te=ev->timed_events;te && te->next;te=te->next) { - if (!timeval_is_zero(&te->next->next_event) && - timeval_compare(&te->next->next_event, &e->next_event) < 0) { - break; - } + last_te = NULL; + for (cur_te = std_ev->timed_events; cur_te; cur_te = cur_te->next) { + /* if the new event comes before the current one break */ + if (!timeval_is_zero(&cur_te->next_event) && + timeval_compare(&cur_te->next_event, &te->next_event) < 0) { + break; } - DLIST_ADD_AFTER(ev->timed_events, e, te); + + last_te = cur_te; } - talloc_set_destructor(e, event_timed_destructor); + DLIST_ADD_AFTER(std_ev->timed_events, te, last_te); + + talloc_set_destructor(te, std_event_timed_destructor); - return e; + return te; } /* a timer has gone off - call it */ -static void event_loop_timer(struct event_context *ev) +static void std_event_loop_timer(struct event_context *ev) { + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); struct timeval t = timeval_current(); - struct timed_event *te = ev->timed_events; + struct timed_event *te = std_ev->timed_events; te->next_event = timeval_zero(); - te->handler(ev, te, t, te->private); + te->handler(ev, te, t, te->private_data); /* note the care taken to prevent referencing a event that could have been freed by the handler */ - if (ev->timed_events && timeval_is_zero(&ev->timed_events->next_event)) { - talloc_free(ev->timed_events); + if (std_ev->timed_events) { + if (timeval_is_zero(&std_ev->timed_events->next_event)) { + talloc_free(te); + } } } @@ -371,12 +352,14 @@ static void event_loop_timer(struct event_context *ev) /* event loop handling using epoll */ -static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp) +static int std_event_loop_epoll(struct event_context *ev, struct timeval *tvalp) { + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); int ret, i; const int maxevents = 8; struct epoll_event events[maxevents]; - uint32_t destruction_count = ev->destruction_count; + uint32_t destruction_count = std_ev->destruction_count; int timeout = -1; if (tvalp) { @@ -384,7 +367,7 @@ static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp) timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); } - ret = epoll_wait(ev->epoll_fd, events, maxevents, timeout); + ret = epoll_wait(std_ev->epoll_fd, events, maxevents, timeout); if (ret == -1 && errno != EINTR) { epoll_fallback_to_select(ev, "epoll_wait() failed"); @@ -392,7 +375,7 @@ static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp) } if (ret == 0 && tvalp) { - event_loop_timer(ev); + std_event_loop_timer(ev); return 0; } @@ -409,8 +392,8 @@ static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp) flags |= EVENT_FD_READ; if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE; if (flags) { - fde->handler(ev, fde, flags, fde->private); - if (destruction_count != ev->destruction_count) { + fde->handler(ev, fde, flags, fde->private_data); + if (destruction_count != std_ev->destruction_count) { break; } } @@ -423,48 +406,48 @@ static int event_loop_epoll(struct event_context *ev, struct timeval *tvalp) /* event loop handling using select() */ -static int event_loop_select(struct event_context *ev, struct timeval *tvalp) +static int std_event_loop_select(struct event_context *ev, struct timeval *tvalp) { + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); fd_set r_fds, w_fds; + struct fd_event *fde; int selrtn; - uint32_t destruction_count = ev->destruction_count; - struct fd_event *fe; + uint32_t destruction_count = std_ev->destruction_count; /* we maybe need to recalculate the maxfd */ - if (ev->maxfd == EVENT_INVALID_MAXFD) { + if (std_ev->maxfd == EVENT_INVALID_MAXFD) { calc_maxfd(ev); } - + FD_ZERO(&r_fds); FD_ZERO(&w_fds); /* setup any fd events */ - for (fe=ev->fd_events; fe; ) { - struct fd_event *next = fe->next; - if (fe->flags & EVENT_FD_READ) { - FD_SET(fe->fd, &r_fds); + for (fde = std_ev->fd_events; fde; fde = fde->next) { + if (fde->flags & EVENT_FD_READ) { + FD_SET(fde->fd, &r_fds); } - if (fe->flags & EVENT_FD_WRITE) { - FD_SET(fe->fd, &w_fds); + if (fde->flags & EVENT_FD_WRITE) { + FD_SET(fde->fd, &w_fds); } - fe = next; } - selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); - + selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp); + if (selrtn == -1 && errno == EBADF) { /* the socket is dead! this should never happen as the socket should have first been made readable and that should have removed the event, so this must be a bug. This is a fatal error. */ - DEBUG(0,("ERROR: EBADF on event_loop_once\n")); - ev->exit_code = EBADF; + DEBUG(0,("ERROR: EBADF on std_event_loop_once\n")); + std_ev->exit_code = EBADF; return -1; } if (selrtn == 0 && tvalp) { - event_loop_timer(ev); + std_event_loop_timer(ev); return 0; } @@ -472,13 +455,14 @@ static int event_loop_select(struct event_context *ev, struct timeval *tvalp) /* at least one file descriptor is ready - check which ones and call the handler, being careful to allow the handler to remove itself when called */ - for (fe=ev->fd_events; fe; fe=fe->next) { + for (fde = std_ev->fd_events; fde; fde = fde->next) { uint16_t flags = 0; - if (FD_ISSET(fe->fd, &r_fds)) flags |= EVENT_FD_READ; - if (FD_ISSET(fe->fd, &w_fds)) flags |= EVENT_FD_WRITE; + + if (FD_ISSET(fde->fd, &r_fds)) flags |= EVENT_FD_READ; + if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE; if (flags) { - fe->handler(ev, fe, flags, fe->private); - if (destruction_count != ev->destruction_count) { + fde->handler(ev, fde, flags, fde->private_data); + if (destruction_count != std_ev->destruction_count) { break; } } @@ -491,51 +475,67 @@ static int event_loop_select(struct event_context *ev, struct timeval *tvalp) /* do a single event loop using the events defined in ev */ -int event_loop_once(struct event_context *ev) +static int std_event_loop_once(struct event_context *ev) { + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); struct timeval tval, *tvalp; tvalp = NULL; - + /* work out the right timeout for all timed events */ - if (ev->timed_events) { + if (std_ev->timed_events) { struct timeval t = timeval_current(); - tval = timeval_diff(&ev->timed_events->next_event, &t); + + tval = timeval_diff(&std_ev->timed_events->next_event, &t); tvalp = &tval; if (timeval_is_zero(tvalp)) { - event_loop_timer(ev); + std_event_loop_timer(ev); return 0; } } #if WITH_EPOLL - if (ev->epoll_fd != -1) { - if (event_loop_epoll(ev, tvalp) == 0) { + if (std_ev->epoll_fd != -1) { + if (std_event_loop_epoll(ev, tvalp) == 0) { return 0; } } #endif - return event_loop_select(ev, tvalp); + return std_event_loop_select(ev, tvalp); } /* - go into an event loop using the events defined in ev this function - will return with the specified code if one of the handlers calls - event_loop_exit() - - also return (with code 0) if all fd events are removed + return on failure or (with 0) if all fd events are removed */ -int event_loop_wait(struct event_context *ev) +static int std_event_loop_wait(struct event_context *ev) { - ev->exit_code = 0; - ev->maxfd = EVENT_INVALID_MAXFD; + struct std_event_context *std_ev = talloc_get_type(ev->additional_data, + struct std_event_context); + std_ev->exit_code = 0; + std_ev->maxfd = EVENT_INVALID_MAXFD; - while (ev->fd_events && ev->exit_code == 0) { - if (event_loop_once(ev) != 0) { + while (std_ev->fd_events && std_ev->exit_code == 0) { + if (std_event_loop_once(ev) != 0) { break; } } - return ev->exit_code; + return std_ev->exit_code; +} + +static const struct event_ops std_event_ops = { + .context_init = std_event_context_init, + .add_fd = std_event_add_fd, + .get_fd_flags = std_event_get_fd_flags, + .set_fd_flags = std_event_set_fd_flags, + .add_timed = std_event_add_timed, + .loop_once = std_event_loop_once, + .loop_wait = std_event_loop_wait, +}; + +const struct event_ops *event_standard_get_ops(void) +{ + return &std_event_ops; } |