X-Git-Url: https://git.llucax.com/software/libev.git/blobdiff_plain/f432e03e319f1ece247021aa0810c4af1cb50042..2fde047707205b8d8f1c71482d2df57105217e17:/ev.c diff --git a/ev.c b/ev.c index e36f182..8a09326 100644 --- a/ev.c +++ b/ev.c @@ -38,6 +38,8 @@ #include #include +#include +#include #include #include @@ -61,6 +63,7 @@ #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */ #define MAX_BLOCKTIME 60. +#define PID_HASHSIZE 16 /* size of pid hahs table, must be power of two */ #include "ev.h" @@ -112,7 +115,13 @@ get_clock (void) #define array_needsize(base,cur,cnt,init) \ if ((cnt) > cur) \ { \ - int newcnt = cur ? cur << 1 : 16; \ + int newcnt = cur; \ + do \ + { \ + newcnt = (newcnt << 1) | 4 & ~3; \ + } \ + while ((cnt) > newcnt); \ + \ base = realloc (base, sizeof (*base) * (newcnt)); \ init (base + cur, newcnt - cur); \ cur = newcnt; \ @@ -190,7 +199,7 @@ queue_events (W *events, int eventcnt, int type) /* called on EBADF to verify fds */ static void -fd_recheck () +fd_recheck (void) { int fd; @@ -198,7 +207,10 @@ fd_recheck () if (anfds [fd].wev) if (fcntl (fd, F_GETFD) == -1 && errno == EBADF) while (anfds [fd].head) - evio_stop (anfds [fd].head); + { + event ((W)anfds [fd].head, EV_ERROR); + evio_stop (anfds [fd].head); + } } /*****************************************************************************/ @@ -326,11 +338,38 @@ siginit (void) static struct ev_idle **idles; static int idlemax, idlecnt; +static struct ev_prepare **prepares; +static int preparemax, preparecnt; + static struct ev_check **checks; static int checkmax, checkcnt; /*****************************************************************************/ +static struct ev_child *childs [PID_HASHSIZE]; +static struct ev_signal childev; + +#ifndef WCONTINUED +# define WCONTINUED 0 +#endif + +static void +childcb (struct ev_signal *sw, int revents) +{ + struct ev_child *w; + int pid, status; + + while ((pid = waitpid (-1, &status, WNOHANG | WUNTRACED | WCONTINUED)) != -1) + for (w = childs [pid & (PID_HASHSIZE - 1)]; w; w = w->next) + if (w->pid == pid || w->pid == -1) + { + w->status = status; + event ((W)w, EV_CHILD); + } +} + +/*****************************************************************************/ + #if HAVE_EPOLL # include "ev_epoll.c" #endif @@ -338,35 +377,53 @@ static int checkmax, checkcnt; # include "ev_select.c" #endif +int +ev_version_major (void) +{ + return EV_VERSION_MAJOR; +} + +int +ev_version_minor (void) +{ + return EV_VERSION_MINOR; +} + int ev_init (int flags) { + if (!ev_method) + { #if HAVE_MONOTONIC - { - struct timespec ts; - if (!clock_gettime (CLOCK_MONOTONIC, &ts)) - have_monotonic = 1; - } + { + struct timespec ts; + if (!clock_gettime (CLOCK_MONOTONIC, &ts)) + have_monotonic = 1; + } #endif - ev_now = ev_time (); - now = get_clock (); - diff = ev_now - now; + ev_now = ev_time (); + now = get_clock (); + diff = ev_now - now; - if (pipe (sigpipe)) - return 0; + if (pipe (sigpipe)) + return 0; - ev_method = EVMETHOD_NONE; + ev_method = EVMETHOD_NONE; #if HAVE_EPOLL - if (ev_method == EVMETHOD_NONE) epoll_init (flags); + if (ev_method == EVMETHOD_NONE) epoll_init (flags); #endif #if HAVE_SELECT - if (ev_method == EVMETHOD_NONE) select_init (flags); + if (ev_method == EVMETHOD_NONE) select_init (flags); #endif - if (ev_method) - { - evw_init (&sigev, sigcb); - siginit (); + if (ev_method) + { + evw_init (&sigev, sigcb); + siginit (); + + evsignal_init (&childev, childcb, SIGCHLD); + evsignal_start (&childev); + } } return ev_method; @@ -374,17 +431,20 @@ int ev_init (int flags) /*****************************************************************************/ -void ev_prefork (void) +void +ev_prefork (void) { /* nop */ } -void ev_postfork_parent (void) +void +ev_postfork_parent (void) { /* nop */ } -void ev_postfork_child (void) +void +ev_postfork_child (void) { #if HAVE_EPOLL if (ev_method == EVMETHOD_EPOLL) @@ -427,7 +487,7 @@ fd_reify (void) } static void -call_pending () +call_pending (void) { while (pendingcnt) { @@ -442,7 +502,7 @@ call_pending () } static void -timers_reify () +timers_reify (void) { while (timercnt && timers [0]->at <= now) { @@ -463,7 +523,7 @@ timers_reify () } static void -periodics_reify () +periodics_reify (void) { while (periodiccnt && periodics [0]->at <= ev_now) { @@ -509,7 +569,7 @@ periodics_reschedule (ev_tstamp diff) } static void -time_update () +time_update (void) { int i; @@ -555,20 +615,22 @@ void ev_loop (int flags) double block; ev_loop_done = flags & EVLOOP_ONESHOT ? 1 : 0; - if (checkcnt) - { - queue_events ((W *)checks, checkcnt, EV_CHECK); - call_pending (); - } - do { + /* queue check watchers (and execute them) */ + if (preparecnt) + { + queue_events ((W *)prepares, preparecnt, EV_PREPARE); + call_pending (); + } + /* update fd-related kernel structures */ fd_reify (); /* calculate blocking time */ - /* we only need this for !monotonic clock, but as we always have timers, we just calculate it every time */ + /* we only need this for !monotonic clockor timers, but as we basically + always have timers, we just calculate it always */ ev_now = ev_time (); if (flags & EVLOOP_NONBLOCK || idlecnt) @@ -598,15 +660,16 @@ void ev_loop (int flags) time_update (); /* queue pending timers and reschedule them */ - periodics_reify (); /* absolute timers first */ - timers_reify (); /* relative timers second */ + timers_reify (); /* relative timers called last */ + periodics_reify (); /* absolute timers called first */ /* queue idle watchers unless io or timers are pending */ if (!pendingcnt) queue_events ((W *)idles, idlecnt, EV_IDLE); - /* queue check and possibly idle watchers */ - queue_events ((W *)checks, checkcnt, EV_CHECK); + /* queue check watchers, to be executed first */ + if (checkcnt) + queue_events ((W *)checks, checkcnt, EV_CHECK); call_pending (); } @@ -835,6 +898,26 @@ void evidle_stop (struct ev_idle *w) ev_stop ((W)w); } +void evprepare_start (struct ev_prepare *w) +{ + if (ev_is_active (w)) + return; + + ev_start ((W)w, ++preparecnt); + array_needsize (prepares, preparemax, preparecnt, ); + prepares [preparecnt - 1] = w; +} + +void evprepare_stop (struct ev_prepare *w) +{ + ev_clear ((W)w); + if (ev_is_active (w)) + return; + + prepares [w->active - 1] = prepares [--preparecnt]; + ev_stop ((W)w); +} + void evcheck_start (struct ev_check *w) { if (ev_is_active (w)) @@ -855,6 +938,25 @@ void evcheck_stop (struct ev_check *w) ev_stop ((W)w); } +void evchild_start (struct ev_child *w) +{ + if (ev_is_active (w)) + return; + + ev_start ((W)w, 1); + wlist_add ((WL *)&childs [w->pid & (PID_HASHSIZE - 1)], (WL)w); +} + +void evchild_stop (struct ev_child *w) +{ + ev_clear ((W)w); + if (ev_is_active (w)) + return; + + wlist_del ((WL *)&childs [w->pid & (PID_HASHSIZE - 1)], (WL)w); + ev_stop ((W)w); +} + /*****************************************************************************/ struct ev_once