rev 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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