From ecc54f900fa6aaf1b97ef85b1101cf7badf33cec Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 14 May 2007 00:57:48 +0000 Subject: r22830: merged the latest lib/events updates from ctdb to Samba4. This includes a new EVENT_FD_AUTOCLOSE flag that prevents race conditions where code using fd events might close a fd before releasing the struct fd_event. That causes headaches for epoll. (This used to be commit f1ad216de13b154a1f8747a44b0970dcc47a784a) --- source4/lib/events/config.m4 | 1 + source4/lib/events/events.c | 25 +++++++++++++++++++++++++ source4/lib/events/events.h | 2 ++ source4/lib/events/events_aio.c | 5 +++++ source4/lib/events/events_epoll.c | 11 +++++++++-- source4/lib/events/events_liboop.c | 5 +++++ source4/lib/events/events_select.c | 5 +++++ source4/lib/events/events_standard.c | 17 +++++++++++------ source4/lib/events/libevents.m4 | 11 +++++++++++ 9 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 source4/lib/events/libevents.m4 diff --git a/source4/lib/events/config.m4 b/source4/lib/events/config.m4 index c65ff91b17..180b58cbc6 100644 --- a/source4/lib/events/config.m4 +++ b/source4/lib/events/config.m4 @@ -5,6 +5,7 @@ AC_CHECK_HEADERS(sys/epoll.h) AC_CHECK_FUNCS(epoll_create) if test x"$ac_cv_header_sys_epoll_h" = x"yes" -a x"$ac_cv_func_epoll_create" = x"yes";then SMB_ENABLE(EVENTS_EPOLL,YES) + AC_DEFINE(HAVE_EVENTS_EPOLL, 1, [Whether epoll is available]) # check for native Linux AIO interface AC_CHECK_HEADERS(libaio.h) diff --git a/source4/lib/events/events.c b/source4/lib/events/events.c index 3a81b55bd9..5b36e70ac0 100644 --- a/source4/lib/events/events.c +++ b/source4/lib/events/events.c @@ -71,6 +71,8 @@ struct event_ops_list { /* list of registered event backends */ static struct event_ops_list *event_backends; +static char *event_default_backend = NULL; + /* register an events backend */ @@ -85,6 +87,15 @@ bool event_register_backend(const char *name, const struct event_ops *ops) return True; } +/* + set the default event backend + */ +void event_set_default_backend(const char *backend) +{ + if (event_default_backend) free(event_default_backend); + event_default_backend = strdup(backend); +} + /* initialise backends if not already done */ @@ -99,7 +110,15 @@ static void event_backend_init(void) run_init_functions(shared_init); #else bool events_standard_init(void); + bool events_select_init(void); + events_select_init(); events_standard_init(); +#if HAVE_EVENTS_EPOLL + { + bool events_epoll_init(void); + events_epoll_init(); + } +#endif #endif } @@ -169,6 +188,9 @@ struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char name = lp_parm_string(-1, "event", "backend"); } #endif + if (name == NULL) { + name = event_default_backend; + } if (name == NULL) { name = "standard"; } @@ -195,6 +217,9 @@ struct event_context *event_context_init(TALLOC_CTX *mem_ctx) /* add a fd based event return NULL on failure (memory allocation error) + + if flags contains EVENT_FD_AUTOCLOSE then the fd will be closed when + the returned fd_event context is freed */ struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, int fd, uint16_t flags, event_fd_handler_t handler, diff --git a/source4/lib/events/events.h b/source4/lib/events/events.h index 94dc56055c..42d67c31bf 100644 --- a/source4/lib/events/events.h +++ b/source4/lib/events/events.h @@ -46,6 +46,7 @@ typedef void (*event_aio_handler_t)(struct event_context *, struct aio_event *, struct event_context *event_context_init(TALLOC_CTX *mem_ctx); struct event_context *event_context_init_byname(TALLOC_CTX *mem_ctx, const char *name); const char **event_backend_list(TALLOC_CTX *mem_ctx); +void event_set_default_backend(const char *backend); struct fd_event *event_add_fd(struct event_context *ev, TALLOC_CTX *mem_ctx, int fd, uint16_t flags, event_fd_handler_t handler, @@ -79,6 +80,7 @@ struct event_context *event_context_find(TALLOC_CTX *mem_ctx); /* bits for file descriptor event flags */ #define EVENT_FD_READ 1 #define EVENT_FD_WRITE 2 +#define EVENT_FD_AUTOCLOSE 4 #define EVENT_FD_WRITEABLE(fde) \ event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE) diff --git a/source4/lib/events/events_aio.c b/source4/lib/events/events_aio.c index 0eadcf5fec..204b749332 100644 --- a/source4/lib/events/events_aio.c +++ b/source4/lib/events/events_aio.c @@ -361,6 +361,11 @@ static int aio_event_fd_destructor(struct fd_event *fde) epoll_del_event(aio_ev, fde); + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + return 0; } diff --git a/source4/lib/events/events_epoll.c b/source4/lib/events/events_epoll.c index 2f879cc410..b553b6fd49 100644 --- a/source4/lib/events/events_epoll.c +++ b/source4/lib/events/events_epoll.c @@ -136,7 +136,9 @@ static void epoll_del_event(struct epoll_event_context *epoll_ev, struct fd_even ZERO_STRUCT(event); event.events = epoll_map_flags(fde->flags); event.data.ptr = fde; - epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event); + if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) { + DEBUG(0,("epoll_del_event failed! probable early close bug (%s)\n", strerror(errno))); + } fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT; } @@ -202,7 +204,7 @@ static void epoll_change_event(struct epoll_event_context *epoll_ev, struct fd_e static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval *tvalp) { int ret, i; -#define MAXEVENTS 8 +#define MAXEVENTS 32 struct epoll_event events[MAXEVENTS]; uint32_t destruction_count = ++epoll_ev->destruction_count; int timeout = -1; @@ -306,6 +308,11 @@ static int epoll_event_fd_destructor(struct fd_event *fde) epoll_del_event(epoll_ev, fde); + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + return 0; } diff --git a/source4/lib/events/events_liboop.c b/source4/lib/events/events_liboop.c index 96bdafd956..cc9047b4eb 100644 --- a/source4/lib/events/events_liboop.c +++ b/source4/lib/events/events_liboop.c @@ -101,6 +101,11 @@ static int oop_event_fd_destructor(struct fd_event *fde) if (fde->flags & EVENT_FD_WRITE) oop->cancel_fd(oop, fde->fd, OOP_WRITE); + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + return 0; } diff --git a/source4/lib/events/events_select.c b/source4/lib/events/events_select.c index b2f9cacf5f..55b477bfa7 100644 --- a/source4/lib/events/events_select.c +++ b/source4/lib/events/events_select.c @@ -104,6 +104,11 @@ static int select_event_fd_destructor(struct fd_event *fde) DLIST_REMOVE(select_ev->fd_events, fde); select_ev->destruction_count++; + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + return 0; } diff --git a/source4/lib/events/events_standard.c b/source4/lib/events/events_standard.c index dcf890ac12..799b19813a 100644 --- a/source4/lib/events/events_standard.c +++ b/source4/lib/events/events_standard.c @@ -30,7 +30,7 @@ #include "includes.h" #include "system/filesys.h" -#include "system/select.h" /* needed for WITH_EPOLL */ +#include "system/select.h" /* needed for HAVE_EVENTS_EPOLL */ #include "lib/util/dlinklist.h" #include "lib/events/events.h" #include "lib/events/events_internal.h" @@ -61,7 +61,7 @@ struct std_event_context { }; /* use epoll if it is available */ -#if WITH_EPOLL +#if HAVE_EVENTS_EPOLL /* called when a epoll call fails, and we should fallback to using select @@ -229,15 +229,15 @@ static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tv timeout = ((tvalp->tv_usec+999) / 1000) + (tvalp->tv_sec*1000); } - if (epoll_ev->ev->num_signal_handlers && - common_event_check_signal(epoll_ev->ev)) { + if (std_ev->ev->num_signal_handlers && + common_event_check_signal(std_ev->ev)) { return 0; } ret = epoll_wait(std_ev->epoll_fd, events, MAXEVENTS, timeout); - if (ret == -1 && errno == EINTR && epoll_ev->ev->num_signal_handlers) { - if (common_event_check_signal(epoll_ev->ev)) { + if (ret == -1 && errno == EINTR && std_ev->ev->num_signal_handlers) { + if (common_event_check_signal(std_ev->ev)) { return 0; } } @@ -353,6 +353,11 @@ static int std_event_fd_destructor(struct fd_event *fde) epoll_del_event(std_ev, fde); + if (fde->flags & EVENT_FD_AUTOCLOSE) { + close(fde->fd); + fde->fd = -1; + } + return 0; } diff --git a/source4/lib/events/libevents.m4 b/source4/lib/events/libevents.m4 new file mode 100644 index 0000000000..99a47dcc54 --- /dev/null +++ b/source4/lib/events/libevents.m4 @@ -0,0 +1,11 @@ +EVENTS_OBJ="lib/events/events.o lib/events/events_select.o lib/events/events_signal.o lib/events/events_timed.o lib/events/events_standard.o" + +AC_CHECK_HEADERS(sys/epoll.h) +AC_CHECK_FUNCS(epoll_create) + +if test x"$ac_cv_header_sys_epoll_h" = x"yes" -a x"$ac_cv_func_epoll_create" = x"yes"; then + EVENTS_OBJ="$EVENTS_OBJ lib/events/events_epoll.o" + AC_DEFINE(HAVE_EVENTS_EPOLL, 1, [Whether epoll available]) +fi + +AC_SUBST(EVENTS_OBJ) -- cgit