From 66886f8966dff8a980a5b9d2daa3fbb20fe5ca8e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 13 Mar 2009 15:47:33 +0100 Subject: tevent: add support for immediate events They're like directly triggered timed events, but you can preallocated them and scheduling them will not fail. metze --- lib/tevent/libtevent.m4 | 3 +- lib/tevent/tevent.c | 49 +++++++++++++++ lib/tevent/tevent.h | 19 ++++++ lib/tevent/tevent_epoll.c | 28 +++++---- lib/tevent/tevent_immediate.c | 139 ++++++++++++++++++++++++++++++++++++++++++ lib/tevent/tevent_internal.h | 35 +++++++++++ lib/tevent/tevent_select.c | 28 +++++---- lib/tevent/tevent_standard.c | 28 +++++---- 8 files changed, 295 insertions(+), 34 deletions(-) create mode 100644 lib/tevent/tevent_immediate.c (limited to 'lib') diff --git a/lib/tevent/libtevent.m4 b/lib/tevent/libtevent.m4 index c316823a71..20730b17d6 100644 --- a/lib/tevent/libtevent.m4 +++ b/lib/tevent/libtevent.m4 @@ -26,7 +26,8 @@ AC_SUBST(TEVENT_LIBS) TEVENT_CFLAGS="-I$teventdir" -TEVENT_OBJ="tevent.o tevent_fd.o tevent_timed.o tevent_signal.o tevent_debug.o tevent_util.o" +TEVENT_OBJ="tevent.o tevent_debug.o tevent_util.o" +TEVENT_OBJ="$TEVENT_OBJ tevent_fd.o tevent_timed.o tevent_immediate.o tevent_signal.o" TEVENT_OBJ="$TEVENT_OBJ tevent_req.o tevent_wakeup.o tevent_queue.o" TEVENT_OBJ="$TEVENT_OBJ tevent_standard.o tevent_select.o" diff --git a/lib/tevent/tevent.c b/lib/tevent/tevent.c index 31dc58d98e..ba2d93f4b9 100644 --- a/lib/tevent/tevent.c +++ b/lib/tevent/tevent.c @@ -143,6 +143,7 @@ int tevent_common_context_destructor(struct tevent_context *ev) { struct tevent_fd *fd, *fn; struct tevent_timer *te, *tn; + struct tevent_immediate *ie, *in; struct tevent_signal *se, *sn; if (ev->pipe_fde) { @@ -162,6 +163,13 @@ int tevent_common_context_destructor(struct tevent_context *ev) DLIST_REMOVE(ev->timer_events, te); } + for (ie = ev->immediate_events; ie; ie = in) { + in = ie->next; + ie->event_ctx = NULL; + ie->cancel_fn = NULL; + DLIST_REMOVE(ev->immediate_events, ie); + } + for (se = ev->signal_events; se; se = sn) { sn = se->next; se->event_ctx = NULL; @@ -349,6 +357,47 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev, handler_name, location); } +/* + allocate an immediate event + return NULL on failure (memory allocation error) +*/ +struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx, + const char *location) +{ + struct tevent_immediate *im; + + im = talloc(mem_ctx, struct tevent_immediate); + if (im == NULL) return NULL; + + im->prev = NULL; + im->next = NULL; + im->event_ctx = NULL; + im->create_location = location; + im->handler = NULL; + im->private_data = NULL; + im->handler_name = NULL; + im->schedule_location = NULL; + im->cancel_fn = NULL; + im->additional_data = NULL; + + return im; +} + +/* + schedule an immediate event + return NULL on failure +*/ +void _tevent_schedule_immediate(struct tevent_immediate *im, + struct tevent_context *ev, + tevent_immediate_handler_t handler, + void *private_data, + const char *handler_name, + const char *location) +{ + ev->ops->schedule_immediate(im, ev, handler, private_data, + handler_name, location); +} + /* add a signal event diff --git a/lib/tevent/tevent.h b/lib/tevent/tevent.h index 4a3f51ae5e..6e64a8cdd9 100644 --- a/lib/tevent/tevent.h +++ b/lib/tevent/tevent.h @@ -37,6 +37,7 @@ struct tevent_context; struct tevent_ops; struct tevent_fd; struct tevent_timer; +struct tevent_immediate; struct tevent_signal; /* event handler types */ @@ -52,6 +53,9 @@ typedef void (*tevent_timer_handler_t)(struct tevent_context *ev, struct tevent_timer *te, struct timeval current_time, void *private_data); +typedef void (*tevent_immediate_handler_t)(struct tevent_context *ctx, + struct tevent_immediate *im, + void *private_data); typedef void (*tevent_signal_handler_t)(struct tevent_context *ev, struct tevent_signal *se, int signum, @@ -87,6 +91,21 @@ struct tevent_timer *_tevent_add_timer(struct tevent_context *ev, _tevent_add_timer(ev, mem_ctx, next_event, handler, private_data, \ #handler, __location__) +struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx, + const char *location); +#define tevent_create_immediate(mem_ctx) \ + _tevent_create_immediate(mem_ctx, __location__) + +void _tevent_schedule_immediate(struct tevent_immediate *im, + struct tevent_context *ctx, + tevent_immediate_handler_t handler, + void *private_data, + const char *handler_name, + const char *location); +#define tevent_schedule_immediate(im, ctx, handler, private_data) \ + _tevent_schedule_immediate(im, ctx, handler, private_data, \ + #handler, __location__); + struct tevent_signal *_tevent_add_signal(struct tevent_context *ev, TALLOC_CTX *mem_ctx, int signum, diff --git a/lib/tevent/tevent_epoll.c b/lib/tevent/tevent_epoll.c index 32544593de..7c7f389d5b 100644 --- a/lib/tevent/tevent_epoll.c +++ b/lib/tevent/tevent_epoll.c @@ -404,8 +404,13 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location struct epoll_event_context); struct timeval tval; - if (epoll_ev->ev->signal_events && - tevent_common_check_signal(epoll_ev->ev)) { + if (ev->signal_events && + tevent_common_check_signal(ev)) { + return 0; + } + + if (ev->immediate_events && + tevent_common_loop_immediate(ev)) { return 0; } @@ -420,15 +425,16 @@ static int epoll_event_loop_once(struct tevent_context *ev, const char *location } static const struct tevent_ops epoll_event_ops = { - .context_init = epoll_event_context_init, - .add_fd = epoll_event_add_fd, - .set_fd_close_fn= tevent_common_fd_set_close_fn, - .get_fd_flags = tevent_common_fd_get_flags, - .set_fd_flags = epoll_event_set_fd_flags, - .add_timer = tevent_common_add_timer, - .add_signal = tevent_common_add_signal, - .loop_once = epoll_event_loop_once, - .loop_wait = tevent_common_loop_wait, + .context_init = epoll_event_context_init, + .add_fd = epoll_event_add_fd, + .set_fd_close_fn = tevent_common_fd_set_close_fn, + .get_fd_flags = tevent_common_fd_get_flags, + .set_fd_flags = epoll_event_set_fd_flags, + .add_timer = tevent_common_add_timer, + .schedule_immediate = tevent_common_schedule_immediate, + .add_signal = tevent_common_add_signal, + .loop_once = epoll_event_loop_once, + .loop_wait = tevent_common_loop_wait, }; bool tevent_epoll_init(void) diff --git a/lib/tevent/tevent_immediate.c b/lib/tevent/tevent_immediate.c new file mode 100644 index 0000000000..1ac293e175 --- /dev/null +++ b/lib/tevent/tevent_immediate.c @@ -0,0 +1,139 @@ +/* + Unix SMB/CIFS implementation. + + common events code for immediate events + + Copyright (C) Stefan Metzmacher 2009 + + ** NOTE! The following LGPL license applies to the tevent + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +#include "replace.h" +#include "tevent.h" +#include "tevent_internal.h" +#include "tevent_util.h" + +static void tevent_common_immediate_cancel(struct tevent_immediate *im) +{ + if (!im->event_ctx) { + return; + } + + tevent_debug(im->event_ctx, TEVENT_DEBUG_TRACE, + "Cancel immediate event %p \"%s\"\n", + im, im->handler_name); + + /* let the backend free im->additional_data */ + if (im->cancel_fn) { + im->cancel_fn(im); + } + + DLIST_REMOVE(im->event_ctx->immediate_events, im); + im->event_ctx = NULL; + im->handler = NULL; + im->private_data = NULL; + im->handler_name = NULL; + im->schedule_location = NULL; + im->cancel_fn = NULL; + im->additional_data = NULL; + + talloc_set_destructor(im, NULL); +} + +/* + destroy an immediate event +*/ +static int tevent_common_immediate_destructor(struct tevent_immediate *im) +{ + tevent_common_immediate_cancel(im); + return 0; +} + +/* + * schedule an immediate event on + */ +void tevent_common_schedule_immediate(struct tevent_immediate *im, + struct tevent_context *ev, + tevent_immediate_handler_t handler, + void *private_data, + const char *handler_name, + const char *location) +{ + tevent_common_immediate_cancel(im); + + if (!handler) { + return; + } + + im->event_ctx = ev; + im->handler = handler; + im->private_data = private_data; + im->handler_name = handler_name; + im->schedule_location = location; + im->cancel_fn = NULL; + im->additional_data = NULL; + + DLIST_ADD_END(ev->immediate_events, im, struct tevent_immediate *); + talloc_set_destructor(im, tevent_common_immediate_destructor); + + tevent_debug(ev, TEVENT_DEBUG_TRACE, + "Schedule immediate event \"%s\": %p\n", + handler_name, im); +} + +/* + trigger the first immediate event and return true + if no event was triggered return false +*/ +bool tevent_common_loop_immediate(struct tevent_context *ev) +{ + struct tevent_immediate *im = ev->immediate_events; + tevent_immediate_handler_t handler; + void *private_data; + + if (!im) { + return false; + } + + tevent_debug(ev, TEVENT_DEBUG_TRACE, + "Run immediate event \"%s\": %p\n", + im->handler_name, im); + + /* + * remember the handler and then clear the event + * the handler might reschedule the event + */ + handler = im->handler; + private_data = im->private_data; + + DLIST_REMOVE(im->event_ctx->immediate_events, im); + im->event_ctx = NULL; + im->handler = NULL; + im->private_data = NULL; + im->handler_name = NULL; + im->schedule_location = NULL; + im->cancel_fn = NULL; + im->additional_data = NULL; + + talloc_set_destructor(im, NULL); + + handler(ev, im, private_data); + + return true; +} + diff --git a/lib/tevent/tevent_internal.h b/lib/tevent/tevent_internal.h index f63a58aadd..cf54242da1 100644 --- a/lib/tevent/tevent_internal.h +++ b/lib/tevent/tevent_internal.h @@ -143,6 +143,15 @@ struct tevent_ops { void *private_data, const char *handler_name, const char *location); + + /* immediate event functions */ + void (*schedule_immediate)(struct tevent_immediate *im, + struct tevent_context *ev, + tevent_immediate_handler_t handler, + void *private_data, + const char *handler_name, + const char *location); + /* signal functions */ struct tevent_signal *(*add_signal)(struct tevent_context *ev, TALLOC_CTX *mem_ctx, @@ -188,6 +197,21 @@ struct tevent_timer { void *additional_data; }; +struct tevent_immediate { + struct tevent_immediate *prev, *next; + struct tevent_context *event_ctx; + tevent_immediate_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is for debugging only! */ + const char *handler_name; + const char *create_location; + const char *schedule_location; + /* this is private for the events_ops implementation */ + void (*cancel_fn)(struct tevent_immediate *im); + void *additional_data; +}; + struct tevent_signal { struct tevent_signal *prev, *next; struct tevent_context *event_ctx; @@ -222,6 +246,9 @@ struct tevent_context { /* list of timed events - used by common code */ struct tevent_timer *timer_events; + /* list of immediate events - used by common code */ + struct tevent_immediate *immediate_events; + /* list of signal events - used by common code */ struct tevent_signal *signal_events; @@ -273,6 +300,14 @@ struct tevent_timer *tevent_common_add_timer(struct tevent_context *ev, const char *location); struct timeval tevent_common_loop_timer_delay(struct tevent_context *); +void tevent_common_schedule_immediate(struct tevent_immediate *im, + struct tevent_context *ev, + tevent_immediate_handler_t handler, + void *private_data, + const char *handler_name, + const char *location); +bool tevent_common_loop_immediate(struct tevent_context *ev); + struct tevent_signal *tevent_common_add_signal(struct tevent_context *ev, TALLOC_CTX *mem_ctx, int signum, diff --git a/lib/tevent/tevent_select.c b/lib/tevent/tevent_select.c index 1c295d7ca4..d97418991a 100644 --- a/lib/tevent/tevent_select.c +++ b/lib/tevent/tevent_select.c @@ -210,8 +210,13 @@ static int select_event_loop_once(struct tevent_context *ev, const char *locatio struct select_event_context); struct timeval tval; - if (select_ev->ev->signal_events && - tevent_common_check_signal(select_ev->ev)) { + if (ev->signal_events && + tevent_common_check_signal(ev)) { + return 0; + } + + if (ev->immediate_events && + tevent_common_loop_immediate(ev)) { return 0; } @@ -224,15 +229,16 @@ static int select_event_loop_once(struct tevent_context *ev, const char *locatio } static const struct tevent_ops select_event_ops = { - .context_init = select_event_context_init, - .add_fd = select_event_add_fd, - .set_fd_close_fn= tevent_common_fd_set_close_fn, - .get_fd_flags = tevent_common_fd_get_flags, - .set_fd_flags = tevent_common_fd_set_flags, - .add_timer = tevent_common_add_timer, - .add_signal = tevent_common_add_signal, - .loop_once = select_event_loop_once, - .loop_wait = tevent_common_loop_wait, + .context_init = select_event_context_init, + .add_fd = select_event_add_fd, + .set_fd_close_fn = tevent_common_fd_set_close_fn, + .get_fd_flags = tevent_common_fd_get_flags, + .set_fd_flags = tevent_common_fd_set_flags, + .add_timer = tevent_common_add_timer, + .schedule_immediate = tevent_common_schedule_immediate, + .add_signal = tevent_common_add_signal, + .loop_once = select_event_loop_once, + .loop_wait = tevent_common_loop_wait, }; bool tevent_select_init(void) diff --git a/lib/tevent/tevent_standard.c b/lib/tevent/tevent_standard.c index 88db6a1725..c3f8b36e84 100644 --- a/lib/tevent/tevent_standard.c +++ b/lib/tevent/tevent_standard.c @@ -524,8 +524,13 @@ static int std_event_loop_once(struct tevent_context *ev, const char *location) struct std_event_context); struct timeval tval; - if (std_ev->ev->signal_events && - tevent_common_check_signal(std_ev->ev)) { + if (ev->signal_events && + tevent_common_check_signal(ev)) { + return 0; + } + + if (ev->immediate_events && + tevent_common_loop_immediate(ev)) { return 0; } @@ -544,15 +549,16 @@ static int std_event_loop_once(struct tevent_context *ev, const char *location) } static const struct tevent_ops std_event_ops = { - .context_init = std_event_context_init, - .add_fd = std_event_add_fd, - .set_fd_close_fn= tevent_common_fd_set_close_fn, - .get_fd_flags = tevent_common_fd_get_flags, - .set_fd_flags = std_event_set_fd_flags, - .add_timer = tevent_common_add_timer, - .add_signal = tevent_common_add_signal, - .loop_once = std_event_loop_once, - .loop_wait = tevent_common_loop_wait, + .context_init = std_event_context_init, + .add_fd = std_event_add_fd, + .set_fd_close_fn = tevent_common_fd_set_close_fn, + .get_fd_flags = tevent_common_fd_get_flags, + .set_fd_flags = std_event_set_fd_flags, + .add_timer = tevent_common_add_timer, + .schedule_immediate = tevent_common_schedule_immediate, + .add_signal = tevent_common_add_signal, + .loop_once = std_event_loop_once, + .loop_wait = tevent_common_loop_wait, }; -- cgit