summaryrefslogtreecommitdiff
path: root/source4/lib/events.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2004-07-23 06:40:49 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:57:42 -0500
commit5ddf678e0113f81aa2b5f99134cda4fe8c01afb7 (patch)
tree68e10d04766a1ad8e05f30c4d58e4398343ac7fb /source4/lib/events.c
parent1ce4a2d5fecae297e5b6f6e8f0d68534d9dc7c92 (diff)
downloadsamba-5ddf678e0113f81aa2b5f99134cda4fe8c01afb7.tar.gz
samba-5ddf678e0113f81aa2b5f99134cda4fe8c01afb7.tar.bz2
samba-5ddf678e0113f81aa2b5f99134cda4fe8c01afb7.zip
r1578: the first stage of the async client rewrite.
Up to now the client code has had an async API, and operated asynchronously at the packet level, but was not truly async in that it assumed that it could always write to the socket and when a partial packet came in that it could block waiting for the rest of the packet. This change makes the SMB client library full async, by adding a separate outgoing packet queue, using non-blocking socket IO and having a input buffer that can fill asynchonously until the full packet has arrived. The main complexity was in dealing with the events structure when using the CIFS proxy backend. In that case the same events structure needs to be used in both the client library and the main smbd server, so that when the client library is waiting for a reply that the main server keeps processing packets. This required some changes in the events library code. Next step is to make the generated rpc client code use these new capabilities. (This used to be commit 96bf4da3edc4d64b0f58ef520269f3b385b8da02)
Diffstat (limited to 'source4/lib/events.c')
-rw-r--r--source4/lib/events.c344
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;