rev 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/CHANGES +11 -0
  2. data/README +10 -3
  3. data/Rakefile +2 -2
  4. data/examples/echo_client.rb +35 -0
  5. data/examples/google.rb +8 -0
  6. data/examples/httpclient.rb +35 -0
  7. data/ext/http11_client/Makefile +149 -0
  8. data/ext/http11_client/http11_client.bundle +0 -0
  9. data/ext/http11_client/http11_client.o +0 -0
  10. data/ext/http11_client/http11_parser.o +0 -0
  11. data/ext/http11_client/mkmf.log +12 -0
  12. data/ext/libev/Changes +114 -1
  13. data/ext/libev/ev.c +212 -97
  14. data/ext/libev/ev.h +13 -7
  15. data/ext/libev/ev_epoll.c +44 -11
  16. data/ext/libev/ev_kqueue.c +2 -2
  17. data/ext/libev/ev_poll.c +3 -1
  18. data/ext/libev/ev_port.c +4 -4
  19. data/ext/libev/ev_select.c +58 -19
  20. data/ext/libev/ev_vars.h +5 -1
  21. data/ext/libev/ev_win32.c +32 -3
  22. data/ext/libev/ev_wrap.h +4 -0
  23. data/ext/libev/test_libev_win32.c +123 -0
  24. data/ext/libev/update_ev_wrap +0 -0
  25. data/ext/rev/Makefile +149 -0
  26. data/ext/rev/ev_wrap.h +8 -0
  27. data/ext/rev/extconf.rb +17 -0
  28. data/ext/rev/libev.c +8 -0
  29. data/ext/rev/libev.o +0 -0
  30. data/ext/rev/mkmf.log +221 -0
  31. data/ext/rev/rev.h +8 -2
  32. data/ext/rev/rev_buffer.c +2 -3
  33. data/ext/rev/rev_buffer.o +0 -0
  34. data/ext/rev/rev_ext.bundle +0 -0
  35. data/ext/rev/rev_ext.c +4 -3
  36. data/ext/rev/rev_ext.o +0 -0
  37. data/ext/rev/rev_io_watcher.c +1 -2
  38. data/ext/rev/rev_io_watcher.o +0 -0
  39. data/ext/rev/rev_loop.c +4 -4
  40. data/ext/rev/rev_loop.o +0 -0
  41. data/ext/rev/rev_ssl.o +0 -0
  42. data/ext/rev/rev_timer_watcher.c +1 -2
  43. data/ext/rev/rev_timer_watcher.o +0 -0
  44. data/ext/rev/rev_utils.c +14 -0
  45. data/ext/rev/rev_utils.o +0 -0
  46. data/ext/rev/rev_watcher.c +7 -6
  47. data/ext/rev/rev_watcher.o +0 -0
  48. data/lib/http11_client.bundle +0 -0
  49. data/lib/rev.rb +1 -1
  50. data/lib/rev/dns_resolver.rb +29 -9
  51. data/lib/rev/io.rb +6 -4
  52. data/lib/rev/listener.rb +5 -1
  53. data/lib/rev/loop.rb +8 -4
  54. data/lib/rev/server.rb +3 -2
  55. data/lib/rev/socket.rb +14 -5
  56. data/lib/rev_ext.bundle +0 -0
  57. data/lib/revem.rb +210 -0
  58. data/rev.gemspec +2 -2
  59. metadata +29 -3
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * libev event processing core, watcher management
3
3
  *
