EV
view release on metacpan or search on metacpan
/*****************************************************************************/
/* associate signal watchers to a signal */
typedef struct
{
EV_ATOMIC_T pending;
#if EV_MULTIPLICITY
EV_P;
#endif
WL head;
} ANSIG;
static ANSIG signals [EV_NSIG - 1];
/*****************************************************************************/
#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
ecb_noinline ecb_cold
static void
evpipe_init (EV_P)
{
if (!ev_is_active (&pipe_w))
{
int fds [2];
# if EV_USE_EVENTFD
fds [0] = -1;
fds [1] = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
if (fds [1] < 0 && errno == EINVAL)
fds [1] = eventfd (0, 0);
if (fds [1] < 0)
# endif
{
while (pipe (fds))
ev_syserr ("(libev) error creating signal/async pipe");
fd_intern (fds [0]);
}
evpipe [0] = fds [0];
if (evpipe [1] < 0)
evpipe [1] = fds [1]; /* first call, set write fd */
else
{
/* on subsequent calls, do not change evpipe [1] */
/* so that evpipe_write can always rely on its value. */
/* this branch does not do anything sensible on windows, */
/* so must not be executed on windows */
dup2 (fds [1], evpipe [1]);
close (fds [1]);
}
fd_intern (evpipe [1]);
ev_io_set (&pipe_w, evpipe [0] < 0 ? evpipe [1] : evpipe [0], EV_READ);
ev_io_start (EV_A_ &pipe_w);
ev_unref (EV_A); /* watcher should not keep loop alive */
}
}
inline_speed void
evpipe_write (EV_P_ EV_ATOMIC_T *flag)
{
ECB_MEMORY_FENCE; /* push out the write before this function was called, acquire flag */
if (ecb_expect_true (*flag))
return;
*flag = 1;
ECB_MEMORY_FENCE_RELEASE; /* make sure flag is visible before the wakeup */
pipe_write_skipped = 1;
ECB_MEMORY_FENCE; /* make sure pipe_write_skipped is visible before we check pipe_write_wanted */
if (pipe_write_wanted)
{
int old_errno;
pipe_write_skipped = 0;
ECB_MEMORY_FENCE_RELEASE;
old_errno = errno; /* save errno because write will clobber it */
#if EV_USE_EVENTFD
if (evpipe [0] < 0)
{
uint64_t counter = 1;
write (evpipe [1], &counter, sizeof (uint64_t));
}
else
#endif
{
#ifdef _WIN32
WSABUF buf;
DWORD sent;
buf.buf = (char *)&buf;
buf.len = 1;
WSASend (EV_FD_TO_WIN32_HANDLE (evpipe [1]), &buf, 1, &sent, 0, 0, 0);
#else
write (evpipe [1], &(evpipe [1]), 1);
#endif
}
errno = old_errno;
}
}
/* called whenever the libev signal pipe */
/* got some events (signal, async) */
static void
pipecb (EV_P_ ev_io *iow, int revents)
{
int i;
if (revents & EV_READ)
{
/* some systems define WCONTINUED but then fail to support it (linux 2.4) */
if (0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED | WCONTINUED)))
if (!WCONTINUED
|| errno != EINVAL
|| 0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED)))
return;
/* make sure we are called again until all children have been reaped */
/* we need to do it this way so that the callback gets called before we continue */
ev_feed_event (EV_A_ (W)sw, EV_SIGNAL);
child_reap (EV_A_ pid, pid, status);
if ((EV_PID_HASHSIZE) > 1)
child_reap (EV_A_ 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */
}
#endif
/*****************************************************************************/
#if EV_USE_TIMERFD
static void periodics_reschedule (EV_P);
static void
timerfdcb (EV_P_ ev_io *iow, int revents)
{
struct itimerspec its = { 0 };
its.it_value.tv_sec = ev_rt_now + (int)MAX_BLOCKTIME2;
timerfd_settime (timerfd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &its, 0);
ev_rt_now = ev_time ();
/* periodics_reschedule only needs ev_rt_now */
/* but maybe in the future we want the full treatment. */
/*
now_floor = EV_TS_CONST (0.);
time_update (EV_A_ EV_TSTAMP_HUGE);
*/
#if EV_PERIODIC_ENABLE
periodics_reschedule (EV_A);
#endif
}
ecb_noinline ecb_cold
static void
evtimerfd_init (EV_P)
{
if (!ev_is_active (&timerfd_w))
{
timerfd = timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
if (timerfd >= 0)
{
fd_intern (timerfd); /* just to be sure */
ev_io_init (&timerfd_w, timerfdcb, timerfd, EV_READ);
ev_set_priority (&timerfd_w, EV_MINPRI);
ev_io_start (EV_A_ &timerfd_w);
ev_unref (EV_A); /* watcher should not keep loop alive */
/* (re-) arm timer */
timerfdcb (EV_A_ 0, 0);
}
}
}
#endif
/*****************************************************************************/
#if EV_USE_IOCP
# include "ev_iocp.c"
#endif
#if EV_USE_PORT
# include "ev_port.c"
#endif
#if EV_USE_KQUEUE
# include "ev_kqueue.c"
#endif
#if EV_USE_EPOLL
# include "ev_epoll.c"
#endif
#if EV_USE_LINUXAIO
# include "ev_linuxaio.c"
#endif
#if EV_USE_IOURING
# include "ev_iouring.c"
#endif
#if EV_USE_POLL
# include "ev_poll.c"
#endif
#if EV_USE_SELECT
# include "ev_select.c"
#endif
ecb_cold int
ev_version_major (void) EV_NOEXCEPT
{
return EV_VERSION_MAJOR;
}
ecb_cold int
ev_version_minor (void) EV_NOEXCEPT
{
return EV_VERSION_MINOR;
}
/* return true if we are running with elevated privileges and should ignore env variables */
inline_size ecb_cold int
enable_secure (void)
{
#ifdef _WIN32
return 0;
#else
return getuid () != geteuid ()
|| getgid () != getegid ();
#endif
}
#if EV_FORK_ENABLE
assert (forkmax >= forkcnt);
array_verify (EV_A_ (W *)forks, forkcnt);
#endif
#if EV_CLEANUP_ENABLE
assert (cleanupmax >= cleanupcnt);
array_verify (EV_A_ (W *)cleanups, cleanupcnt);
#endif
#if EV_ASYNC_ENABLE
assert (asyncmax >= asynccnt);
array_verify (EV_A_ (W *)asyncs, asynccnt);
#endif
#if EV_PREPARE_ENABLE
assert (preparemax >= preparecnt);
array_verify (EV_A_ (W *)prepares, preparecnt);
#endif
#if EV_CHECK_ENABLE
assert (checkmax >= checkcnt);
array_verify (EV_A_ (W *)checks, checkcnt);
#endif
# if 0
#if EV_CHILD_ENABLE
for (w = (ev_child *)childs [chain & ((EV_PID_HASHSIZE) - 1)]; w; w = (ev_child *)((WL)w)->next)
for (signum = EV_NSIG; signum--; ) if (signals [signum].pending)
#endif
# endif
#endif
}
#endif
#if EV_MULTIPLICITY
ecb_cold
struct ev_loop *
#else
int
#endif
ev_default_loop (unsigned int flags) EV_NOEXCEPT
{
if (!ev_default_loop_ptr)
{
#if EV_MULTIPLICITY
EV_P = ev_default_loop_ptr = &default_loop_struct;
#else
ev_default_loop_ptr = 1;
#endif
loop_init (EV_A_ flags);
if (ev_backend (EV_A))
{
#if EV_CHILD_ENABLE
ev_signal_init (&childev, childcb, SIGCHLD);
ev_set_priority (&childev, EV_MAXPRI);
ev_signal_start (EV_A_ &childev);
ev_unref (EV_A); /* child watcher should not keep loop alive */
#endif
}
else
ev_default_loop_ptr = 0;
}
return ev_default_loop_ptr;
}
void
ev_loop_fork (EV_P) EV_NOEXCEPT
{
postfork = 1;
}
/*****************************************************************************/
void
ev_invoke (EV_P_ void *w, int revents)
{
EV_CB_INVOKE ((W)w, revents);
}
unsigned int
ev_pending_count (EV_P) EV_NOEXCEPT
{
int pri;
unsigned int count = 0;
for (pri = NUMPRI; pri--; )
count += pendingcnt [pri];
return count;
}
ecb_noinline
void
ev_invoke_pending (EV_P)
{
pendingpri = NUMPRI;
do
{
--pendingpri;
/* pendingpri possibly gets modified in the inner loop */
while (pendingcnt [pendingpri])
{
ANPENDING *p = pendings [pendingpri] + --pendingcnt [pendingpri];
p->w->pending = 0;
EV_CB_INVOKE (p->w, p->events);
EV_FREQUENT_CHECK;
}
}
while (pendingpri);
}
#if EV_IDLE_ENABLE
/* make idle watchers pending. this handles the "call-idle */
adjustheap (periodics, periodiccnt, active);
}
}
ev_stop (EV_A_ (W)w);
EV_FREQUENT_CHECK;
}
ecb_noinline
void
ev_periodic_again (EV_P_ ev_periodic *w) EV_NOEXCEPT
{
/* TODO: use adjustheap and recalculation */
ev_periodic_stop (EV_A_ w);
ev_periodic_start (EV_A_ w);
}
#endif
#ifndef SA_RESTART
# define SA_RESTART 0
#endif
#if EV_SIGNAL_ENABLE
ecb_noinline
void
ev_signal_start (EV_P_ ev_signal *w) EV_NOEXCEPT
{
if (ecb_expect_false (ev_is_active (w)))
return;
assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0 && w->signum < EV_NSIG));
#if EV_MULTIPLICITY
assert (("libev: a signal must not be attached to two different loops",
!signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop));
signals [w->signum - 1].loop = EV_A;
ECB_MEMORY_FENCE_RELEASE;
#endif
EV_FREQUENT_CHECK;
#if EV_USE_SIGNALFD
if (sigfd == -2)
{
sigfd = signalfd (-1, &sigfd_set, SFD_NONBLOCK | SFD_CLOEXEC);
if (sigfd < 0 && errno == EINVAL)
sigfd = signalfd (-1, &sigfd_set, 0); /* retry without flags */
if (sigfd >= 0)
{
fd_intern (sigfd); /* doing it twice will not hurt */
sigemptyset (&sigfd_set);
ev_io_init (&sigfd_w, sigfdcb, sigfd, EV_READ);
ev_set_priority (&sigfd_w, EV_MAXPRI);
ev_io_start (EV_A_ &sigfd_w);
ev_unref (EV_A); /* signalfd watcher should not keep loop alive */
}
}
if (sigfd >= 0)
{
/* TODO: check .head */
sigaddset (&sigfd_set, w->signum);
sigprocmask (SIG_BLOCK, &sigfd_set, 0);
signalfd (sigfd, &sigfd_set, 0);
}
#endif
ev_start (EV_A_ (W)w, 1);
wlist_add (&signals [w->signum - 1].head, (WL)w);
if (!((WL)w)->next)
# if EV_USE_SIGNALFD
if (sigfd < 0) /*TODO*/
# endif
{
# ifdef _WIN32
evpipe_init (EV_A);
signal (w->signum, ev_sighandler);
# else
struct sigaction sa;
evpipe_init (EV_A);
sa.sa_handler = ev_sighandler;
sigfillset (&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
sigaction (w->signum, &sa, 0);
if (origflags & EVFLAG_NOSIGMASK)
{
sigemptyset (&sa.sa_mask);
sigaddset (&sa.sa_mask, w->signum);
sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0);
}
#endif
}
EV_FREQUENT_CHECK;
}
ecb_noinline
void
ev_signal_stop (EV_P_ ev_signal *w) EV_NOEXCEPT
{
clear_pending (EV_A_ (W)w);
if (ecb_expect_false (!ev_is_active (w)))
return;
EV_FREQUENT_CHECK;
wlist_del (&signals [w->signum - 1].head, (WL)w);
ev_stop (EV_A_ (W)w);
( run in 1.381 second using v1.01-cache-2.11-cpan-39bf76dae61 )