summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/include/dlinklist.h28
-rw-r--r--source4/lib/events.c142
2 files changed, 75 insertions, 95 deletions
diff --git a/source4/include/dlinklist.h b/source4/include/dlinklist.h
index 40f7f0a0c7..fbc7b43652 100644
--- a/source4/include/dlinklist.h
+++ b/source4/include/dlinklist.h
@@ -71,23 +71,15 @@ do { \
} \
} while (0)
-/* demote an element to the end of the list, needs a tmp pointer */
-#define DLIST_DEMOTE(list, p, tmp) \
+/* insert 'p' after the given element 'el' in a list. If el is NULL then
+ this is the same as a DLIST_ADD() */
+#define DLIST_ADD_AFTER(list, p, el) \
do { \
- DLIST_REMOVE(list, p); \
- DLIST_ADD_END(list, p, tmp); \
-} while (0)
-
-/* concatenate two lists - putting all elements of the 2nd list at the
- end of the first list */
-#define DLIST_CONCATENATE(list1, list2, type) \
-do { \
- if (!(list1)) { \
- (list1) = (list2); \
- } else { \
- type tmp; \
- for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
- tmp->next = (list2); \
- (list2)->prev = tmp; \
- } \
+ if (!(list) || !(el)) { \
+ DLIST_ADD(list, p); \
+ } else { \
+ p->prev = el; \
+ p->next = el->next; \
+ el->next = p; \
+ }\
} while (0)
diff --git a/source4/lib/events.c b/source4/lib/events.c
index b2e0404e34..10d15d8111 100644
--- a/source4/lib/events.c
+++ b/source4/lib/events.c
@@ -200,7 +200,6 @@ static int event_timed_destructor(void *ptr)
{
struct timed_event *te = talloc_get_type(ptr, struct timed_event);
DLIST_REMOVE(te->event_ctx->timed_events, te);
- te->event_ctx->destruction_count++;
return 0;
}
@@ -213,19 +212,32 @@ struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ct
event_timed_handler_t handler,
void *private)
{
- struct timed_event *e = talloc(ev, struct timed_event);
- if (!e) return NULL;
+ struct timed_event *te, *e;
+
+ e = talloc(mem_ctx?mem_ctx:ev, struct timed_event);
+ if (e == NULL) return NULL;
e->event_ctx = ev;
e->next_event = next_event;
e->handler = handler;
e->private = private;
- DLIST_ADD(ev->timed_events, e);
- talloc_set_destructor(e, event_timed_destructor);
- if (mem_ctx) {
- talloc_steal(mem_ctx, e);
+ /* 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_event) &&
+ timeval_compare(&te->next_event, &e->next_event) < 0) {
+ break;
+ }
+ }
+ DLIST_ADD_AFTER(ev->timed_events, e, te);
}
+
+ talloc_set_destructor(e, event_timed_destructor);
+
return e;
}
@@ -236,9 +248,8 @@ int event_loop_once(struct event_context *ev)
{
fd_set r_fds, w_fds;
struct fd_event *fe;
- struct timed_event *te, *te_next;
int selrtn;
- struct timeval tval, t, *tvalp;
+ struct timeval tval, *tvalp;
uint32_t destruction_count = ev->destruction_count;
FD_ZERO(&r_fds);
@@ -257,88 +268,65 @@ int event_loop_once(struct event_context *ev)
}
tvalp = NULL;
- t = timeval_current();
/* work out the right timeout for all timed events */
- for (te=ev->timed_events;te;te=te_next) {
- struct timeval tv;
- te_next = te->next;
- if (timeval_is_zero(&te->next_event)) {
- talloc_free(te);
- continue;
- }
- tv = timeval_diff(&te->next_event, &t);
- if (tvalp == NULL) {
- tval = tv;
- } else {
- tval = timeval_min(&tv, &tval);
- }
+ if (ev->timed_events) {
+ struct timeval t = timeval_current();
+ tval = timeval_diff(&ev->timed_events->next_event, &t);
tvalp = &tval;
}
- /* 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);
- }
+ /* 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, tvalp);
+ selrtn = select(ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);
- t = timeval_current();
+ 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;
+ return -1;
+ }
- 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_once - exiting\n"));
- ev->exit_code = EBADF;
- return -1;
+ if (selrtn == 0) {
+ struct timeval t = timeval_current();
+ struct timed_event *te = ev->timed_events;
+
+ te->next_event = timeval_zero();
+
+ te->handler(ev, te, t, te->private);
+
+ /* 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 (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 (flags) {
- fe->handler(ev, fe, t, flags, fe->private);
- if (destruction_count != ev->destruction_count) {
- break;
- }
+ }
+
+ if (selrtn > 0) {
+ struct timeval t = timeval_current();
+ /* 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 (flags) {
+ fe->handler(ev, fe, t, flags, fe->private);
+ if (destruction_count != ev->destruction_count) {
+ break;
}
}
}
}
- /* call any timed events that are now due */
- for (te=ev->timed_events;te;) {
- struct timed_event *next = te->next;
- if (timeval_compare(&te->next_event, &t) >= 0) {
- te->next_event = timeval_zero();
- te->handler(ev, te, t, te->private);
- if (destruction_count != ev->destruction_count) {
- break;
- }
- }
- te = next;
- }
-
return 0;
}