diff options
Diffstat (limited to 'source4/lib')
-rw-r--r-- | source4/lib/events.c | 344 |
1 files changed, 209 insertions, 135 deletions
diff --git a/source4/lib/events.c b/source4/lib/events.c index 13a9a444e8..a6099db5c5 100644 --- a/source4/lib/events.c +++ b/source4/lib/events.c @@ -81,25 +81,50 @@ struct event_context *event_context_init(void) /* start off with no events */ ZERO_STRUCTP(ev); + ev->ref_count = 1; + return ev; } - - /* - add a fd based event - return NULL on failure (memory allocation error) + destroy an events context, also destroying any remaining events */ -struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e) +void event_context_destroy(struct event_context *ev) { - e = memdup(e, sizeof(*e)); - if (!e) return NULL; - DLIST_ADD(ev->fd_events, e); - e->ref_count = 1; - if (e->fd > ev->maxfd) { - ev->maxfd = e->fd; + struct fd_event *fde; + struct timed_event *te; + struct loop_event *le; + + ev->ref_count--; + if (ev->ref_count != 0) { + return; } - return e; + + for (fde=ev->fd_events; fde;) { + struct fd_event *next = fde->next; + event_remove_fd(ev, fde); + if (fde->ref_count == 0) { + free(fde); + } + fde=next; + } + for (te=ev->timed_events; te;) { + struct timed_event *next = te->next; + event_remove_timed(ev, te); + if (te->ref_count == 0) { + free(te); + } + te=next; + } + for (le=ev->loop_events; le;) { + struct loop_event *next = le->next; + event_remove_loop(ev, le); + if (le->ref_count == 0) { + free(le); + } + le=next; + } + free(ev); } @@ -118,6 +143,47 @@ static void calc_maxfd(struct event_context *ev) } } +/* + move the event structures from ev2 into ev, upping the reference + count on ev. The event context ev2 is then destroyed. + + this is used by modules that need to call on the events of a lower module +*/ +void event_context_merge(struct event_context *ev, struct event_context *ev2) +{ + DLIST_CONCATENATE(ev->fd_events, ev2->fd_events, struct fd_event *); + DLIST_CONCATENATE(ev->timed_events, ev2->timed_events, struct timed_event *); + DLIST_CONCATENATE(ev->loop_events, ev2->loop_events, struct loop_event *); + + ev->ref_count++; + + ev2->fd_events = NULL; + ev2->timed_events = NULL; + ev2->loop_events = NULL; + + event_context_destroy(ev2); + + calc_maxfd(ev); +} + + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +struct fd_event *event_add_fd(struct event_context *ev, struct fd_event *e) +{ + e = memdup(e, sizeof(*e)); + if (!e) return NULL; + DLIST_ADD(ev->fd_events, e); + e->ref_count = 1; + if (e->fd > ev->maxfd) { + ev->maxfd = e->fd; + } + return e; +} + + /* to mark the ev->maxfd invalid * this means we need to recalculate it */ @@ -242,150 +308,158 @@ void event_loop_exit(struct event_context *ev, int code) } /* - 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 + do a single event loop using the events defined in ev this function */ -int event_loop_wait(struct event_context *ev) +void event_loop_once(struct event_context *ev) { time_t t; - - ZERO_STRUCT(ev->exit); - ev->maxfd = EVENT_INVALID_MAXFD; + fd_set r_fds, w_fds; + struct fd_event *fe; + struct loop_event *le; + struct timed_event *te; + int selrtn; + struct timeval tval; t = time(NULL); - while (ev->fd_events && !ev->exit.exit_now) { - fd_set r_fds, w_fds; - struct fd_event *fe; - struct loop_event *le; - struct timed_event *te; - int selrtn; - struct timeval tval; - - /* the loop events are called on each loop. Be careful to allow the - event to remove itself */ - for (le=ev->loop_events;le;) { - struct loop_event *next = le->next; - if (le->ref_count == 0) { - DLIST_REMOVE(ev->loop_events, le); - free(le); - } else { - le->ref_count++; - le->handler(ev, le, t); - le->ref_count--; - } - le = next; + /* the loop events are called on each loop. Be careful to allow the + event to remove itself */ + for (le=ev->loop_events;le;) { + struct loop_event *next = le->next; + if (le->ref_count == 0) { + DLIST_REMOVE(ev->loop_events, le); + free(le); + } else { + le->ref_count++; + le->handler(ev, le, t); + le->ref_count--; } + le = next; + } - ZERO_STRUCT(tval); - 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->ref_count == 0) { - DLIST_REMOVE(ev->fd_events, fe); - if (ev->maxfd == fe->fd) { - ev->maxfd = EVENT_INVALID_MAXFD; - } - free(fe); - } else { - if (fe->flags & EVENT_FD_READ) { - FD_SET(fe->fd, &r_fds); - } - if (fe->flags & EVENT_FD_WRITE) { - FD_SET(fe->fd, &w_fds); - } + ZERO_STRUCT(tval); + 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->ref_count == 0) { + DLIST_REMOVE(ev->fd_events, fe); + if (ev->maxfd == fe->fd) { + ev->maxfd = EVENT_INVALID_MAXFD; + } + free(fe); + } else { + if (fe->flags & EVENT_FD_READ) { + FD_SET(fe->fd, &r_fds); + } + if (fe->flags & EVENT_FD_WRITE) { + FD_SET(fe->fd, &w_fds); } - fe = next; } + fe = next; + } - /* start with a reasonable max timeout */ - tval.tv_sec = 600; + /* start with a reasonable max timeout */ + tval.tv_sec = 600; - /* work out the right timeout for all timed events */ - for (te=ev->timed_events;te;te=te->next) { - int timeout = te->next_event - t; - if (timeout < 0) { - timeout = 0; - } - if (te->ref_count && - timeout < tval.tv_sec) { - tval.tv_sec = timeout; - } + /* work out the right timeout for all timed events */ + for (te=ev->timed_events;te;te=te->next) { + int timeout = te->next_event - t; + if (timeout < 0) { + timeout = 0; } + if (te->ref_count && + timeout < tval.tv_sec) { + tval.tv_sec = timeout; + } + } - /* only do a select() if there're fd_events - * otherwise we would block for a the time in tval, - * and if there're no fd_events present anymore we want to - * leave the event loop directly + /* only do a select() if there're fd_events + * otherwise we would block for a the time in tval, + * and if there're no fd_events present anymore we want to + * leave the event loop directly + */ + if (ev->fd_events) { + /* we maybe need to recalculate the maxfd */ + if (ev->maxfd == EVENT_INVALID_MAXFD) { + calc_maxfd(ev); + } + + /* TODO: + * we don't use sys_select() as it isn't thread + * safe. We need to replace the magic pipe handling in + * sys_select() with something in the events + * structure - for now just use select() */ - if (ev->fd_events) { - /* we maybe need to recalculate the maxfd */ - if (ev->maxfd == EVENT_INVALID_MAXFD) { - calc_maxfd(ev); - } - - /* TODO: - * we don't use sys_select() as it isn't thread - * safe. We need to replace the magic pipe handling in - * sys_select() with something in the events - * structure - for now just use select() - */ - selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval); - - t = time(NULL); - - 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,("EBADF on event_loop_wait - exiting\n")); - return -1; - } - - if (selrtn > 0) { - /* 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) { - 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 (fe->ref_count && flags) { - fe->ref_count++; - fe->handler(ev, fe, t, flags); - fe->ref_count--; - } + selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, &tval); + + t = time(NULL); + + 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,("EBADF on event_loop_wait - exiting\n")); + return; + } + + if (selrtn > 0) { + /* 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) { + 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 (fe->ref_count && flags) { + fe->ref_count++; + fe->handler(ev, fe, t, flags); + fe->ref_count--; } } } + } - /* call any timed events that are now due */ - for (te=ev->timed_events;te;) { - struct timed_event *next = te->next; - if (te->ref_count == 0) { - DLIST_REMOVE(ev->timed_events, te); - free(te); - } else if (te->next_event <= t) { - te->ref_count++; - te->handler(ev, te, t); - te->ref_count--; - if (te->next_event <= t) { - /* the handler didn't set a time for the - next event - remove the event */ - event_remove_timed(ev, te); - } + /* call any timed events that are now due */ + for (te=ev->timed_events;te;) { + struct timed_event *next = te->next; + if (te->ref_count == 0) { + DLIST_REMOVE(ev->timed_events, te); + free(te); + } else if (te->next_event <= t) { + te->ref_count++; + te->handler(ev, te, t); + te->ref_count--; + if (te->next_event <= t) { + /* the handler didn't set a time for the + next event - remove the event */ + event_remove_timed(ev, te); } - te = next; - } + } + te = next; + } +} + +/* + 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 +*/ +int event_loop_wait(struct event_context *ev) +{ + ZERO_STRUCT(ev->exit); + ev->maxfd = EVENT_INVALID_MAXFD; + + ev->exit.exit_now = False; + while (ev->fd_events && !ev->exit.exit_now) { + event_loop_once(ev); } return ev->exit.code; |