diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/lib/events/config.mk | 3 | ||||
-rw-r--r-- | source4/lib/events/events.c | 155 | ||||
-rw-r--r-- | source4/lib/events/events.h | 15 | ||||
-rw-r--r-- | source4/lib/events/events_internal.h | 80 | ||||
-rw-r--r-- | source4/lib/events/events_liboop.c | 273 | ||||
-rw-r--r-- | source4/lib/events/events_standard.c | 366 |
6 files changed, 701 insertions, 191 deletions
diff --git a/source4/lib/events/config.mk b/source4/lib/events/config.mk index e1f9f589a1..4fe0856f88 100644 --- a/source4/lib/events/config.mk +++ b/source4/lib/events/config.mk @@ -2,7 +2,8 @@ # Start SUBSYSTEM LIBEVENTS [SUBSYSTEM::LIBEVENTS] NOPROTO = YES -INIT_OBJ_FILES = lib/events/events_standard.o +INIT_OBJ_FILES = lib/events/events.o +ADD_OBJ_FILES = lib/events/events_standard.o REQUIRED_SUBSYSTEMS = LIBTALLOC # End SUBSYSTEM LIBEVENTS ############################## diff --git a/source4/lib/events/events.c b/source4/lib/events/events.c new file mode 100644 index 0000000000..83b013f366 --- /dev/null +++ b/source4/lib/events/events.c @@ -0,0 +1,155 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + Copyright (C) Andrew Tridgell 2003 + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + 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_once() to block waiting for one of the + events to occor or event_loop_wait() which will loop + forever. + +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "lib/events/events_internal.h" + +/* + create a event_context structure for a specific implemementation. + 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. + + This function is for allowing third-party-applications to hook in gluecode + to their own event loop code, so that they can make async usage of our client libs + + NOTE: use event_context_init() inside of samba! +*/ +struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, const struct event_ops *ops, void *private_data) +{ + struct event_context *ev; + int ret; + + ev = talloc_zero(mem_ctx, struct event_context); + if (!ev) return NULL; + + ev->ops = ops; + + ret = ev->ops->context_init(ev, private_data); + if (ret != 0) { + talloc_free(ev); + return NULL; + } + + return ev; +} + +/* + 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. +*/ +struct event_context *event_context_init(TALLOC_CTX *mem_ctx) +{ + const struct event_ops *ops = event_standard_get_ops(); + return event_context_init_ops(mem_ctx, ops, NULL); +} + +/* + 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_data) +{ + return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data); +} + +/* + return the fd event flags +*/ +uint16_t event_get_fd_flags(struct fd_event *fde) +{ + return fde->event_ctx->ops->get_fd_flags(fde); +} + +/* + set the fd event flags +*/ +void event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + fde->event_ctx->ops->set_fd_flags(fde, flags); +} + +/* + add a timed event + return NULL on failure +*/ +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_data) +{ + return ev->ops->add_timed(ev, mem_ctx, next_event, handler, private_data); +} + +/* + do a single event loop using the events defined in ev +*/ +int event_loop_once(struct event_context *ev) +{ + return ev->ops->loop_once(ev); +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +int event_loop_wait(struct event_context *ev) +{ + return ev->ops->loop_wait(ev); +} diff --git a/source4/lib/events/events.h b/source4/lib/events/events.h index e3973c3c48..6994f6a124 100644 --- a/source4/lib/events/events.h +++ b/source4/lib/events/events.h @@ -21,6 +21,7 @@ */ struct event_context; +struct event_ops; struct fd_event; struct timed_event; @@ -31,6 +32,7 @@ typedef void (*event_timed_handler_t)(struct event_context *, struct timed_event struct timeval , void *); struct event_context *event_context_init(TALLOC_CTX *mem_ctx); +struct event_context *event_context_init_ops(TALLOC_CTX *mem_ctx, const struct event_ops *ops, void *private_data); struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, int fd, uint16_t flags, event_fd_handler_t handler, @@ -44,20 +46,19 @@ struct timed_event *event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ct int event_loop_once(struct event_context *ev); int event_loop_wait(struct event_context *ev); -uint16_t event_fd_flags(struct fd_event *fde); -void event_fd_setflags(struct fd_event *fde, uint16_t flags); +uint16_t event_get_fd_flags(struct fd_event *fde); +void event_set_fd_flags(struct fd_event *fde, uint16_t flags); /* bits for file descriptor event flags */ #define EVENT_FD_READ 1 #define EVENT_FD_WRITE 2 #define EVENT_FD_WRITEABLE(fde) \ - event_fd_setflags(fde, event_fd_flags(fde) | EVENT_FD_WRITE) + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE) #define EVENT_FD_READABLE(fde) \ - event_fd_setflags(fde, event_fd_flags(fde) | EVENT_FD_READ) + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ) #define EVENT_FD_NOT_WRITEABLE(fde) \ - event_fd_setflags(fde, event_fd_flags(fde) & ~EVENT_FD_WRITE) + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE) #define EVENT_FD_NOT_READABLE(fde) \ - event_fd_setflags(fde, event_fd_flags(fde) & ~EVENT_FD_WRITE) - + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE) diff --git a/source4/lib/events/events_internal.h b/source4/lib/events/events_internal.h new file mode 100644 index 0000000000..9fc5a2065f --- /dev/null +++ b/source4/lib/events/events_internal.h @@ -0,0 +1,80 @@ +/* + Unix SMB/CIFS implementation. + + generalised event loop handling + + Internal structs + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +struct event_ops { + /* conntext init */ + int (*context_init)(struct event_context *ev, void *private_data); + + /* fd_event functions */ + struct fd_event *(*add_fd)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + event_fd_handler_t handler, + void *private_data); + uint16_t (*get_fd_flags)(struct fd_event *fde); + void (*set_fd_flags)(struct fd_event *fde, uint16_t flags); + + /* timed_event functions */ + struct timed_event *(*add_timed)(struct event_context *ev, + TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data); + + /* loop functions */ + int (*loop_once)(struct event_context *ev); + int (*loop_wait)(struct event_context *ev); +}; + +struct fd_event { + struct fd_event *prev, *next; + struct event_context *event_ctx; + int fd; + uint16_t flags; /* see EVENT_FD_* flags */ + event_fd_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is private for the events_ops implementation */ + void *additional_data; +}; + +struct timed_event { + struct timed_event *prev, *next; + struct event_context *event_ctx; + struct timeval next_event; + event_timed_handler_t handler; + /* this is private for the specific handler */ + void *private_data; + /* this is private for the events_ops implementation */ + void *additional_data; +}; + +struct event_context { + /* the specific events implementation */ + const struct event_ops *ops; + /* this is private for the events_ops implementation */ + void *additional_data; +}; + +const struct event_ops *event_standard_get_ops(void); diff --git a/source4/lib/events/events_liboop.c b/source4/lib/events/events_liboop.c new file mode 100644 index 0000000000..ad7c43cd4e --- /dev/null +++ b/source4/lib/events/events_liboop.c @@ -0,0 +1,273 @@ +/* + Unix SMB/CIFS implementation. + main select loop and event handling + wrapper for http://liboop.org/ + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* NOTE: this code compiles fine, but is completly *UNTESTED* + and is only commited as example +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "lib/events/events_internal.h" + +#include <oop.h> + +static int oop_event_context_destructor(void *ptr) +{ + struct event_context *ev = talloc_get_type(ptr, struct event_context); + oop_source_sys *oop_sys = ev->additional_data; + + oop_sys_delete(oop_sys); + + return 0; +} + +/* + create a oop_event_context structure. +*/ +static int oop_event_context_init(struct event_context *ev, void *private_data) +{ + oop_source_sys *oop_sys = private_data; + + if (!oop_sys) { + oop_sys = oop_sys_new(); + if (!oop_sys) { + return -1; + } + + talloc_set_destructor(ev, oop_event_context_destructor); + } + + ev->additional_data = oop_sys; + + return 0; +} + +static void *oop_event_fd_handler(oop_source *oop, int fd, oop_event oop_type, void *ptr) +{ + struct fd_event *fde = ptr; + + if (fd != fde->fd) return OOP_ERROR; + + switch(oop_type) { + case OOP_READ: + fde->handler(fde->event_ctx, fde, EVENT_FD_READ, fde->private_data); + return OOP_CONTINUE; + case OOP_WRITE: + fde->handler(fde->event_ctx, fde, EVENT_FD_WRITE, fde->private_data); + return OOP_CONTINUE; + case OOP_EXCEPTION: + return OOP_ERROR; + case OOP_NUM_EVENTS: + return OOP_ERROR; + } + + return OOP_ERROR; +} + +/* + destroy an fd_event +*/ +static int oop_event_fd_destructor(void *ptr) +{ + struct fd_event *fde = talloc_get_type(ptr, struct fd_event); + struct event_context *ev = fde->event_ctx; + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + + if (fde->flags & EVENT_FD_READ) + oop->cancel_fd(oop, fde->fd, OOP_READ); + if (fde->flags & EVENT_FD_WRITE) + oop->cancel_fd(oop, fde->fd, OOP_WRITE); + + return 0; +} + +/* + add a fd based event + return NULL on failure (memory allocation error) +*/ +static struct fd_event *oop_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 *fde; + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + + fde = talloc(mem_ctx?mem_ctx:ev, struct fd_event); + if (!fde) return NULL; + + fde->event_ctx = ev; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + fde->additional_data = NULL; + + if (fde->flags & EVENT_FD_READ) + oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde); + if (fde->flags & EVENT_FD_WRITE) + oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde); + + talloc_set_destructor(fde, oop_event_fd_destructor); + + return fde; +} + +/* + return the fd event flags +*/ +static uint16_t oop_event_get_fd_flags(struct fd_event *fde) +{ + if (!fde) return 0; + + return fde->flags; +} + +/* + set the fd event flags +*/ +static void oop_event_set_fd_flags(struct fd_event *fde, uint16_t flags) +{ + oop_source_sys *oop_sys; + oop_source *oop; + + if (!fde) return; + + oop_sys = fde->event_ctx->additional_data; + oop = oop_sys_source(oop_sys); + + if ((fde->flags & EVENT_FD_READ)&&(!(flags & EVENT_FD_READ))) + oop->cancel_fd(oop, fde->fd, OOP_READ); + + if ((!(fde->flags & EVENT_FD_READ))&&(flags & EVENT_FD_READ)) + oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde); + + if ((fde->flags & EVENT_FD_WRITE)&&(!(flags & EVENT_FD_WRITE))) + oop->cancel_fd(oop, fde->fd, OOP_WRITE); + + if ((!(fde->flags & EVENT_FD_WRITE))&&(flags & EVENT_FD_WRITE)) + oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde); + + fde->flags = flags; +} + +static void *oop_event_timed_handler(oop_source *oop, struct timeval t, void *ptr) +{ + struct timed_event *te = ptr; + + te->handler(te->event_ctx, te, t, te->private_data); + + return OOP_CONTINUE; +} + +/* + destroy a timed event +*/ +static int oop_event_timed_destructor(void *ptr) +{ + struct timed_event *te = talloc_get_type(ptr, struct timed_event); + struct event_context *ev = te->event_ctx; + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + + oop->cancel_time(oop, te->next_event, oop_event_timed_handler, te); + + return 0; +} + +/* + add a timed event + return NULL on failure (memory allocation error) +*/ +static struct timed_event *oop_event_add_timed(struct event_context *ev, TALLOC_CTX *mem_ctx, + struct timeval next_event, + event_timed_handler_t handler, + void *private_data) +{ + oop_source_sys *oop_sys = ev->additional_data; + oop_source *oop = oop_sys_source(oop_sys); + struct timed_event *te; + + te = talloc(mem_ctx?mem_ctx:ev, struct timed_event); + if (te == NULL) return NULL; + + te->event_ctx = ev; + te->next_event = next_event; + te->handler = handler; + te->private_data = private_data; + te->additional_data = NULL; + + oop->cancel_time(oop, te->next_event, oop_event_timed_handler, te); + + talloc_set_destructor(te, oop_event_timed_destructor); + + return te; +} + +/* + do a single event loop using the events defined in ev +*/ +static int oop_event_loop_once(struct event_context *ev) +{ + void *oop_ret; + oop_source_sys *oop_sys = ev->additional_data; + + oop_ret = oop_sys_run_once(oop_sys); + if (oop_ret == OOP_CONTINUE) { + return 0; + } + + return -1; +} + +/* + return on failure or (with 0) if all fd events are removed +*/ +static int oop_event_loop_wait(struct event_context *ev) +{ + void *oop_ret; + oop_source_sys *oop_sys = ev->additional_data; + + oop_ret = oop_sys_run(oop_sys); + if (oop_ret == OOP_CONTINUE) { + return 0; + } + + return -1; +} + +static const struct event_ops events_oop_ops = { + .context_init = oop_event_context_init, + .add_fd = oop_event_add_fd, + .get_fd_flags = oop_event_get_fd_flags, + .set_fd_flags = oop_event_set_fd_flags, + .add_timed = oop_event_add_timed, + .loop_once = oop_event_loop_once, + .loop_wait = oop_event_loop_wait, +}; + +const struct event_ops *events_oop_get_ops(void) +{ + return &events_oop_ops; +} 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; } |