4
- * Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without modifica-
@@ -49,6 +49,18 @@ extern "C" {
49
49
  # include "config.h"
50
50
  # endif
51
51
 
52
+ # if HAVE_CLOCK_SYSCALL
53
+ # ifndef EV_USE_CLOCK_SYSCALL
54
+ # define EV_USE_CLOCK_SYSCALL 1
55
+ # ifndef EV_USE_REALTIME
56
+ # define EV_USE_REALTIME 0
57
+ # endif
58
+ # ifndef EV_USE_MONOTONIC
59
+ # define EV_USE_MONOTONIC 1
60
+ # endif
61
+ # endif
62
+ # endif
63
+
52
64
  # if HAVE_CLOCK_GETTIME
53
65
  # ifndef EV_USE_MONOTONIC
54
66
  # define EV_USE_MONOTONIC 1
@@ -156,6 +168,7 @@ extern "C" {
156
168
  # include <sys/wait.h>
157
169
  # include <unistd.h>
158
170
  #else
171
+ # include <io.h>
159
172
  # define WIN32_LEAN_AND_MEAN
160
173
  # include <windows.h>
161
174
  # ifndef EV_SELECT_IS_WINSOCKET
@@ -165,8 +178,20 @@ extern "C" {
165
178
 
166
179
  /* this block tries to deduce configuration from header-defined symbols and defaults */
167
180
 
181
+ #ifndef EV_USE_CLOCK_SYSCALL
182
+ # if __linux && __GLIBC__ >= 2
183
+ # define EV_USE_CLOCK_SYSCALL 1
184
+ # else
185
+ # define EV_USE_CLOCK_SYSCALL 0
186
+ # endif
187
+ #endif
188
+
168
189
  #ifndef EV_USE_MONOTONIC
169
- # define EV_USE_MONOTONIC 0
190
+ # if defined (_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
191
+ # define EV_USE_MONOTONIC 1
192
+ # else
193
+ # define EV_USE_MONOTONIC 0
194
+ # endif
170
195
  #endif
171
196
 
172
197
  #ifndef EV_USE_REALTIME
@@ -174,7 +199,11 @@ extern "C" {
174
199
  #endif
175
200
 
176
201
  #ifndef EV_USE_NANOSLEEP
177
- # define EV_USE_NANOSLEEP 0
202
+ # if _POSIX_C_SOURCE >= 199309L
203
+ # define EV_USE_NANOSLEEP 1
204
+ # else
205
+ # define EV_USE_NANOSLEEP 0
206
+ # endif
178
207
  #endif
179
208
 
180
209
  #ifndef EV_USE_SELECT
@@ -279,13 +308,29 @@ extern "C" {
279
308
  #endif
280
309
 
281
310
  #if EV_USE_INOTIFY
311
+ # include <sys/utsname.h>
312
+ # include <sys/statfs.h>
282
313
  # include <sys/inotify.h>
314
+ /* some very old inotify.h headers don't have IN_DONT_FOLLOW */
315
+ # ifndef IN_DONT_FOLLOW
316
+ # undef EV_USE_INOTIFY
317
+ # define EV_USE_INOTIFY 0
318
+ # endif
283
319
  #endif
284
320
 
285
321
  #if EV_SELECT_IS_WINSOCKET
286
322
  # include <winsock.h>
287
323
  #endif
288
324
 
325
+ /* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */
326
+ /* which makes programs even slower. might work on other unices, too. */
327
+ #if EV_USE_CLOCK_SYSCALL
328
+ # include <syscall.h>
329
+ # define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts))
330
+ # undef EV_USE_MONOTONIC
331
+ # define EV_USE_MONOTONIC 1
332
+ #endif
333
+
289
334
  #if EV_USE_EVENTFD
290
335
  /* our minimum requirement is glibc 2.7 which has the stub, but not the header */
291
336
  # include <stdint.h>
@@ -375,7 +420,7 @@ ev_set_syserr_cb (void (*cb)(const char *msg))
375
420
  }
376
421
 
377
422
  static void noinline
378
- syserr (const char *msg)
423
+ ev_syserr (const char *msg)
379
424
  {
380
425
  if (!msg)
381
426
  msg = "(libev) system error";
@@ -436,6 +481,11 @@ typedef struct
436
481
  WL head;
437
482
  unsigned char events;
438
483
  unsigned char reify;
484
+ unsigned char emask; /* the epoll backend stores the actual kernel mask in here */
485
+ unsigned char unused;
486
+ #if EV_USE_EPOLL
487
+ unsigned int egen; /* generation counter to counter epoll bugs */
488
+ #endif
439
489
  #if EV_SELECT_IS_WINSOCKET
440
490
  SOCKET handle;
441
491
  #endif
@@ -558,6 +608,9 @@ ev_sleep (ev_tstamp delay)
558
608
  tv.tv_sec = (time_t)delay;
559
609
  tv.tv_usec = (long)((delay - (ev_tstamp)(tv.tv_sec)) * 1e6);
560
610
 
611
+ /* here we rely on sys/time.h + sys/types.h + unistd.h providing select */
612
+ /* somehting nto guaranteed by newer posix versions, but guaranteed */
613
+ /* by older ones */
561
614
  select (0, 0, 0, 0, &tv);
562
615
  #endif
563
616
  }
@@ -595,6 +648,9 @@ array_realloc (int elem, void *base, int *cur, int cnt)
595
648
  return ev_realloc (base, elem * *cur);
596
649
  }
597
650
 
651
+ #define array_init_zero(base,count) \
652
+ memset ((void *)(base), 0, sizeof (*(base)) * (count))
653
+
598
654
  #define array_needsize(type,base,cur,cnt,init) \
599
655
  if (expect_false ((cnt) > (cur))) \
600
656
  { \
@@ -647,19 +703,6 @@ queue_events (EV_P_ W *events, int eventcnt, int type)
647
703
 
648
704
  /*****************************************************************************/
649
705
 
650
- void inline_size
651
- anfds_init (ANFD *base, int count)
652
- {
653
- while (count--)
654
- {
655
- base->head = 0;
656
- base->events = EV_NONE;
657
- base->reify = 0;
658
-
659
- ++base;
660
- }
661
- }
662
-
663
706
  void inline_speed
664
707
  fd_event (EV_P_ int fd, int revents)
665
708
  {
@@ -701,13 +744,13 @@ fd_reify (EV_P)
701
744
  #if EV_SELECT_IS_WINSOCKET
702
745
  if (events)
703
746
  {
704
- unsigned long argp;
747
+ unsigned long arg;
705
748
  #ifdef EV_FD_TO_WIN32_HANDLE
706
749
  anfd->handle = EV_FD_TO_WIN32_HANDLE (fd);
707
750
  #else
708
751
  anfd->handle = _get_osfhandle (fd);
709
752
  #endif
710
- assert (("libev only supports socket fds in this configuration", ioctlsocket (anfd->handle, FIONREAD, &argp) == 0));
753
+ assert (("libev: only socket fds supported in this configuration", ioctlsocket (anfd->handle, FIONREAD, &arg) == 0));
711
754
  }
712
755
  #endif
713
756
 
@@ -770,7 +813,7 @@ fd_ebadf (EV_P)
770
813
 
771
814
  for (fd = 0; fd < anfdmax; ++fd)
772
815
  if (anfds [fd].events)
773
- if (!fd_valid (fd) == -1 && errno == EBADF)
816
+ if (!fd_valid (fd) && errno == EBADF)
774
817
  fd_kill (EV_A_ fd);
775
818
  }
776
819
 
@@ -798,6 +841,7 @@ fd_rearm_all (EV_P)
798
841
  if (anfds [fd].events)
799
842
  {
800
843
  anfds [fd].events = 0;
844
+ anfds [fd].emask = 0;
801
845
  fd_change (EV_A_ fd, EV_IOFDSET | 1);
802
846
  }
803
847
  }
@@ -959,25 +1003,13 @@ static int signalmax;
959
1003
 
960
1004
  static EV_ATOMIC_T gotsig;
961
1005
 
962
- void inline_size
963
- signals_init (ANSIG *base, int count)
964
- {
965
- while (count--)
966
- {
967
- base->head = 0;
968
- base->gotsig = 0;
969
-
970
- ++base;
971
- }
972
- }
973
-
974
1006
  /*****************************************************************************/
975
1007
 
976
1008
  void inline_speed
977
1009
  fd_intern (int fd)
978
1010
  {
979
1011
  #ifdef _WIN32
980
- int arg = 1;
1012
+ unsigned long arg = 1;
981
1013
  ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg);
982
1014
  #else
983
1015
  fcntl (fd, F_SETFD, FD_CLOEXEC);
@@ -1001,7 +1033,7 @@ evpipe_init (EV_P)
1001
1033
  #endif
1002
1034
  {
1003
1035
  while (pipe (evpipe))
1004
- syserr ("(libev) error creating signal/async pipe");
1036
+ ev_syserr ("(libev) error creating signal/async pipe");
1005
1037
 
1006
1038
  fd_intern (evpipe [0]);
1007
1039
  fd_intern (evpipe [1]);
@@ -1101,7 +1133,7 @@ ev_feed_signal_event (EV_P_ int signum)
1101
1133
  WL w;
1102
1134
 
1103
1135
  #if EV_MULTIPLICITY
1104
- assert (("feeding signal events is only supported in the default loop", loop == ev_default_loop_ptr));
1136
+ assert (("libev: feeding signal events is only supported in the default loop", loop == ev_default_loop_ptr));
1105
1137
  #endif
1106
1138
 
1107
1139
  --signum;
@@ -1240,8 +1272,9 @@ ev_recommended_backends (void)
1240
1272
  flags &= ~EVBACKEND_KQUEUE;
1241
1273
  #endif
1242
1274
  #ifdef __APPLE__
1243
- // flags &= ~EVBACKEND_KQUEUE; for documentation
1244
- flags &= ~EVBACKEND_POLL;
1275
+ /* only select works correctly on that "unix-certified" platform */
1276
+ flags &= ~EVBACKEND_KQUEUE; /* horribly broken, even for sockets */
1277
+ flags &= ~EVBACKEND_POLL; /* poll is based on kqueue from 10.5 onwards */
1245
1278
  #endif
1246
1279
 
1247
1280
  return flags;
@@ -1501,13 +1534,13 @@ ev_loop_fork (EV_P)
1501
1534
  }
1502
1535
 
1503
1536
  #if EV_VERIFY
1504
- void noinline
1537
+ static void noinline
1505
1538
  verify_watcher (EV_P_ W w)
1506
1539
  {
1507
- assert (("watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI));
1540
+ assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI));
1508
1541
 
1509
1542
  if (w->pending)
1510
- assert (("pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w));
1543
+ assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w));
1511
1544
  }
1512
1545
 
1513
1546
  static void noinline
@@ -1517,9 +1550,9 @@ verify_heap (EV_P_ ANHE *heap, int N)
1517
1550
 
1518
1551
  for (i = HEAP0; i < N + HEAP0; ++i)
1519
1552
  {
1520
- assert (("active index mismatch in heap", ev_active (ANHE_w (heap [i])) == i));
1521
- assert (("heap condition violated", i == HEAP0 || ANHE_at (heap [HPARENT (i)]) <= ANHE_at (heap [i])));
1522
- assert (("heap at cache mismatch", ANHE_at (heap [i]) == ev_at (ANHE_w (heap [i]))));
1553
+ assert (("libev: active index mismatch in heap", ev_active (ANHE_w (heap [i])) == i));
1554
+ assert (("libev: heap condition violated", i == HEAP0 || ANHE_at (heap [HPARENT (i)]) <= ANHE_at (heap [i])));
1555
+ assert (("libev: heap at cache mismatch", ANHE_at (heap [i]) == ev_at (ANHE_w (heap [i]))));
1523
1556
 
1524
1557
  verify_watcher (EV_A_ (W)ANHE_w (heap [i]));
1525
1558
  }
@@ -1530,7 +1563,7 @@ array_verify (EV_P_ W *ws, int cnt)
1530
1563
  {
1531
1564
  while (cnt--)
1532
1565
  {
1533
- assert (("active index mismatch", ev_active (ws [cnt]) == cnt + 1));
1566
+ assert (("libev: active index mismatch", ev_active (ws [cnt]) == cnt + 1));
1534
1567
  verify_watcher (EV_A_ ws [cnt]);
1535
1568
  }
1536
1569
  }
@@ -1547,15 +1580,15 @@ ev_loop_verify (EV_P)
1547
1580
 
1548
1581
  assert (fdchangemax >= fdchangecnt);
1549
1582
  for (i = 0; i < fdchangecnt; ++i)
1550
- assert (("negative fd in fdchanges", fdchanges [i] >= 0));
1583
+ assert (("libev: negative fd in fdchanges", fdchanges [i] >= 0));
1551
1584
 
1552
1585
  assert (anfdmax >= 0);
1553
1586
  for (i = 0; i < anfdmax; ++i)
1554
1587
  for (w = anfds [i].head; w; w = w->next)
1555
1588
  {
1556
1589
  verify_watcher (EV_A_ (W)w);
1557
- assert (("inactive fd watcher on anfd list", ev_active (w) == 1));
1558
- assert (("fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i));
1590
+ assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1));
1591
+ assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i));
1559
1592
  }
1560
1593
 
1561
1594
  assert (timermax >= timercnt);
@@ -1642,6 +1675,8 @@ ev_default_destroy (void)
1642
1675
  struct ev_loop *loop = ev_default_loop_ptr;
1643
1676
  #endif
1644
1677
 
1678
+ ev_default_loop_ptr = 0;
1679
+
1645
1680
  #ifndef _WIN32
1646
1681
  ev_ref (EV_A); /* child watcher */
1647
1682
  ev_signal_stop (EV_A_ &childev);
@@ -1657,8 +1692,7 @@ ev_default_fork (void)
1657
1692
  struct ev_loop *loop = ev_default_loop_ptr;
1658
1693
  #endif
1659
1694
 
1660
- if (backend)
1661
- postfork = 1; /* must be in line with ev_loop_fork */
1695
+ postfork = 1; /* must be in line with ev_loop_fork */
1662
1696
  }
