summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2007-05-17 02:38:07 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:52:32 -0500
commitb6e64bad555e39013b8a70dff1c1172078d56d1a (patch)
tree510f8e59b8fec98ef9aefab1c01689e4b3568158
parente9eb862dc0cb100bf2ee3de367a20587346f85aa (diff)
downloadsamba-b6e64bad555e39013b8a70dff1c1172078d56d1a.tar.gz
samba-b6e64bad555e39013b8a70dff1c1172078d56d1a.tar.bz2
samba-b6e64bad555e39013b8a70dff1c1172078d56d1a.zip
r22963: fixed the epoll/fork interaction in the epoll and aio backends
(This used to be commit aeca07659aa612bee0c4dd6bdbb24c799e912909)
-rw-r--r--source4/lib/events/events_aio.c42
-rw-r--r--source4/lib/events/events_epoll.c44
2 files changed, 86 insertions, 0 deletions
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;