0
* libev event processing core, watcher management
0
- * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
0
+ * Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
0
- * Redistribution and use in source and binary forms, with or without
0
- * modification, are permitted provided that the following conditions are
0
+ * Redistribution and use in source and binary forms, with or without modifica-
0
+ * tion, are permitted provided that the following conditions are met:
0
+ * 1. Redistributions of source code must retain the above copyright notice,
0
+ * this list of conditions and the following disclaimer.
0
+ * 2. Redistributions in binary form must reproduce the above copyright
0
+ * notice, this list of conditions and the following disclaimer in the
0
+ * documentation and/or other materials provided with the distribution.
0
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
0
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
0
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
0
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
0
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
0
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
0
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
0
- * * Redistributions of source code must retain the above copyright
0
- * notice, this list of conditions and the following disclaimer.
0
- * * Redistributions in binary form must reproduce the above
0
- * copyright notice, this list of conditions and the following
0
- * disclaimer in the documentation and/or other materials provided
0
- * with the distribution.
0
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
0
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
0
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
0
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
0
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0
+ * Alternatively, the contents of this file may be used under the terms of
0
+ * the GNU General Public License ("GPL") version 2 or any later version,
0
+ * in which case the provisions of the GPL are applicable instead of
0
+ * the above. If you wish to allow the use of your version of this file
0
+ * only under the terms of the GPL and not to allow others to use your
0
+ * version of this file under the BSD license, indicate your decision
0
+ * by deleting the provisions above and replace them with the notice
0
+ * and other provisions required by the GPL. If you do not delete the
0
+ * provisions above, a recipient may use your version of this file under
0
+ * either the BSD or the GPL.
0
@@ -282,9 +290,11 @@ typedef ev_watcher *W;
0
typedef ev_watcher_list *WL;
0
typedef ev_watcher_time *WT;
0
/* sig_atomic_t is used to avoid per-thread variables or locking but still */
0
/* giving it a reasonably high chance of working on typical architetcures */
0
-static sig_atomic_t have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */
0
+static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */
0
@@ -443,7 +453,7 @@ ev_sleep (ev_tstamp delay)
0
+ Sleep ((unsigned long)(delay * 1e3));
0
@@ -592,7 +602,11 @@ fd_reify (EV_P)
0
- anfd->handle = _get_osfhandle (fd);
0
+ #ifdef EV_FD_TO_WIN32_HANDLE
0
+ anfd->handle = EV_FD_TO_WIN32_HANDLE (fd);
0
+ anfd->handle = _get_osfhandle (fd);
0
assert (("libev only supports socket fds in this configuration", ioctlsocket (anfd->handle, FIONREAD, &argp) == 0));
0
@@ -751,15 +765,13 @@ adjustheap (WT *heap, int N, int k)
0
- sig_atomic_t volatile gotsig;
0
-static int sigpipe [2];
0
-static sig_atomic_t volatile gotsig;
0
+static EV_ATOMIC_T gotsig;
0
signals_init (ANSIG *base, int count)
0
@@ -773,24 +785,102 @@ signals_init (ANSIG *base, int count)
0
-sighandler (int signum)
0
+/*****************************************************************************/
0
- signal (signum, sighandler);
0
+ ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg);
0
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
0
+ fcntl (fd, F_SETFL, O_NONBLOCK);
0
- signals [signum - 1].gotsig = 1;
0
+ if (!ev_is_active (&pipeev))
0
+ syserr ("(libev) error creating signal/async pipe");
0
+ fd_intern (evpipe [0]);
0
+ fd_intern (evpipe [1]);
0
+ ev_io_set (&pipeev, evpipe [0], EV_READ);
0
+ ev_io_start (EV_A_ &pipeev);
0
+ ev_unref (EV_A); /* watcher should not keep loop alive */
0
+evpipe_write (EV_P_ EV_ATOMIC_T *flag)
0
- int old_errno = errno;
0
- write (sigpipe [1], &signum, 1);
0
+ int old_errno = errno; /* save errno because write might clobber it */
0
+ write (evpipe [1], &old_errno, 1);
0
+pipecb (EV_P_ ev_io *iow, int revents)
0
+ read (evpipe [0], &dummy, 1);
0
+ if (gotsig && ev_is_default_loop (EV_A))
0
+ for (signum = signalmax; signum--; )
0
+ if (signals [signum].gotsig)
0
+ ev_feed_signal_event (EV_A_ signum + 1);
0
+ for (i = asynccnt; i--; )
0
+ ev_feed_event (EV_A_ asyncs [i], EV_ASYNC);
0
+/*****************************************************************************/
0
+ev_sighandler (int signum)
0
+ struct ev_loop *loop = &default_loop_struct;
0
+ signal (signum, ev_sighandler);
0
+ signals [signum - 1].gotsig = 1;
0
+ evpipe_write (EV_A_ &gotsig);
0
ev_feed_signal_event (EV_P_ int signum)
0
@@ -811,42 +901,6 @@ ev_feed_signal_event (EV_P_ int signum)
0
ev_feed_event (EV_A_ (W)w, EV_SIGNAL);
0
-sigcb (EV_P_ ev_io *iow, int revents)
0
- read (sigpipe [0], &revents, 1);
0
- for (signum = signalmax; signum--; )
0
- if (signals [signum].gotsig)
0
- ev_feed_signal_event (EV_A_ signum + 1);
0
- ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg);
0
- fcntl (fd, F_SETFD, FD_CLOEXEC);
0
- fcntl (fd, F_SETFL, O_NONBLOCK);
0
- fd_intern (sigpipe [0]);
0
- fd_intern (sigpipe [1]);
0
- ev_io_set (&sigev, sigpipe [0], EV_READ);
0
- ev_io_start (EV_A_ &sigev);
0
- ev_unref (EV_A); /* child watcher should not keep loop alive */
0
/*****************************************************************************/
0
static WL childs [EV_PID_HASHSIZE];
0
@@ -855,19 +909,27 @@ static WL childs [EV_PID_HASHSIZE];
0
static ev_signal childev;
0
+# define WIFCONTINUED(status) 0
0
-child_reap (EV_P_ ev_signal *sw, int chain, int pid, int status)
0
+child_reap (EV_P_ int chain, int pid, int status)
0
+ int traced = WIFSTOPPED (status) || WIFCONTINUED (status);
0
for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next)
0
- if (w->pid == pid || !w->pid)
0
- ev_set_priority (w, ev_priority (sw)); /* need to do it *now* */
0
- ev_feed_event (EV_A_ (W)w, EV_CHILD);
0
+ if ((w->pid == pid || !w->pid)
0
+ && (!traced || (w->flags & 1)))
0
+ ev_set_priority (w, EV_MAXPRI); /* need to do it *now*, this *must* be the same prio as the signal watcher itself */
0
+ ev_feed_event (EV_A_ (W)w, EV_CHILD);
0
@@ -886,13 +948,13 @@ childcb (EV_P_ ev_signal *sw, int revents)
0
|| 0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED)))
0
- /* make sure we are called again until all childs have been reaped */
0
+ /* make sure we are called again until all children have been reaped */
0
/* we need to do it this way so that the callback gets called before we continue */
0
ev_feed_event (EV_A_ (W)sw, EV_SIGNAL);
0
- child_reap (EV_A_ sw, pid, pid, status);
0
+ child_reap (EV_A_ pid, pid, status);
0
if (EV_PID_HASHSIZE > 1)
0
- child_reap (EV_A_ sw, 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */
0
+ child_reap (EV_A_ 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */
0
@@ -1020,13 +1082,19 @@ loop_init (EV_P_ unsigned int flags)
0
- ev_rt_now = ev_time ();
0
- mn_now = get_clock ();
0
- rtmn_diff = ev_rt_now - mn_now;
0
+ ev_rt_now = ev_time ();
0
+ mn_now = get_clock ();
0
+ rtmn_diff = ev_rt_now - mn_now;
0
timeout_blocktime = 0.;
0
/* pid check not overridable via env */
0
@@ -1042,12 +1110,6 @@ loop_init (EV_P_ unsigned int flags)
0
if (!(flags & 0x0000ffffUL))
0
flags |= ev_recommended_backends ();
0
if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
0
@@ -1064,8 +1126,8 @@ loop_init (EV_P_ unsigned int flags)
0
if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
0
- ev_init (&sigev, sigcb);
0
- ev_set_priority (&sigev, EV_MAXPRI);
0
+ ev_init (&pipeev, pipecb);
0
+ ev_set_priority (&pipeev, EV_MAXPRI);
0
@@ -1074,6 +1136,15 @@ loop_destroy (EV_P)
0
+ if (ev_is_active (&pipeev))
0
+ ev_ref (EV_A); /* signal watcher */
0
+ ev_io_stop (EV_A_ &pipeev);
0
+ close (evpipe [0]); evpipe [0] = 0;
0
+ close (evpipe [1]); evpipe [1] = 0;
0
@@ -1119,6 +1190,9 @@ loop_destroy (EV_P)
0
array_free (prepare, EMPTY);
0
array_free (check, EMPTY);
0
+ array_free (async, EMPTY);
0
@@ -1141,19 +1215,23 @@ loop_fork (EV_P)
0
- if (ev_is_active (&sigev))
0
+ if (ev_is_active (&pipeev))
0
+ /* this "locks" the handlers against writing to the pipe */
0
+ /* while we modify the fd vars */
0
- ev_io_stop (EV_A_ &sigev);
0
- while (pipe (sigpipe))
0
- syserr ("(libev) error creating pipe");
0
+ ev_io_stop (EV_A_ &pipeev);
0
+ /* now iterate over everything, in case we missed something */
0
+ pipecb (EV_A_ &pipeev, EV_READ);
0
@@ -1185,7 +1263,7 @@ ev_loop_destroy (EV_P)
0
+ postfork = 1; /* must be in line with ev_default_fork */
0
@@ -1198,10 +1276,6 @@ int
0
ev_default_loop (unsigned int flags)
0
- if (sigpipe [0] == sigpipe [1])
0
if (!ev_default_loop_ptr)
0
@@ -1214,8 +1288,6 @@ ev_default_loop (unsigned int flags)
0
ev_signal_init (&childev, childcb, SIGCHLD);
0
ev_set_priority (&childev, EV_MAXPRI);
0
@@ -1242,12 +1314,6 @@ ev_default_destroy (void)
0
ev_signal_stop (EV_A_ &childev);
0
- ev_ref (EV_A); /* signal watcher */
0
- ev_io_stop (EV_A_ &sigev);
0
- close (sigpipe [0]); sigpipe [0] = 0;
0
- close (sigpipe [1]); sigpipe [1] = 0;
0
@@ -1259,7 +1325,7 @@ ev_default_fork (void)
0
+ postfork = 1; /* must be in line with ev_loop_fork */
0
/*****************************************************************************/
0
@@ -1478,9 +1544,7 @@ static int loop_done;
0
ev_loop (EV_P_ int flags)
0
- loop_done = flags & (EVLOOP_ONESHOT | EVLOOP_NONBLOCK)
0
+ loop_done = EVUNLOOP_CANCEL;
0
call_pending (EV_A); /* in case we recurse, ensure ordering stays nice and clean */
0
@@ -1586,9 +1650,12 @@ ev_loop (EV_P_ int flags)
0
queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
0
- while (expect_true (activecnt && !loop_done));
0
+ && !(flags & (EVLOOP_ONESHOT | EVLOOP_NONBLOCK))
0
if (loop_done == EVUNLOOP_ONE)
0
loop_done = EVUNLOOP_CANCEL;
0
@@ -1844,6 +1911,8 @@ ev_signal_start (EV_P_ ev_signal *w)
0
assert (("ev_signal_start called with illegal signal number", w->signum > 0));
0
@@ -1864,10 +1933,10 @@ ev_signal_start (EV_P_ ev_signal *w)
0
- signal (w->signum, sighandler);
0
+ signal (w->signum, ev_sighandler);
0
- sa.sa_handler = sighandler;
0
+ sa.sa_handler = ev_sighandler;
0
sigfillset (&sa.sa_mask);
0
sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
0
sigaction (w->signum, &sa, 0);
0
@@ -2366,6 +2435,44 @@ ev_fork_stop (EV_P_ ev_fork *w)
0
+ev_async_start (EV_P_ ev_async *w)
0
+ if (expect_false (ev_is_active (w)))
0
+ ev_start (EV_A_ (W)w, ++asynccnt);
0
+ array_needsize (ev_async *, asyncs, asyncmax, asynccnt, EMPTY2);
0
+ asyncs [asynccnt - 1] = w;
0
+ev_async_stop (EV_P_ ev_async *w)
0
+ clear_pending (EV_A_ (W)w);
0
+ if (expect_false (!ev_is_active (w)))
0
+ int active = ((W)w)->active;
0
+ asyncs [active - 1] = asyncs [--asynccnt];
0
+ ((W)asyncs [active - 1])->active = active;
0
+ev_async_send (EV_P_ ev_async *w)
0
+ evpipe_write (EV_A_ &gotasync);
0
/*****************************************************************************/