#include <signal.h>
#ifndef _WIN32
-# include <unistd.h>
# include <sys/time.h>
# include <sys/wait.h>
+# include <unistd.h>
#else
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#if __GNUC__ >= 3
# define expect(expr,value) __builtin_expect ((expr),(value))
-# define inline static inline
+# 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
#else
# define expect(expr,value) (expr)
-# define inline static
+# define inline_speed static
+# define inline_minimal static
+# define noinline
#endif
#define expect_false(expr) expect ((expr) != 0, 0)
/*****************************************************************************/
-ev_tstamp
+ev_tstamp noinline
ev_time (void)
{
#if EV_USE_REALTIME
#endif
}
-inline ev_tstamp
+ev_tstamp inline_size
get_clock (void)
{
#if EV_USE_MONOTONIC
/*****************************************************************************/
-static void
+void inline_size
anfds_init (ANFD *base, int count)
{
while (count--)
}
}
-void
+void noinline
ev_feed_event (EV_P_ void *w, int revents)
{
W w_ = (W)w;
ev_feed_event (EV_A_ events [i], type);
}
-inline void
+void inline_speed
fd_event (EV_P_ int fd, int revents)
{
ANFD *anfd = anfds + fd;
/*****************************************************************************/
-inline void
+void inline_size
fd_reify (EV_P)
{
int i;
fdchangecnt = 0;
}
-static void
+void inline_size
fd_change (EV_P_ int fd)
{
if (expect_false (anfds [fd].reify))
fdchanges [fdchangecnt - 1] = fd;
}
-static void
+void inline_speed
fd_kill (EV_P_ int fd)
{
ev_io *w;
}
}
-inline int
+int inline_size
fd_valid (int fd)
{
#ifdef _WIN32
}
/* called on EBADF to verify fds */
-static void
+static void noinline
fd_ebadf (EV_P)
{
int fd;
}
/* called on ENOMEM in select/poll to kill some fds and retry */
-static void
+static void noinline
fd_enomem (EV_P)
{
int fd;
}
/* usually called after fork if backend needs to re-arm all fds from scratch */
-static void
+static void noinline
fd_rearm_all (EV_P)
{
int fd;
/*****************************************************************************/
-static void
+void inline_speed
upheap (WT *heap, int k)
{
WT w = heap [k];
}
-static void
+void inline_speed
downheap (WT *heap, int N, int k)
{
WT w = heap [k];
((W)heap [k])->active = k + 1;
}
-inline void
+void inline_size
adjustheap (WT *heap, int N, int k)
{
upheap (heap, k);
static sig_atomic_t volatile gotsig;
static ev_io sigev;
-static void
+void inline_size
signals_init (ANSIG *base, int count)
{
while (count--)
}
}
-void
+void noinline
ev_feed_signal_event (EV_P_ int signum)
{
WL w;
ev_feed_signal_event (EV_A_ signum + 1);
}
-static void
+void inline_size
fd_intern (int fd)
{
#ifdef _WIN32
#endif
}
-static void
+static void noinline
siginit (EV_P)
{
fd_intern (sigpipe [0]);
# define WCONTINUED 0
#endif
-static void
+void inline_speed
child_reap (EV_P_ ev_signal *sw, int chain, int pid, int status)
{
ev_child *w;
}
/* return true if we are running with elevated privileges and should ignore env variables */
-static int
+int inline_size
enable_secure (void)
{
#ifdef _WIN32
/* have to use the microsoft-never-gets-it-right macro */
array_free (fdchange, EMPTY0);
array_free (timer, EMPTY0);
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
array_free (periodic, EMPTY0);
#endif
array_free (idle, EMPTY0);
/*****************************************************************************/
-static int
+int inline_size
any_pending (EV_P)
{
int pri;
return 0;
}
-inline void
+void inline_speed
call_pending (EV_P)
{
int pri;
}
}
-inline void
+void inline_size
timers_reify (EV_P)
{
while (timercnt && ((WT)timers [0])->at <= mn_now)
}
}
-#if EV_PERIODICS
-inline void
+#if EV_PERIODIC_ENABLE
+void inline_size
periodics_reify (EV_P)
{
while (periodiccnt && ((WT)periodics [0])->at <= ev_rt_now)
}
}
-static void
+static void noinline
periodics_reschedule (EV_P)
{
int i;
}
#endif
-inline int
+int inline_size
time_update_monotonic (EV_P)
{
mn_now = get_clock ();
}
}
-inline void
+void inline_size
time_update (EV_P)
{
int i;
now_floor = mn_now;
}
-# if EV_PERIODICS
+# if EV_PERIODIC_ENABLE
periodics_reschedule (EV_A);
# endif
/* no timer adjustment, as the monotonic clock doesn't jump */
if (expect_false (mn_now > ev_rt_now || mn_now < ev_rt_now - MAX_BLOCKTIME - MIN_TIMEJUMP))
{
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
periodics_reschedule (EV_A);
#endif
if (block > to) block = to;
}
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
if (periodiccnt)
{
ev_tstamp to = ((WT)periodics [0])->at - ev_rt_now + backend_fudge;
/* queue pending timers and reschedule them */
timers_reify (EV_A); /* relative timers called last */
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
periodics_reify (EV_A); /* absolute timers called first */
#endif
/*****************************************************************************/
-inline void
+void inline_size
wlist_add (WL *head, WL elem)
{
elem->next = *head;
*head = elem;
}
-inline void
+void inline_size
wlist_del (WL *head, WL elem)
{
while (*head)
}
}
-inline void
+void inline_speed
ev_clear_pending (EV_P_ W w)
{
if (w->pending)
}
}
-inline void
+void inline_speed
ev_start (EV_P_ W w, int active)
{
if (w->priority < EV_MINPRI) w->priority = EV_MINPRI;
ev_ref (EV_A);
}
-inline void
+void inline_size
ev_stop (EV_P_ W w)
{
ev_unref (EV_A);
}
}
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
void
ev_periodic_start (EV_P_ ev_periodic *w)
{
ev_stop (EV_A_ (W)w);
}
-#if EV_MULTIPLICITY
-void
+#if EV_EMBED_ENABLE
+void noinline
ev_embed_sweep (EV_P_ ev_embed *w)
{
ev_loop (w->loop, EVLOOP_NONBLOCK);
ev_set_priority (&w->io, ev_priority (w));
ev_io_start (EV_A_ &w->io);
+
ev_start (EV_A_ (W)w, 1);
}
return;
ev_io_stop (EV_A_ &w->io);
+
+ ev_stop (EV_A_ (W)w);
+}
+#endif
+
+#if EV_STAT_ENABLE
+
+# ifdef _WIN32
+# define lstat(a,b) stat(a,b)
+# endif
+
+void
+ev_stat_stat (EV_P_ ev_stat *w)
+{
+ if (lstat (w->path, &w->attr) < 0)
+ w->attr.st_nlink = 0;
+ else if (!w->attr.st_nlink)
+ w->attr.st_nlink = 1;
+}
+
+static void
+stat_timer_cb (EV_P_ ev_timer *w_, int revents)
+{
+ ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
+
+ /* we copy this here each the time so that */
+ /* prev has the old value when the callback gets invoked */
+ w->prev = w->attr;
+ ev_stat_stat (EV_A_ w);
+
+ if (memcmp (&w->prev, &w->attr, sizeof (ev_statdata)))
+ ev_feed_event (EV_A_ w, EV_STAT);
+}
+
+void
+ev_stat_start (EV_P_ ev_stat *w)
+{
+ if (expect_false (ev_is_active (w)))
+ return;
+
+ /* since we use memcmp, we need to clear any padding data etc. */
+ memset (&w->prev, 0, sizeof (ev_statdata));
+ memset (&w->attr, 0, sizeof (ev_statdata));
+
+ ev_stat_stat (EV_A_ w);
+
+ ev_timer_init (&w->timer, stat_timer_cb, w->interval, w->interval);
+ ev_set_priority (&w->timer, ev_priority (w));
+ ev_timer_start (EV_A_ &w->timer);
+
+ ev_start (EV_A_ (W)w, 1);
+}
+
+void
+ev_stat_stop (EV_P_ ev_stat *w)
+{
+ ev_clear_pending (EV_A_ (W)w);
+ if (expect_false (!ev_is_active (w)))
+ return;
+
+ ev_timer_stop (EV_A_ &w->timer);
+
ev_stop (EV_A_ (W)w);
}
#endif
# define EV_MULTIPLICITY 1
#endif
-#ifndef EV_PERIODICS
-# define EV_PERIODICS 1
+#ifndef EV_PERIODIC_ENABLE
+# define EV_PERIODIC_ENABLE 1
+#endif
+
+#ifndef EV_STAT_ENABLE
+# define EV_STAT_ENABLE 1
+#endif
+
+#ifndef EV_EMBED_ENABLE
+# define EV_EMBED_ENABLE 1
+#endif
+
+/*****************************************************************************/
+
+#if EV_STAT_ENABLE
+# include <sys/stat.h>
#endif
/* support multiple event loops? */
# define EV_A_
# define EV_DEFAULT_A
# define EV_DEFAULT_A_
+
+# undef EV_EMBED_ENABLE
#endif
/* eventmask, revents, events... */
-#define EV_UNDEF -1L /* guaranteed to be invalid */
-#define EV_NONE 0x00L
-#define EV_READ 0x01L /* io only */
-#define EV_WRITE 0x02L /* io only */
-#define EV_TIMEOUT 0x000100L /* timer only */
-#define EV_PERIODIC 0x000200L /* periodic timer only */
-#define EV_SIGNAL 0x000400L /* signal only */
-#define EV_IDLE 0x000800L /* idle only */
-#define EV_CHECK 0x001000L /* check only */
-#define EV_PREPARE 0x002000L /* prepare only */
-#define EV_CHILD 0x004000L /* child/pid only */
-#define EV_EMBED 0x008000L /* embedded event loop */
-#define EV_ERROR 0x800000L /* sent when an error occurs */
+#define EV_UNDEF -1L /* guaranteed to be invalid */
+#define EV_NONE 0x00L /* no events */
+#define EV_READ 0x01L /* ev_io detected read will not block */
+#define EV_WRITE 0x02L /* ev_io detected write will not block */
+#define EV_TIMEOUT 0x00000100L /* timer timed out */
+#define EV_PERIODIC 0x00000200L /* periodic timer timed out */
+#define EV_SIGNAL 0x00000400L /* signal was received */
+#define EV_IDLE 0x00000800L /* event loop is idling */
+#define EV_PREPARE 0x00001000L /* event loop about to poll */
+#define EV_CHECK 0x00002000L /* event loop finished poll */
+#define EV_CHILD 0x00004000L /* child/pid had status change */
+#define EV_EMBED 0x00008000L /* embedded event loop needs sweep */
+#define EV_STAT 0x00010000L /* stat data changed */
+#define EV_ERROR 0x80000000L /* sent when an error occurs */
/* can be used to add custom fields to all watchers, while losing binary compatibility */
#ifndef EV_COMMON
int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */
} ev_child;
-#if EV_MULTIPLICITY
+#if EV_EMBED_ENABLE
/* used to embed an event loop inside another */
/* the callback gets invoked when the event loop has handled events, and can be 0 */
typedef struct ev_embed
} ev_embed;
#endif
+#if EV_STAT_ENABLE
+/* st_nlink = 0 means missing file or other error */
+typedef struct stat ev_statdata;
+
+/* invoked each time the stat data changes for a given path */
+/* revent EV_STAT */
+typedef struct ev_stat
+{
+ EV_WATCHER (ev_stat)
+
+ ev_timer timer; /* private */
+ ev_tstamp interval; /* rw */
+ const char *path; /* ro */
+ ev_statdata prev; /* ro */
+ ev_statdata attr; /* ro */
+} ev_stat;
+#endif
+
/* the presence of this union forces similar struct layout */
union ev_any_watcher
{
struct ev_check check;
struct ev_signal signal;
struct ev_child child;
-#if EV_MULTIPLICITY
+#if EV_EMBED_ENABLE
struct ev_embed embed;
#endif
+#if EV_STAT_ENABLE
+ struct ev_stat stat;
+#endif
};
/* bits for ev_default_loop and ev_loop_new */
#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */
#define ev_child_set(ev,pid_) do { (ev)->pid = (pid_); } while (0)
#define ev_embed_set(ev,loop_) do { (ev)->loop = (loop_); } while (0)
+#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); } while (0)
#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)
#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0)
#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0)
#define ev_child_init(ev,cb,pid) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid)); } while (0)
#define ev_embed_init(ev,cb,loop) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(loop)); } while (0)
+#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_path_set ((ev),(path),(interval)); } while (0)
#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */
#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */
/* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */
void ev_timer_again (EV_P_ ev_timer *w);
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
void ev_periodic_start (EV_P_ ev_periodic *w);
void ev_periodic_stop (EV_P_ ev_periodic *w);
void ev_periodic_again (EV_P_ ev_periodic *w);
void ev_child_start (EV_P_ ev_child *w);
void ev_child_stop (EV_P_ ev_child *w);
-# if EV_MULTIPLICITY
+# if EV_EMBED_ENABLE
/* only supported when loop to be embedded is in fact embeddable */
void ev_embed_start (EV_P_ ev_embed *w);
void ev_embed_stop (EV_P_ ev_embed *w);
void ev_embed_sweep (EV_P_ ev_embed *w);
# endif
+# if EV_STAT_ENABLE
+void ev_stat_start (EV_P_ ev_stat *w);
+void ev_stat_stop (EV_P_ ev_stat *w);
+void ev_stat_stat (EV_P_ ev_stat *w);
+# endif
+
#endif
#ifdef __cplusplus
for multiple event loops and there is no first event loop pointer
argument. Instead, all functions act on the single default loop.
-=item EV_PERIODICS
+=item EV_PERIODIC_ENABLE
-If undefined or defined to be C<1>, then periodic timers are supported,
-otherwise not. This saves a few kb of code.
+If undefined or defined to be C<1>, then periodic timers are supported. If
+defined to be C<0>, then they are not. Disabling them saves a few kB of
+code.
+
+=item EV_EMBED_ENABLE
+
+If undefined or defined to be C<1>, then embed watchers are supported. If
+defined to be C<0>, then they are not.
+
+=item EV_STAT_ENABLE
+
+If undefined or defined to be C<1>, then stat watchers are supported. If
+defined to be C<0>, then they are not.
+
+=item EV_MINIMAL
+
+If you need to shave off some kilobytes of code at the expense of some
+speed, define this symbol to C<1>. Currently only used for gcc to override
+some inlining decisions, saves roughly 30% codesize of amd64.
=item EV_COMMON
VARx(int, timermax)
VARx(int, timercnt)
-#if EV_PERIODICS || EV_GENWRAP
+#if EV_PERIODIC_ENABLE || EV_GENWRAP
VARx(struct ev_periodic **, periodics)
VARx(int, periodicmax)
VARx(int, periodiccnt)