1663
1697
 
1664
1698
  /*****************************************************************************/
@@ -1681,7 +1715,7 @@ call_pending (EV_P)
1681
1715
 
1682
1716
  if (expect_true (p->w))
1683
1717
  {
1684
- /*assert (("non-pending watcher on pending list", p->w->pending));*/
1718
+ /*assert (("libev: non-pending watcher on pending list", p->w->pending));*/
1685
1719
 
1686
1720
  p->w->pending = 0;
1687
1721
  EV_CB_INVOKE (p->w, p->events);
@@ -1722,7 +1756,7 @@ timers_reify (EV_P)
1722
1756
  {
1723
1757
  ev_timer *w = (ev_timer *)ANHE_w (timers [HEAP0]);
1724
1758
 
1725
- /*assert (("inactive timer on timer heap detected", ev_is_active (w)));*/
1759
+ /*assert (("libev: inactive timer on timer heap detected", ev_is_active (w)));*/
1726
1760
 
1727
1761
  /* first reschedule or stop timer */
1728
1762
  if (w->repeat)
@@ -1731,7 +1765,7 @@ timers_reify (EV_P)
1731
1765
  if (ev_at (w) < mn_now)
1732
1766
  ev_at (w) = mn_now;
1733
1767
 
1734
- assert (("negative ev_timer repeat value found while processing timers", w->repeat > 0.));
1768
+ assert (("libev: negative ev_timer repeat value found while processing timers", w->repeat > 0.));
1735
1769
 
1736
1770
  ANHE_at_cache (timers [HEAP0]);
1737
1771
  downheap (timers, timercnt, HEAP0);
@@ -1754,14 +1788,14 @@ periodics_reify (EV_P)
1754
1788
  {
1755
1789
  ev_periodic *w = (ev_periodic *)ANHE_w (periodics [HEAP0]);
1756
1790
 
1757
- /*assert (("inactive timer on periodic heap detected", ev_is_active (w)));*/
1791
+ /*assert (("libev: inactive timer on periodic heap detected", ev_is_active (w)));*/
1758
1792
 
1759
1793
  /* first reschedule or stop timer */
1760
1794
  if (w->reschedule_cb)
1761
1795
  {
1762
1796
  ev_at (w) = w->reschedule_cb (w, ev_rt_now);
1763
1797
 
1764
- assert (("ev_periodic reschedule callback returned time in the past", ev_at (w) >= ev_rt_now));
1798
+ assert (("libev: ev_periodic reschedule callback returned time in the past", ev_at (w) >= ev_rt_now));
1765
1799
 
1766
1800
  ANHE_at_cache (periodics [HEAP0]);
1767
1801
  downheap (periodics, periodiccnt, HEAP0);
@@ -1899,6 +1933,12 @@ ev_unref (EV_P)
1899
1933
  --activecnt;
1900
1934
  }
1901
1935
 
1936
+ void
1937
+ ev_now_update (EV_P)
1938
+ {
1939
+ time_update (EV_A_ 1e100);
1940
+ }
1941
+
1902
1942
  static int loop_done;
1903
1943
 
1904
1944
  void
@@ -2116,12 +2156,13 @@ ev_io_start (EV_P_ ev_io *w)
2116
2156
  if (expect_false (ev_is_active (w)))
2117
2157
  return;
2118
2158
 
2119
- assert (("ev_io_start called with negative fd", fd >= 0));
2159
+ assert (("libev: ev_io_start called with negative fd", fd >= 0));
2160
+ assert (("libev: ev_io start called with illegal event mask", !(w->events & ~(EV_IOFDSET | EV_READ | EV_WRITE))));
2120
2161
 
2121
2162
  EV_FREQUENT_CHECK;
2122
2163
 
2123
2164
  ev_start (EV_A_ (W)w, 1);
2124
- array_needsize (ANFD, anfds, anfdmax, fd + 1, anfds_init);
2165
+ array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero);
2125
2166
  wlist_add (&anfds[fd].head, (WL)w);
2126
2167
 
2127
2168
  fd_change (EV_A_ fd, w->events & EV_IOFDSET | 1);
@@ -2137,7 +2178,7 @@ ev_io_stop (EV_P_ ev_io *w)
2137
2178
  if (expect_false (!ev_is_active (w)))
2138
2179
  return;
2139
2180
 
2140
- assert (("ev_io_stop called with illegal fd (must stay constant after start!)", w->fd >= 0 && w->fd < anfdmax));
2181
+ assert (("libev: ev_io_stop called with illegal fd (must stay constant after start!)", w->fd >= 0 && w->fd < anfdmax));
2141
2182
 
2142
2183
  EV_FREQUENT_CHECK;
2143
2184
 
@@ -2157,7 +2198,7 @@ ev_timer_start (EV_P_ ev_timer *w)
2157
2198
 
2158
2199
  ev_at (w) += mn_now;
2159
2200
 
2160
- assert (("ev_timer_start called with negative timer repeat value", w->repeat >= 0.));
2201
+ assert (("libev: ev_timer_start called with negative timer repeat value", w->repeat >= 0.));
2161
2202
 
2162
2203
  EV_FREQUENT_CHECK;
2163
2204
 
@@ -2170,7 +2211,7 @@ ev_timer_start (EV_P_ ev_timer *w)
2170
2211
 
2171
2212
  EV_FREQUENT_CHECK;
2172
2213
 
2173
- /*assert (("internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/
2214
+ /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/
2174
2215
  }
2175
2216
 
2176
2217
  void noinline
@@ -2185,7 +2226,7 @@ ev_timer_stop (EV_P_ ev_timer *w)
2185
2226
  {
2186
2227
  int active = ev_active (w);
2187
2228
 
2188
- assert (("internal timer heap corruption", ANHE_w (timers [active]) == (WT)w));
2229
+ assert (("libev: internal timer heap corruption", ANHE_w (timers [active]) == (WT)w));
2189
2230
 
2190
2231
  --timercnt;
2191
2232
 
@@ -2239,7 +2280,7 @@ ev_periodic_start (EV_P_ ev_periodic *w)
2239
2280
  ev_at (w) = w->reschedule_cb (w, ev_rt_now);
2240
2281
  else if (w->interval)
2241
2282
  {
2242
- assert (("ev_periodic_start called with negative interval value", w->interval >= 0.));
2283
+ assert (("libev: ev_periodic_start called with negative interval value", w->interval >= 0.));
2243
2284
  /* this formula differs from the one in periodic_reify because we do not always round up */
2244
2285
  ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
2245
2286
  }
@@ -2257,7 +2298,7 @@ ev_periodic_start (EV_P_ ev_periodic *w)
2257
2298
 
2258
2299
  EV_FREQUENT_CHECK;
2259
2300
 
2260
- /*assert (("internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/
2301
+ /*assert (("libev: internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/
2261
2302
  }
2262
2303
 
2263
2304
  void noinline
@@ -2272,7 +2313,7 @@ ev_periodic_stop (EV_P_ ev_periodic *w)
2272
2313
  {
2273
2314
  int active = ev_active (w);
2274
2315
 
2275
- assert (("internal periodic heap corruption", ANHE_w (periodics [active]) == (WT)w));
2316
+ assert (("libev: internal periodic heap corruption", ANHE_w (periodics [active]) == (WT)w));
2276
2317
 
2277
2318
  --periodiccnt;
2278
2319
 
@@ -2305,12 +2346,12 @@ void noinline
2305
2346
  ev_signal_start (EV_P_ ev_signal *w)
2306
2347
  {
2307
2348
  #if EV_MULTIPLICITY
2308
- assert (("signal watchers are only supported in the default loop", loop == ev_default_loop_ptr));
2349
+ assert (("libev: signal watchers are only supported in the default loop", loop == ev_default_loop_ptr));
2309
2350
  #endif
2310
2351
  if (expect_false (ev_is_active (w)))
2311
2352
  return;
2312
2353
 
2313
- assert (("ev_signal_start called with illegal signal number", w->signum > 0));
2354
+ assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0));
2314
2355
 
2315
2356
  evpipe_init (EV_A);
2316
2357
 
@@ -2323,7 +2364,7 @@ ev_signal_start (EV_P_ ev_signal *w)
2323
2364
  sigprocmask (SIG_SETMASK, &full, &prev);
2324
2365
  #endif
2325
2366
 
2326
- array_needsize (ANSIG, signals, signalmax, w->signum, signals_init);
2367
+ array_needsize (ANSIG, signals, signalmax, w->signum, array_init_zero);
2327
2368
 
2328
2369
  #ifndef _WIN32
2329
2370
  sigprocmask (SIG_SETMASK, &prev, 0);
@@ -2371,7 +2412,7 @@ void
2371
2412
  ev_child_start (EV_P_ ev_child *w)
2372
2413
  {
2373
2414
  #if EV_MULTIPLICITY
2374
- assert (("child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
2415
+ assert (("libev: child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
2375
2416
  #endif
2376
2417
  if (expect_false (ev_is_active (w)))
2377
2418
  return;
@@ -2406,8 +2447,9 @@ ev_child_stop (EV_P_ ev_child *w)
2406
2447
  # define lstat(a,b) _stati64 (a,b)
2407
2448
  # endif
2408
2449
 
2409
- #define DEF_STAT_INTERVAL 5.0074891
2410
- #define MIN_STAT_INTERVAL 0.1074891
2450
+ #define DEF_STAT_INTERVAL 5.0074891
2451
+ #define NFS_STAT_INTERVAL 30.1074891 /* for filesystems potentially failing inotify */
2452
+ #define MIN_STAT_INTERVAL 0.1074891
2411
2453
 
2412
2454
  static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents);
