#if __GNUC__ >= 3
# define expect(expr,value) __builtin_expect ((expr),(value))
-# define inline_size static inline /* inline for codesize */
-# if EV_MINIMAL
-# define noinline __attribute__ ((noinline))
-# define inline_speed static noinline
-# else
-# define noinline
-# define inline_speed static inline
-# endif
+# define noinline __attribute__ ((noinline))
#else
# define expect(expr,value) (expr)
-# define inline_speed static
-# define inline_size static
# define noinline
+# if __STDC_VERSION__ < 199901L
+# define inline
+# endif
#endif
#define expect_false(expr) expect ((expr) != 0, 0)
#define expect_true(expr) expect ((expr) != 0, 1)
+#define inline_size static inline
+
+#if EV_MINIMAL
+# define inline_speed static noinline
+#else
+# define inline_speed static inline
+#endif
#define NUMPRI (EV_MAXPRI - EV_MINPRI + 1)
-#define ABSPRI(w) ((w)->priority - EV_MINPRI)
+#define ABSPRI(w) (((W)w)->priority - EV_MINPRI)
-#define EMPTY0 /* required for microsofts broken pseudo-c compiler */
+#define EMPTY /* required for microsofts broken pseudo-c compiler */
#define EMPTY2(a,b) /* used to suppress some warnings */
typedef ev_watcher *W;
}
}
-static void *(*alloc)(void *ptr, size_t size) = realloc;
+static void *(*alloc)(void *ptr, long size);
void
-ev_set_allocator (void *(*cb)(void *ptr, size_t size))
+ev_set_allocator (void *(*cb)(void *ptr, long size))
{
alloc = cb;
}
inline_speed void *
-ev_realloc (void *ptr, size_t size)
+ev_realloc (void *ptr, long size)
{
- ptr = alloc (ptr, size);
+ ptr = alloc ? alloc (ptr, size) : realloc (ptr, size);
if (!ptr && size)
{
- fprintf (stderr, "libev: cannot allocate %ld bytes, aborting.", (long)size);
+ fprintf (stderr, "libev: cannot allocate %ld bytes, aborting.", size);
abort ();
}
int events;
} ANPENDING;
+#if EV_USE_INOTIFY
typedef struct
{
-#if EV_USE_INOTIFY
WL head;
-#endif
} ANFS;
+#endif
#if EV_MULTIPLICITY
}
#endif
-#define array_roundsize(type,n) (((n) | 4) & ~3)
+int inline_size
+array_nextsize (int elem, int cur, int cnt)
+{
+ int ncur = cur + 1;
+
+ do
+ ncur <<= 1;
+ while (cnt > ncur);
+
+ /* if size > 4096, round to 4096 - 4 * longs to accomodate malloc overhead */
+ if (elem * ncur > 4096)
+ {
+ ncur *= elem;
+ ncur = (ncur + elem + 4095 + sizeof (void *) * 4) & ~4095;
+ ncur = ncur - sizeof (void *) * 4;
+ ncur /= elem;
+ }
+
+ return ncur;
+}
+
+inline_speed void *
+array_realloc (int elem, void *base, int *cur, int cnt)
+{
+ *cur = array_nextsize (elem, *cur, cnt);
+ return ev_realloc (base, elem * *cur);
+}
#define array_needsize(type,base,cur,cnt,init) \
- if (expect_false ((cnt) > cur)) \
+ if (expect_false ((cnt) > (cur))) \
{ \
- int newcnt = cur; \
- do \
- { \
- newcnt = array_roundsize (type, newcnt << 1); \
- } \
- while ((cnt) > newcnt); \
- \
- base = (type *)ev_realloc (base, sizeof (type) * (newcnt));\
- init (base + cur, newcnt - cur); \
- cur = newcnt; \
+ int ocur_ = (cur); \
+ (base) = (type *)array_realloc \
+ (sizeof (type), (base), &(cur), (cnt)); \
+ init ((base) + (ocur_), (cur) - ocur_); \
}
+#if 0
#define array_slim(type,stem) \
if (stem ## max < array_roundsize (stem ## cnt >> 2)) \
{ \
base = (type *)ev_realloc (base, sizeof (type) * (stem ## max));\
fprintf (stderr, "slimmed down " # stem " to %d\n", stem ## max);/*D*/\
}
+#endif
#define array_free(stem, idx) \
ev_free (stem ## s idx); stem ## cnt idx = stem ## max idx = 0;
void
ev_feed_fd_event (EV_P_ int fd, int revents)
{
- fd_event (EV_A_ fd, revents);
+ if (fd >= 0 && fd < anfdmax)
+ fd_event (EV_A_ fd, revents);
}
void inline_size
{
int fd;
- /* this should be highly optimised to not do anything but set a flag */
for (fd = 0; fd < anfdmax; ++fd)
if (anfds [fd].events)
{
for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next)
if (w->pid == pid || !w->pid)
{
- ev_priority (w) = ev_priority (sw); /* need to do it *now* */
- w->rpid = pid;
- w->rstatus = status;
+ ev_set_priority (w, ev_priority (sw)); /* need to do it *now* */
+ w->rpid = pid;
+ w->rstatus = status;
ev_feed_event (EV_A_ (W)w, EV_CHILD);
}
}
return backend;
}
+unsigned int
+ev_loop_count (EV_P)
+{
+ return loop_count;
+}
+
static void noinline
loop_init (EV_P_ unsigned int flags)
{
now_floor = mn_now;
rtmn_diff = ev_rt_now - mn_now;
+ /* pid check not overridable via env */
+#ifndef _WIN32
+ if (flags & EVFLAG_FORKCHECK)
+ curpid = getpid ();
+#endif
+
if (!(flags & EVFLAG_NOENV)
&& !enable_secure ()
&& getenv ("LIBEV_FLAGS"))
#endif
for (i = NUMPRI; i--; )
- array_free (pending, [i]);
+ {
+ array_free (pending, [i]);
+#if EV_IDLE_ENABLE
+ array_free (idle, [i]);
+#endif
+ }
/* have to use the microsoft-never-gets-it-right macro */
- array_free (fdchange, EMPTY0);
- array_free (timer, EMPTY0);
+ array_free (fdchange, EMPTY);
+ array_free (timer, EMPTY);
#if EV_PERIODIC_ENABLE
- array_free (periodic, EMPTY0);
+ array_free (periodic, EMPTY);
#endif
- array_free (idle, EMPTY0);
- array_free (prepare, EMPTY0);
- array_free (check, EMPTY0);
+ array_free (prepare, EMPTY);
+ array_free (check, EMPTY);
backend = 0;
}
+void inline_size infy_fork (EV_P);
+
void inline_size
loop_fork (EV_P)
{
#if EV_USE_EPOLL
if (backend == EVBACKEND_EPOLL ) epoll_fork (EV_A);
#endif
+#if EV_USE_INOTIFY
+ infy_fork (EV_A);
+#endif
if (ev_is_active (&sigev))
{
/*****************************************************************************/
-int inline_size
-any_pending (EV_P)
+void
+ev_invoke (EV_P_ void *w, int revents)
{
- int pri;
-
- for (pri = NUMPRI; pri--; )
- if (pendingcnt [pri])
- return 1;
-
- return 0;
+ EV_CB_INVOKE ((W)w, revents);
}
void inline_speed
}
#endif
+#if EV_IDLE_ENABLE
+void inline_size
+idle_reify (EV_P)
+{
+ if (expect_false (idleall))
+ {
+ int pri;
+
+ for (pri = NUMPRI; pri--; )
+ {
+ if (pendingcnt [pri])
+ break;
+
+ if (idlecnt [pri])
+ {
+ queue_events (EV_A_ (W *)idles [pri], idlecnt [pri], EV_IDLE);
+ break;
+ }
+ }
+ }
+}
+#endif
+
int inline_size
time_update_monotonic (EV_P)
{
/* loop a few times, before making important decisions.
* on the choice of "4": one iteration isn't enough,
* in case we get preempted during the calls to
- * ev_time and get_clock. a second call is almost guarenteed
+ * ev_time and get_clock. a second call is almost guaranteed
* to succeed in that case, though. and looping a few more times
* doesn't hurt either as we only do this on time-jumps or
- * in the unlikely event of getting preempted here.
+ * in the unlikely event of having been preempted here.
*/
for (i = 4; --i; )
{
periodics_reschedule (EV_A);
#endif
- /* adjust timers. this is easy, as the offset is the same for all */
+ /* adjust timers. this is easy, as the offset is the same for all of them */
for (i = 0; i < timercnt; ++i)
((WT)timers [i])->at += ev_rt_now - mn_now;
}
? EVUNLOOP_ONE
: EVUNLOOP_CANCEL;
- while (activecnt)
+ call_pending (EV_A); /* in case we recurse, ensure ordering stays nice and clean */
+
+ do
{
- /* we might have forked, so reify kernel state if necessary */
- #if EV_FORK_ENABLE
- if (expect_false (postfork))
- if (forkcnt)
- {
- queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
- call_pending (EV_A);
- }
- #endif
+#ifndef _WIN32
+ if (expect_false (curpid)) /* penalise the forking check even more */
+ if (expect_false (getpid () != curpid))
+ {
+ curpid = getpid ();
+ postfork = 1;
+ }
+#endif
+
+#if EV_FORK_ENABLE
+ /* we might have forked, so queue fork handlers */
+ if (expect_false (postfork))
+ if (forkcnt)
+ {
+ queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
+ call_pending (EV_A);
+ }
+#endif
/* queue check watchers (and execute them) */
if (expect_false (preparecnt))
call_pending (EV_A);
}
+ if (expect_false (!activecnt))
+ break;
+
/* we might have forked, so reify kernel state if necessary */
if (expect_false (postfork))
loop_fork (EV_A);
/* calculate blocking time */
{
- double block;
+ ev_tstamp block;
- if (flags & EVLOOP_NONBLOCK || idlecnt)
+ if (expect_false (flags & EVLOOP_NONBLOCK || idleall || !activecnt))
block = 0.; /* do not block at all */
else
{
if (expect_false (block < 0.)) block = 0.;
}
+ ++loop_count;
backend_poll (EV_A_ block);
}
periodics_reify (EV_A); /* absolute timers called first */
#endif
+#if EV_IDLE_ENABLE
/* queue idle watchers unless other events are pending */
- if (idlecnt && !any_pending (EV_A))
- queue_events (EV_A_ (W *)idles, idlecnt, EV_IDLE);
+ idle_reify (EV_A);
+#endif
/* queue check watchers, to be executed first */
if (expect_false (checkcnt))
call_pending (EV_A);
- if (expect_false (loop_done))
- break;
}
+ while (expect_true (activecnt && !loop_done));
if (loop_done == EVUNLOOP_ONE)
loop_done = EVUNLOOP_CANCEL;
}
void inline_speed
-ev_clear_pending (EV_P_ W w)
+clear_pending (EV_P_ W w)
{
if (w->pending)
{
}
}
+int
+ev_clear_pending (EV_P_ void *w)
+{
+ W w_ = (W)w;
+ int pending = w_->pending;
+
+ if (!pending)
+ return 0;
+
+ w_->pending = 0;
+ ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1;
+ p->w = 0;
+
+ return p->events;
+}
+
+void inline_size
+pri_adjust (EV_P_ W w)
+{
+ int pri = w->priority;
+ pri = pri < EV_MINPRI ? EV_MINPRI : pri;
+ pri = pri > EV_MAXPRI ? EV_MAXPRI : pri;
+ w->priority = pri;
+}
+
void inline_speed
ev_start (EV_P_ W w, int active)
{
- if (w->priority < EV_MINPRI) w->priority = EV_MINPRI;
- if (w->priority > EV_MAXPRI) w->priority = EV_MAXPRI;
-
+ pri_adjust (EV_A_ w);
w->active = active;
ev_ref (EV_A);
}
void
ev_io_stop (EV_P_ ev_io *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_timer_stop (EV_P_ ev_timer *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_periodic_stop (EV_P_ ev_periodic *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_signal_stop (EV_P_ ev_signal *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_child_stop (EV_P_ ev_child *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
#define DEF_STAT_INTERVAL 5.0074891
#define MIN_STAT_INTERVAL 0.1074891
-void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents);
+static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents);
#if EV_USE_INOTIFY
-# define EV_INOTIFY_BUFSIZE ((PATH_MAX + sizeof (struct inotify_event)) + 2048)
+# define EV_INOTIFY_BUFSIZE 8192
static void noinline
infy_add (EV_P_ ev_stat *w)
ev_timer_start (EV_A_ &w->timer); /* this is not race-free, so we still need to recheck periodically */
/* monitor some parent directory for speedup hints */
- if (errno == ENOENT || errno == EACCES)
+ if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096)
{
- char path [PATH_MAX];
+ char path [4096];
strcpy (path, w->path);
do
break; /* whoops, no '/', complain to your admin */
*pend = 0;
- w->wd = inotify_add_watch (fs_fd, path, IN_DELETE_SELF | IN_CREATE | IN_MOVED_TO | IN_MASK_ADD);
+ w->wd = inotify_add_watch (fs_fd, path, mask);
}
while (w->wd < 0 && (errno == ENOENT || errno == EACCES));
}
static void noinline
infy_del (EV_P_ ev_stat *w)
{
- WL w_;
int slot;
int wd = w->wd;
infy_add (EV_A_ w); /* re-add, no matter what */
}
- stat_timer_cb (EV_P_ &w->timer, 0);
+ stat_timer_cb (EV_A_ &w->timer, 0);
}
}
}
}
}
+void inline_size
+infy_fork (EV_P)
+{
+ int slot;
+
+ if (fs_fd < 0)
+ return;
+
+ close (fs_fd);
+ fs_fd = inotify_init ();
+
+ for (slot = 0; slot < EV_INOTIFY_HASHSIZE; ++slot)
+ {
+ WL w_ = fs_hash [slot].head;
+ fs_hash [slot].head = 0;
+
+ while (w_)
+ {
+ ev_stat *w = (ev_stat *)w_;
+ w_ = w_->next; /* lets us add this watcher */
+
+ w->wd = -1;
+
+ if (fs_fd >= 0)
+ infy_add (EV_A_ w); /* re-add, no matter what */
+ else
+ ev_timer_start (EV_A_ &w->timer);
+ }
+
+ }
+}
+
#endif
void
w->attr.st_nlink = 1;
}
-void noinline
+static void noinline
stat_timer_cb (EV_P_ ev_timer *w_, int revents)
{
ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
w->prev = w->attr;
ev_stat_stat (EV_A_ w);
- if (memcmp (&w->prev, &w->attr, sizeof (ev_statdata)))
- {
+ /* memcmp doesn't work on netbsd, they.... do stuff to their struct stat */
+ if (
+ w->prev.st_dev != w->attr.st_dev
+ || w->prev.st_ino != w->attr.st_ino
+ || w->prev.st_mode != w->attr.st_mode
+ || w->prev.st_nlink != w->attr.st_nlink
+ || w->prev.st_uid != w->attr.st_uid
+ || w->prev.st_gid != w->attr.st_gid
+ || w->prev.st_rdev != w->attr.st_rdev
+ || w->prev.st_size != w->attr.st_size
+ || w->prev.st_atime != w->attr.st_atime
+ || w->prev.st_mtime != w->attr.st_mtime
+ || w->prev.st_ctime != w->attr.st_ctime
+ ) {
#if EV_USE_INOTIFY
infy_del (EV_A_ w);
infy_add (EV_A_ w);
void
ev_stat_stop (EV_P_ ev_stat *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
}
#endif
+#if EV_IDLE_ENABLE
void
ev_idle_start (EV_P_ ev_idle *w)
{
if (expect_false (ev_is_active (w)))
return;
- ev_start (EV_A_ (W)w, ++idlecnt);
- array_needsize (ev_idle *, idles, idlemax, idlecnt, EMPTY2);
- idles [idlecnt - 1] = w;
+ pri_adjust (EV_A_ (W)w);
+
+ {
+ int active = ++idlecnt [ABSPRI (w)];
+
+ ++idleall;
+ ev_start (EV_A_ (W)w, active);
+
+ array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, EMPTY2);
+ idles [ABSPRI (w)][active - 1] = w;
+ }
}
void
ev_idle_stop (EV_P_ ev_idle *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
{
int active = ((W)w)->active;
- idles [active - 1] = idles [--idlecnt];
- ((W)idles [active - 1])->active = active;
- }
- ev_stop (EV_A_ (W)w);
+ idles [ABSPRI (w)][active - 1] = idles [ABSPRI (w)][--idlecnt [ABSPRI (w)]];
+ ((W)idles [ABSPRI (w)][active - 1])->active = active;
+
+ ev_stop (EV_A_ (W)w);
+ --idleall;
+ }
}
+#endif
void
ev_prepare_start (EV_P_ ev_prepare *w)
void
ev_prepare_stop (EV_P_ ev_prepare *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_check_stop (EV_P_ ev_check *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_embed_stop (EV_P_ ev_embed *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;
void
ev_fork_stop (EV_P_ ev_fork *w)
{
- ev_clear_pending (EV_A_ (W)w);
+ clear_pending (EV_A_ (W)w);
if (expect_false (!ev_is_active (w)))
return;