From 499c7e995433fedd0a2333ec6d9bc3768e6224f4 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 6 Nov 2007 00:52:32 +0000 Subject: better fork --- ev.c | 60 ++++++++++++++++++++++++++++++++++++++---------------------- ev.h | 2 +- ev_epoll.c | 13 +++++++++++-- ev_kqueue.c | 13 +++++++++++-- ev_poll.c | 2 +- ev_select.c | 2 +- ev_vars.h | 1 + 7 files changed, 64 insertions(+), 29 deletions(-) diff --git a/ev.c b/ev.c index c12037c..0457088 100644 --- a/ev.c +++ b/ev.c @@ -155,21 +155,24 @@ volatile double SIGFPE_REQ = 0.0f; /*****************************************************************************/ -static void (*syserr_cb)(void); +static void (*syserr_cb)(const char *msg); -void ev_set_syserr_cb (void (*cb)(void)) +void ev_set_syserr_cb (void (*cb)(const char *msg)) { syserr_cb = cb; } static void -syserr (void) +syserr (const char *msg) { + if (!msg) + msg = "(libev) system error"; + if (syserr_cb) - syserr_cb (); + syserr_cb (msg); else { - perror ("libev"); + perror (msg); abort (); } } @@ -380,7 +383,7 @@ fd_reify (EV_P) static void fd_change (EV_P_ int fd) { - if (anfds [fd].reify || fdchangecnt < 0) + if (anfds [fd].reify) return; anfds [fd].reify = 1; @@ -428,7 +431,7 @@ fd_enomem (EV_P) } } -/* susually called after fork if method needs to re-arm all fds from scratch */ +/* usually called after fork if method needs to re-arm all fds from scratch */ static void fd_rearm_all (EV_P) { @@ -695,6 +698,9 @@ loop_init (EV_P_ int methods) #if EV_USE_SELECT if (!method && (methods & EVMETHOD_SELECT)) method = select_init (EV_A_ methods); #endif + + ev_watcher_init (&sigev, sigcb); + ev_set_priority (&sigev, EV_MAXPRI); } } @@ -730,19 +736,34 @@ loop_destroy (EV_P) array_free (check, ); method = 0; - /*TODO*/ } -void +static void loop_fork (EV_P) { - /*TODO*/ #if EV_USE_EPOLL if (method == EVMETHOD_EPOLL ) epoll_fork (EV_A); #endif #if EV_USE_KQUEUE if (method == EVMETHOD_KQUEUE) kqueue_fork (EV_A); #endif + + if (ev_is_active (&sigev)) + { + /* default loop */ + + ev_ref (EV_A); + ev_io_stop (EV_A_ &sigev); + close (sigpipe [0]); + close (sigpipe [1]); + + while (pipe (sigpipe)) + syserr ("(libev) error creating pipe"); + + siginit (EV_A); + } + + postfork = 0; } #if EV_MULTIPLICITY @@ -771,7 +792,7 @@ ev_loop_destroy (EV_P) void ev_loop_fork (EV_P) { - loop_fork (EV_A); + postfork = 1; } #endif @@ -804,8 +825,6 @@ ev_default_loop (int methods) if (ev_method (EV_A)) { - ev_watcher_init (&sigev, sigcb); - ev_set_priority (&sigev, EV_MAXPRI); siginit (EV_A); #ifndef WIN32 @@ -848,15 +867,8 @@ ev_default_fork (void) struct ev_loop *loop = default_loop; #endif - loop_fork (EV_A); - - ev_io_stop (EV_A_ &sigev); - close (sigpipe [0]); - close (sigpipe [1]); - pipe (sigpipe); - - ev_ref (EV_A); /* signal watcher */ - siginit (EV_A); + if (method) + postfork = 1; } /*****************************************************************************/ @@ -1044,6 +1056,10 @@ ev_loop (EV_P_ int flags) call_pending (EV_A); } + /* we might have forked, so reify kernel state if necessary */ + if (expect_false (postfork)) + loop_fork (EV_A); + /* update fd-related kernel structures */ fd_reify (EV_A); diff --git a/ev.h b/ev.h index 08b5963..83cda6f 100644 --- a/ev.h +++ b/ev.h @@ -241,7 +241,7 @@ void ev_set_allocator (void *(*cb)(void *ptr, long size)); * retryable syscall error * (such as failed select, poll, epoll_wait) */ -void ev_set_syserr_cb (void (*cb)(void)); +void ev_set_syserr_cb (void (*cb)(const char *msg)); # if EV_MULTIPLICITY /* the default loop is the only one that handles signals and child watchers */ diff --git a/ev_epoll.c b/ev_epoll.c index 6bb41bc..2040103 100644 --- a/ev_epoll.c +++ b/ev_epoll.c @@ -57,7 +57,7 @@ epoll_poll (EV_P_ ev_tstamp timeout) if (eventcnt < 0) { if (errno != EINTR) - syserr (); + syserr ("(libev) epoll_wait"); return; } @@ -110,7 +110,16 @@ epoll_destroy (EV_P) static void epoll_fork (EV_P) { - epoll_fd = epoll_create (256); + for (;;) + { + epoll_fd = epoll_create (256); + + if (epoll_fd >= 0) + break; + + syserr ("(libev) epoll_create"); + } + fcntl (epoll_fd, F_SETFD, FD_CLOEXEC); fd_rearm_all (EV_A); diff --git a/ev_kqueue.c b/ev_kqueue.c index 4fefcee..07d16e4 100644 --- a/ev_kqueue.c +++ b/ev_kqueue.c @@ -87,7 +87,7 @@ kqueue_poll (EV_P_ ev_tstamp timeout) if (res < 0) { if (errno != EINTR) - syserr (); + syserr ("(libev) kevent"); return; } @@ -185,7 +185,16 @@ kqueue_destroy (EV_P) static void kqueue_fork (EV_P) { - kqueue_fd = kqueue (); + for (;;) + { + kqueue_fd = kqueue (); + + if (kqueue_fd >= 0) + break; + + syserr ("(libev) kqueue"); + } + fcntl (kqueue_fd, F_SETFD, FD_CLOEXEC); /* re-register interest in fds */ diff --git a/ev_poll.c b/ev_poll.c index e809ddd..1ce41c6 100644 --- a/ev_poll.c +++ b/ev_poll.c @@ -85,7 +85,7 @@ poll_poll (EV_P_ ev_tstamp timeout) else if (errno == ENOMEM && !syserr_cb) fd_enomem (EV_A); else if (errno != EINTR) - syserr (); + syserr ("(libev) poll"); return; } diff --git a/ev_select.c b/ev_select.c index 5f75e37..e3e79ca 100644 --- a/ev_select.c +++ b/ev_select.c @@ -96,7 +96,7 @@ select_poll (EV_P_ ev_tstamp timeout) else if (errno == ENOMEM && !syserr_cb) fd_enomem (EV_A); else if (errno != EINTR) - syserr (); + syserr ("(libev) select"); return; } diff --git a/ev_vars.h b/ev_vars.h index 98029ed..c506944 100644 --- a/ev_vars.h +++ b/ev_vars.h @@ -10,6 +10,7 @@ VARx(ev_tstamp, method_fudge) /* assumed typical timer resolution */ VAR (method_modify, void (*method_modify)(EV_P_ int fd, int oev, int nev)) VAR (method_poll , void (*method_poll)(EV_P_ ev_tstamp timeout)) +VARx(int, postfork) /* true if we need to recreate kernel state after fork */ VARx(int, activecnt) /* number of active events */ #if EV_USE_SELECT || EV_GENWRAP -- cgit v1.2.3