2413
2455
 
@@ -2421,10 +2463,11 @@ infy_add (EV_P_ ev_stat *w)
2421
2463
 
2422
2464
  if (w->wd < 0)
2423
2465
  {
2424
- ev_timer_start (EV_A_ &w->timer); /* this is not race-free, so we still need to recheck periodically */
2466
+ w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL;
2467
+ ev_timer_again (EV_A_ &w->timer); /* this is not race-free, so we still need to recheck periodically */
2425
2468
 
2426
2469
  /* monitor some parent directory for speedup hints */
2427
- /* note that exceeding the hardcoded limit is not a correctness issue, */
2470
+ /* note that exceeding the hardcoded path limit is not a correctness issue, */
2428
2471
  /* but an efficiency issue only */
2429
2472
  if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096)
2430
2473
  {
@@ -2438,8 +2481,8 @@ infy_add (EV_P_ ev_stat *w)
2438
2481
 
2439
2482
  char *pend = strrchr (path, '/');
2440
2483
 
2441
- if (!pend)
2442
- break; /* whoops, no '/', complain to your admin */
2484
+ if (!pend || pend == path)
2485
+ break;
2443
2486
 
2444
2487
  *pend = 0;
2445
2488
  w->wd = inotify_add_watch (fs_fd, path, mask);
@@ -2447,11 +2490,28 @@ infy_add (EV_P_ ev_stat *w)
2447
2490
  while (w->wd < 0 && (errno == ENOENT || errno == EACCES));
2448
2491
  }
