From b7e58d7ed7f85d7cb7fe1c34cfe3fa2484a6dc31 Mon Sep 17 00:00:00 2001
From: root <root>
Date: Mon, 26 Nov 2007 19:49:36 +0000
Subject: - add non-os-assisted ev_stat watcher - add some EV_MINIMAL, exg made
 me do it

---
 ev.c      | 162 +++++++++++++++++++++++++++++++++++++++++++++-----------------
 ev.h      |  84 ++++++++++++++++++++++++--------
 ev.pod    |  23 +++++++--
 ev_vars.h |   2 +-
 4 files changed, 203 insertions(+), 68 deletions(-)

diff --git a/ev.c b/ev.c
index 4cb9467..96d297c 100644
--- a/ev.c
+++ b/ev.c
@@ -113,9 +113,9 @@ extern "C" {
 #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>
@@ -189,10 +189,19 @@ extern "C" {
 
 #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)
@@ -308,7 +317,7 @@ typedef struct
 
 /*****************************************************************************/
 
-ev_tstamp
+ev_tstamp noinline
 ev_time (void)
 {
 #if EV_USE_REALTIME
@@ -322,7 +331,7 @@ ev_time (void)
 #endif
 }
 
-inline ev_tstamp
+ev_tstamp inline_size
 get_clock (void)
 {
 #if EV_USE_MONOTONIC
@@ -375,7 +384,7 @@ ev_now (EV_P)
 
 /*****************************************************************************/
 
-static void
+void inline_size
 anfds_init (ANFD *base, int count)
 {
   while (count--)
@@ -388,7 +397,7 @@ anfds_init (ANFD *base, int count)
     }
 }
 
-void
+void noinline
 ev_feed_event (EV_P_ void *w, int revents)
 {
   W w_ = (W)w;
@@ -414,7 +423,7 @@ queue_events (EV_P_ W *events, int eventcnt, int type)
     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;
@@ -437,7 +446,7 @@ ev_feed_fd_event (EV_P_ int fd, int revents)
 
 /*****************************************************************************/
 
-inline void
+void inline_size
 fd_reify (EV_P)
 {
   int i;
@@ -471,7 +480,7 @@ fd_reify (EV_P)
   fdchangecnt = 0;
 }
 
-static void
+void inline_size
 fd_change (EV_P_ int fd)
 {
   if (expect_false (anfds [fd].reify))
@@ -484,7 +493,7 @@ fd_change (EV_P_ int fd)
   fdchanges [fdchangecnt - 1] = fd;
 }
 
-static void
+void inline_speed
 fd_kill (EV_P_ int fd)
 {
   ev_io *w;
@@ -496,7 +505,7 @@ fd_kill (EV_P_ int fd)
     }
 }
 
-inline int
+int inline_size
 fd_valid (int fd)
 {
 #ifdef _WIN32
@@ -507,7 +516,7 @@ fd_valid (int fd)
 }
 
 /* called on EBADF to verify fds */
-static void
+static void noinline
 fd_ebadf (EV_P)
 {
   int fd;
@@ -519,7 +528,7 @@ fd_ebadf (EV_P)
 }
 
 /* called on ENOMEM in select/poll to kill some fds and retry */
-static void
+static void noinline
 fd_enomem (EV_P)
 {
   int fd;
@@ -533,7 +542,7 @@ fd_enomem (EV_P)
 }
 
 /* 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;
@@ -549,7 +558,7 @@ fd_rearm_all (EV_P)
 
 /*****************************************************************************/
 
-static void
+void inline_speed
 upheap (WT *heap, int k)
 {
   WT w = heap [k];
@@ -566,7 +575,7 @@ upheap (WT *heap, int k)
 
 }
 
-static void
+void inline_speed
 downheap (WT *heap, int N, int k)
 {
   WT w = heap [k];
@@ -590,7 +599,7 @@ downheap (WT *heap, int N, int k)
   ((W)heap [k])->active = k + 1;
 }
 
-inline void
+void inline_size
 adjustheap (WT *heap, int N, int k)
 {
   upheap (heap, k);
@@ -612,7 +621,7 @@ static int sigpipe [2];
 static sig_atomic_t volatile gotsig;
 static ev_io sigev;
 
-static void
+void inline_size
 signals_init (ANSIG *base, int count)
 {
   while (count--)
@@ -642,7 +651,7 @@ sighandler (int signum)
     }
 }
 
-void
+void noinline
 ev_feed_signal_event (EV_P_ int signum)
 {
   WL w;
@@ -675,7 +684,7 @@ sigcb (EV_P_ ev_io *iow, int revents)
       ev_feed_signal_event (EV_A_ signum + 1);
 }
 
-static void
+void inline_size
 fd_intern (int fd)
 {
 #ifdef _WIN32
@@ -687,7 +696,7 @@ fd_intern (int fd)
 #endif
 }
 
-static void
+static void noinline
 siginit (EV_P)
 {
   fd_intern (sigpipe [0]);
@@ -710,7 +719,7 @@ static ev_signal childev;
 # 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;
@@ -774,7 +783,7 @@ ev_version_minor (void)
 }
 
 /* return true if we are running with elevated privileges and should ignore env variables */
-static int
+int inline_size
 enable_secure (void)
 {
 #ifdef _WIN32
@@ -906,7 +915,7 @@ loop_destroy (EV_P)
   /* 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);
@@ -1052,7 +1061,7 @@ ev_default_fork (void)
 
 /*****************************************************************************/
 
-static int
+int inline_size
 any_pending (EV_P)
 {
   int pri;
@@ -1064,7 +1073,7 @@ any_pending (EV_P)
   return 0;
 }
 
-inline void
+void inline_speed
 call_pending (EV_P)
 {
   int pri;
@@ -1084,7 +1093,7 @@ call_pending (EV_P)
       }
 }
 
-inline void
+void inline_size
 timers_reify (EV_P)
 {
   while (timercnt && ((WT)timers [0])->at <= mn_now)
@@ -1111,8 +1120,8 @@ timers_reify (EV_P)
     }
 }
 
-#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)
@@ -1141,7 +1150,7 @@ periodics_reify (EV_P)
     }
 }
 
