From b6e64bad555e39013b8a70dff1c1172078d56d1a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 May 2007 02:38:07 +0000 Subject: r22963: fixed the epoll/fork interaction in the epoll and aio backends (This used to be commit aeca07659aa612bee0c4dd6bdbb24c799e912909) --- source4/lib/events/events_aio.c | 42 +++++++++++++++++++++++++++++++++++++ source4/lib/events/events_epoll.c | 44 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) (limited to 'source4/lib/events') diff --git a/source4/lib/events/events_aio.c b/source4/lib/events/events_aio.c index 204b749332..68109d7265 100644 --- a/source4/lib/events/events_aio.c +++ b/source4/lib/events/events_aio.c @@ -48,6 +48,9 @@ struct aio_event_context { /* a pointer back to the generic event_context */ struct event_context *ev; + /* list of filedescriptor events */ + struct fd_event *fd_events; + /* number of registered fd event handlers */ int num_fd_events; @@ -61,6 +64,7 @@ struct aio_event_context { int epoll_fd; int is_epoll_set; + pid_t pid; }; struct aio_event { @@ -92,6 +96,28 @@ static int aio_ctx_destructor(struct aio_event_context *aio_ev) return 0; } +static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *fde); + +/* + reopen the epoll handle when our pid changes + see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an + demonstration of why this is needed + */ +static void epoll_reopen(struct aio_event_context *aio_ev) +{ + struct fd_event *fde; + + close(aio_ev->epoll_fd); + aio_ev->epoll_fd = epoll_create(64); + if (aio_ev->epoll_fd == -1) { + return; + } + aio_ev->pid = getpid(); + for (fde=aio_ev->fd_events;fde;fde=fde->next) { + epoll_add_event(aio_ev, fde); + } +} + #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) @@ -104,6 +130,16 @@ static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *f struct epoll_event event; if (aio_ev->epoll_fd == -1) return; + /* during an add event we need to check if our pid has changed + and re-open the epoll socket. Note that we don't need to do this + for other epoll changes */ + if (aio_ev->pid != getpid()) { + epoll_reopen(aio_ev); + /* the current event gets added in epoll_reopen(), so + we can return here */ + return; + } + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; /* if we don't want events yet, don't add an aio_event */ @@ -127,6 +163,9 @@ static void epoll_add_event(struct aio_event_context *aio_ev, struct fd_event *f static void epoll_del_event(struct aio_event_context *aio_ev, struct fd_event *fde) { struct epoll_event event; + + DLIST_REMOVE(aio_ev->fd_events, fde); + if (aio_ev->epoll_fd == -1) return; fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; @@ -185,6 +224,7 @@ static void epoll_change_event(struct aio_event_context *aio_ev, struct fd_event /* there's no aio_event attached to the fde */ if (want_read || (want_write && !got_error)) { + DLIST_ADD(aio_ev->fd_events, fde); epoll_add_event(aio_ev, fde); return; } @@ -334,6 +374,7 @@ static int aio_event_context_init(struct event_context *ev) talloc_free(aio_ev); return -1; } + aio_ev->pid = getpid(); talloc_set_destructor(aio_ev, aio_ctx_destructor); @@ -396,6 +437,7 @@ static struct fd_event *aio_event_add_fd(struct event_context *ev, TALLOC_CTX *m aio_ev->num_fd_events++; talloc_set_destructor(fde, aio_event_fd_destructor); + DLIST_ADD(aio_ev->fd_events, fde); epoll_add_event(aio_ev, fde); return fde; diff --git a/source4/lib/events/events_epoll.c b/source4/lib/events/events_epoll.c index b553b6fd49..cfea8363ab 100644 --- a/source4/lib/events/events_epoll.c +++ b/source4/lib/events/events_epoll.c @@ -32,6 +32,9 @@ struct epoll_event_context { /* a pointer back to the generic event_context */ struct event_context *ev; + /* list of filedescriptor events */ + struct fd_event *fd_events; + /* number of registered fd event handlers */ int num_fd_events; @@ -45,6 +48,8 @@ struct epoll_event_context { /* when using epoll this is the handle from epoll_create */ int epoll_fd; + + pid_t pid; }; /* @@ -86,9 +91,32 @@ static int epoll_ctx_destructor(struct epoll_event_context *epoll_ev) static void epoll_init_ctx(struct epoll_event_context *epoll_ev) { epoll_ev->epoll_fd = epoll_create(64); + epoll_ev->pid = getpid(); talloc_set_destructor(epoll_ev, epoll_ctx_destructor); } +static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_event *fde); + +/* + reopen the epoll handle when our pid changes + see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an + demonstration of why this is needed + */ +static void epoll_reopen(struct epoll_event_context *epoll_ev) +{ + struct fd_event *fde; + + close(epoll_ev->epoll_fd); + epoll_ev->epoll_fd = epoll_create(64); + if (epoll_ev->epoll_fd == -1) { + return; + } + epoll_ev->pid = getpid(); + for (fde=epoll_ev->fd_events;fde;fde=fde->next) { + epoll_add_event(epoll_ev, fde); + } +} + #define EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT (1<<0) #define EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR (1<<1) #define EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR (1<<2) @@ -99,8 +127,19 @@ static void epoll_init_ctx(struct epoll_event_context *epoll_ev) static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) { struct epoll_event event; + if (epoll_ev->epoll_fd == -1) return; + /* during an add event we need to check if our pid has changed + and re-open the epoll socket. Note that we don't need to do this + for other epoll changes */ + if (epoll_ev->pid != getpid()) { + epoll_reopen(epoll_ev); + /* the current event gets added in epoll_reopen(), so + we can return here */ + return; + } + fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; /* if we don't want events yet, don't add an epoll_event */ @@ -126,6 +165,9 @@ static void epoll_add_event(struct epoll_event_context *epoll_ev, struct fd_even static void epoll_del_event(struct epoll_event_context *epoll_ev, struct fd_event *fde) { struct epoll_event event; + + DLIST_REMOVE(epoll_ev->fd_events, fde); + if (epoll_ev->epoll_fd == -1) return; fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR; @@ -193,6 +235,7 @@ static void epoll_change_event(struct epoll_event_context *epoll_ev, struct fd_e /* there's no epoll_event attached to the fde */ if (want_read || (want_write && !got_error)) { + DLIST_ADD(epoll_ev->fd_events, fde); epoll_add_event(epoll_ev, fde); return; } @@ -343,6 +386,7 @@ static struct fd_event *epoll_event_add_fd(struct event_context *ev, TALLOC_CTX epoll_ev->num_fd_events++; talloc_set_destructor(fde, epoll_event_fd_destructor); + DLIST_ADD(epoll_ev->fd_events, fde); epoll_add_event(epoll_ev, fde); return fde; -- cgit