2449
2492
  }
2450
- else
2451
- ev_timer_stop (EV_A_ &w->timer); /* we can watch this in a race-free way */
2452
2493
 
2453
2494
  if (w->wd >= 0)
2454
- wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w);
2495
+ {
2496
+ wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w);
2497
+
2498
+ /* now local changes will be tracked by inotify, but remote changes won't */
2499
+ /* unless the filesystem it known to be local, we therefore still poll */
2500
+ /* also do poll on <2.6.25, but with normal frequency */
2501
+ struct statfs sfs;
2502
+
2503
+ if (fs_2625 && !statfs (w->path, &sfs))
2504
+ if (sfs.f_type == 0x1373 /* devfs */
2505
+ || sfs.f_type == 0xEF53 /* ext2/3 */
2506
+ || sfs.f_type == 0x3153464a /* jfs */
2507
+ || sfs.f_type == 0x52654973 /* reiser3 */
2508
+ || sfs.f_type == 0x01021994 /* tempfs */
2509
+ || sfs.f_type == 0x58465342 /* xfs */)
2510
+ return;
2511
+
2512
+ w->timer.repeat = w->interval ? w->interval : fs_2625 ? NFS_STAT_INTERVAL : DEF_STAT_INTERVAL;
2513
+ ev_timer_again (EV_A_ &w->timer);
2514
+ }
2455
2515
  }