-static void
+static void noinline
 periodics_reschedule (EV_P)
 {
   int i;
@@ -1163,7 +1172,7 @@ periodics_reschedule (EV_P)
 }
 #endif
 
-inline int
+int inline_size
 time_update_monotonic (EV_P)
 {
   mn_now = get_clock ();
@@ -1181,7 +1190,7 @@ time_update_monotonic (EV_P)
     }
 }
 
-inline void
+void inline_size
 time_update (EV_P)
 {
   int i;
@@ -1213,7 +1222,7 @@ time_update (EV_P)
               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 */
@@ -1227,7 +1236,7 @@ time_update (EV_P)
 
       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
 
@@ -1304,7 +1313,7 @@ ev_loop (EV_P_ int flags)
                 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;
@@ -1323,7 +1332,7 @@ ev_loop (EV_P_ int flags)
 
       /* 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
 
@@ -1353,14 +1362,14 @@ ev_unloop (EV_P_ int how)
 
 /*****************************************************************************/
 
-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)
@@ -1375,7 +1384,7 @@ wlist_del (WL *head, WL elem)
     }
 }
 
-inline void
+void inline_speed
 ev_clear_pending (EV_P_ W w)
 {
   if (w->pending)
@@ -1385,7 +1394,7 @@ ev_clear_pending (EV_P_ W w)
     }
 }
 
-inline void
+void inline_speed
 ev_start (EV_P_ W w, int active)
 {
   if (w->priority < EV_MINPRI) w->priority = EV_MINPRI;
@@ -1395,7 +1404,7 @@ ev_start (EV_P_ W w, int active)
   ev_ref (EV_A);
 }
 
-inline void
+void inline_size
 ev_stop (EV_P_ W w)
 {
   ev_unref (EV_A);
@@ -1494,7 +1503,7 @@ ev_timer_again (EV_P_ ev_timer *w)
     }
 }
 
-#if EV_PERIODICS
+#if EV_PERIODIC_ENABLE
 void
 ev_periodic_start (EV_P_ ev_periodic *w)
 {
@@ -1697,8 +1706,8 @@ ev_child_stop (EV_P_ ev_child *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);
@@ -1729,6 +1738,7 @@ ev_embed_start (EV_P_ ev_embed *w)
 
   ev_set_priority (&w->io, ev_priority (w));
   ev_io_start (EV_A_ &w->io);
+
   ev_start (EV_A_ (W)w, 1);
 }
 
@@ -1740,6 +1750,68 @@ ev_embed_stop (EV_P_ ev_embed *w)
     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
diff --git a/ev.h b/ev.h
index 0e56875..9fcae61 100644
--- a/ev.h
+++ b/ev.h
@@ -48,8 +48,22 @@ typedef double ev_tstamp;
 # 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? */
@@ -68,22 +82,25 @@ struct ev_loop;
 # 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
@@ -216,7 +233,7 @@ typedef struct ev_child
   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
@@ -228,6 +245,24 @@ 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
 {
@@ -242,9 +277,12 @@ 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 */
@@ -370,6 +408,7 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent
 #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)
@@ -380,6 +419,7 @@ void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revent
 #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 */
@@ -410,7 +450,7 @@ void ev_timer_stop     (EV_P_ ev_timer *w);
 /* 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);
@@ -433,13 +473,19 @@ void ev_signal_stop    (EV_P_ ev_signal *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
diff --git a/ev.pod b/ev.pod
index cab6e18..3f4a064 100644
--- a/ev.pod
+++ b/ev.pod
@@ -1702,10 +1702,27 @@ additional independent event loops. Otherwise there will be no support
 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
 
diff --git a/ev_vars.h b/ev_vars.h
index a298104..080ba55 100644
--- a/ev_vars.h
+++ b/ev_vars.h
@@ -62,7 +62,7 @@ VARx(struct ev_timer **, timers)
 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)
-- 
cgit v1.2.3