2456
2516
 
2457
2517
  static void noinline
@@ -2475,7 +2535,7 @@ static void noinline
2475
2535
  infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev)
2476
2536
  {
2477
2537
  if (slot < 0)
2478
- /* overflow, need to check for all hahs slots */
2538
+ /* overflow, need to check for all hash slots */
2479
2539
  for (slot = 0; slot < EV_INOTIFY_HASHSIZE; ++slot)
2480
2540
  infy_wd (EV_A_ slot, wd, ev);
2481
2541
  else
@@ -2491,6 +2551,7 @@ infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev)
2491
2551
  {
2492
2552
  if (ev->mask & (IN_IGNORED | IN_UNMOUNT | IN_DELETE_SELF))
2493
2553
  {
2554
+ wlist_del (&fs_hash [slot & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w);
2494
2555
  w->wd = -1;
2495
2556
  infy_add (EV_A_ w); /* re-add, no matter what */
2496
2557
  }
@@ -2513,12 +2574,39 @@ infy_cb (EV_P_ ev_io *w, int revents)
2513
2574
  infy_wd (EV_A_ ev->wd, ev->wd, ev);
2514
2575
  }
2515
2576
 
2577
+ void inline_size
2578
+ check_2625 (EV_P)
2579
+ {
2580
+ /* kernels < 2.6.25 are borked
2581
+ * http://www.ussg.indiana.edu/hypermail/linux/kernel/0711.3/1208.html
2582
+ */
2583
+ struct utsname buf;
2584
+ int major, minor, micro;
2585
+
2586
+ if (uname (&buf))
2587
+ return;
2588
+
2589
+ if (sscanf (buf.release, "%d.%d.%d", &major, &minor, &micro) != 3)
2590
+ return;
2591
+
2592
+ if (major < 2
2593
+ || (major == 2 && minor < 6)
2594
+ || (major == 2 && minor == 6 && micro < 25))
2595
+ return;
2596
+
2597
+ fs_2625 = 1;
2598
+ }
2599
+
2516
2600
  void inline_size
2517
2601
  infy_init (EV_P)
2518
2602
  {
2519
2603
  if (fs_fd != -2)
2520
2604
  return;
2521
2605
 
2606
+ fs_fd = -1;
2607
+
2608
+ check_2625 (EV_A);
2609
+
2522
2610
  fs_fd = inotify_init ();
2523
2611
 
2524
2612
  if (fs_fd >= 0)
@@ -2555,14 +2643,19 @@ infy_fork (EV_P)
2555
2643
  if (fs_fd >= 0)
2556
2644
  infy_add (EV_A_ w); /* re-add, no matter what */
2557
2645
  else
2558
- ev_timer_start (EV_A_ &w->timer);
2646
+ ev_timer_again (EV_A_ &w->timer);
2559
2647
  }
2560
-
2561
2648
  }
2562
2649
  }
2563
2650
 
2564
2651
  #endif
2565
2652
 
2653
+ #ifdef _WIN32
2654
+ # define EV_LSTAT(p,b) _stati64 (p, b)
2655
+ #else
2656
+ # define EV_LSTAT(p,b) lstat (p, b)
2657
+ #endif
2658
+
2566
2659
  void
2567
2660
  ev_stat_stat (EV_P_ ev_stat *w)
2568
2661
  {
@@ -2597,9 +2690,12 @@ stat_timer_cb (EV_P_ ev_timer *w_, int revents)
2597
2690
  || w->prev.st_ctime != w->attr.st_ctime
2598
2691
  ) {
2599
2692
  #if EV_USE_INOTIFY
2600
- infy_del (EV_A_ w);
2601
- infy_add (EV_A_ w);
2602
- ev_stat_stat (EV_A_ w); /* avoid race... */
2693
+ if (fs_fd >= 0)
2694
+ {
2695
+ infy_del (EV_A_ w);
2696
+ infy_add (EV_A_ w);
2697
+ ev_stat_stat (EV_A_ w); /* avoid race... */
2698
+ }
2603
2699
  #endif
2604
2700
 
2605
2701
  ev_feed_event (EV_A_ w, EV_STAT);
@@ -2612,16 +2708,12 @@ ev_stat_start (EV_P_ ev_stat *w)
2612
2708
  if (expect_false (ev_is_active (w)))
2613
2709
  return;
2614
2710
 
2615
- /* since we use memcmp, we need to clear any padding data etc. */
2616
- memset (&w->prev, 0, sizeof (ev_statdata));
2617
- memset (&w->attr, 0, sizeof (ev_statdata));
2618
-
2619
2711
  ev_stat_stat (EV_A_ w);
2620
2712
 
2621
- if (w->interval < MIN_STAT_INTERVAL)
2622
- w->interval = w->interval ? MIN_STAT_INTERVAL : DEF_STAT_INTERVAL;
2713
+ if (w->interval < MIN_STAT_INTERVAL && w->interval)
2714
+ w->interval = MIN_STAT_INTERVAL;
2623
2715
 
2624
- ev_timer_init (&w->timer, stat_timer_cb, w->interval, w->interval);
2716
+ ev_timer_init (&w->timer, stat_timer_cb, 0., w->interval ? w->interval : DEF_STAT_INTERVAL);
2625
2717
  ev_set_priority (&w->timer, ev_priority (w));
2626
2718
 
2627
2719
  #if EV_USE_INOTIFY
@@ -2631,7 +2723,7 @@ ev_stat_start (EV_P_ ev_stat *w)
2631
2723
  infy_add (EV_A_ w);
2632
2724
  else
2633
2725
  #endif
2634
- ev_timer_start (EV_A_ &w->timer);
2726
+ ev_timer_again (EV_A_ &w->timer);
2635
2727
 
2636
2728
  ev_start (EV_A_ (W)w, 1);
2637
2729
 
@@ -2811,6 +2903,23 @@ embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents)
2811
2903
  }
2812
2904
  }
2813
2905
 
2906
+ static void
2907
+ embed_fork_cb (EV_P_ ev_fork *fork_w, int revents)
2908
+ {
2909
+ ev_embed *w = (ev_embed *)(((char *)fork_w) - offsetof (ev_embed, fork));
2910
+
2911
+ ev_embed_stop (EV_A_ w);
2912
+
2913
+ {
2914
+ struct ev_loop *loop = w->other;
2915
+
2916
+ ev_loop_fork (EV_A);
2917
+ ev_loop (EV_A_ EVLOOP_NONBLOCK);
2918
+ }
2919
+
2920
+ ev_embed_start (EV_A_ w);
2921
+ }
2922
+
2814
2923
  #if 0
2815
2924
  static void
2816
2925
  embed_idle_cb (EV_P_ ev_idle *idle, int revents)
@@ -2827,7 +2936,7 @@ ev_embed_start (EV_P_ ev_embed *w)
2827
2936
 
2828
2937
  {
2829
2938
  struct ev_loop *loop = w->other;
2830
- assert (("loop to be embedded is not embeddable", backend & ev_embeddable_backends ()));
2939
+ assert (("libev: loop to be embedded is not embeddable", backend & ev_embeddable_backends ()));
2831
2940
  ev_io_init (&w->io, embed_io_cb, backend_fd, EV_READ);
2832
2941
  }
2833
2942
 
@@ -2840,6 +2949,9 @@ ev_embed_start (EV_P_ ev_embed *w)
2840
2949
  ev_set_priority (&w->prepare, EV_MINPRI);
2841
2950
  ev_prepare_start (EV_A_ &w->prepare);
2842
2951
 
2952
+ ev_fork_init (&w->fork, embed_fork_cb);
2953
+ ev_fork_start (EV_A_ &w->fork);
2954
+
2843
2955
  /*ev_idle_init (&w->idle, e,bed_idle_cb);*/
2844
2956
 
2845
2957
  ev_start (EV_A_ (W)w, 1);
@@ -2856,10 +2968,9 @@ ev_embed_stop (EV_P_ ev_embed *w)
2856
2968
 
2857
2969
  EV_FREQUENT_CHECK;
2858
2970
 
2859
- ev_io_stop (EV_A_ &w->io);
2971
+ ev_io_stop (EV_A_ &w->io);
2860
2972
  ev_prepare_stop (EV_A_ &w->prepare);
2861
-
2862
- ev_stop (EV_A_ (W)w);
2973
+ ev_fork_stop (EV_A_ &w->fork);
2863
2974
 
2864
2975
  EV_FREQUENT_CHECK;
2865
2976
  }
@@ -2966,7 +3077,7 @@ once_cb (EV_P_ struct ev_once *once, int revents)
2966
3077
  void (*cb)(int revents, void *arg) = once->cb;
2967
3078
  void *arg = once->arg;
2968
3079
 
2969
- ev_io_stop (EV_A_ &once->io);
3080
+ ev_io_stop (EV_A_ &once->io);
2970
3081
  ev_timer_stop (EV_A_ &once->to);
2971
3082
  ev_free (once);
2972
3083
 
@@ -2976,13 +3087,17 @@ once_cb (EV_P_ struct ev_once *once, int revents)
2976
3087
  static void
2977
3088
  once_cb_io (EV_P_ ev_io *w, int revents)
2978
3089
  {
2979
- once_cb (EV_A_ (struct ev_once *)(((char *)w) - offsetof (struct ev_once, io)), revents);
3090
+ struct ev_once *once = (struct ev_once *)(((char *)w) - offsetof (struct ev_once, io));
3091
+
3092
+ once_cb (EV_A_ once, revents | ev_clear_pending (EV_A_ &once->to));
2980
3093
  }
2981
3094
 
2982
3095
  static void
2983
3096
  once_cb_to (EV_P_ ev_timer *w, int revents)
2984
3097
  {
2985
- once_cb (EV_A_ (struct ev_once *)(((char *)w) - offsetof (struct ev_once, to)), revents);
3098
+ struct ev_once *once = (struct ev_once *)(((char *)w) - offsetof (struct ev_once, to));
3099
+
3100
+ once_cb (EV_A_ once, revents | ev_clear_pending (EV_A_ &once->io));
2986
3101
  }
2987
3102
 
2988
3103
  void