evdispatch 0.1.0

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 (97) hide show
  1. data/History.txt +3 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +96 -0
  4. data/README.txt +73 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +70 -0
  7. data/config/requirements.rb +15 -0
  8. data/ext/revdispatch/extconf.rb +31 -0
  9. data/ext/revdispatch/libevdispatch/Changelog +0 -0
  10. data/ext/revdispatch/libevdispatch/LICENSE +0 -0
  11. data/ext/revdispatch/libevdispatch/Makefile.am +10 -0
  12. data/ext/revdispatch/libevdispatch/Makefile.in +637 -0
  13. data/ext/revdispatch/libevdispatch/README +3 -0
  14. data/ext/revdispatch/libevdispatch/TODO +5 -0
  15. data/ext/revdispatch/libevdispatch/aclocal.m4 +7459 -0
  16. data/ext/revdispatch/libevdispatch/autogen.sh +11 -0
  17. data/ext/revdispatch/libevdispatch/confdefs.h +32 -0
  18. data/ext/revdispatch/libevdispatch/config.guess +1516 -0
  19. data/ext/revdispatch/libevdispatch/config.h.in +112 -0
  20. data/ext/revdispatch/libevdispatch/config.sub +1626 -0
  21. data/ext/revdispatch/libevdispatch/configure +21949 -0
  22. data/ext/revdispatch/libevdispatch/configure.ac +40 -0
  23. data/ext/revdispatch/libevdispatch/depcomp +584 -0
  24. data/ext/revdispatch/libevdispatch/install-sh +507 -0
  25. data/ext/revdispatch/libevdispatch/libev/Changes +54 -0
  26. data/ext/revdispatch/libevdispatch/libev/LICENSE +25 -0
  27. data/ext/revdispatch/libevdispatch/libev/Makefile.am +18 -0
  28. data/ext/revdispatch/libevdispatch/libev/Makefile.in +677 -0
  29. data/ext/revdispatch/libevdispatch/libev/README +130 -0
  30. data/ext/revdispatch/libevdispatch/libev/aclocal.m4 +7430 -0
  31. data/ext/revdispatch/libevdispatch/libev/autogen.sh +7 -0
  32. data/ext/revdispatch/libevdispatch/libev/config.guess +1516 -0
  33. data/ext/revdispatch/libevdispatch/libev/config.h.in +106 -0
  34. data/ext/revdispatch/libevdispatch/libev/config.sub +1626 -0
  35. data/ext/revdispatch/libevdispatch/libev/configure +21636 -0
  36. data/ext/revdispatch/libevdispatch/libev/configure.ac +18 -0
  37. data/ext/revdispatch/libevdispatch/libev/ev++.h +779 -0
  38. data/ext/revdispatch/libevdispatch/libev/ev.3 +3276 -0
  39. data/ext/revdispatch/libevdispatch/libev/ev.c +2547 -0
  40. data/ext/revdispatch/libevdispatch/libev/ev.h +608 -0
  41. data/ext/revdispatch/libevdispatch/libev/ev.pod +3192 -0
  42. data/ext/revdispatch/libevdispatch/libev/ev_epoll.c +182 -0
  43. data/ext/revdispatch/libevdispatch/libev/ev_kqueue.c +194 -0
  44. data/ext/revdispatch/libevdispatch/libev/ev_poll.c +135 -0
  45. data/ext/revdispatch/libevdispatch/libev/ev_port.c +163 -0
  46. data/ext/revdispatch/libevdispatch/libev/ev_select.c +244 -0
  47. data/ext/revdispatch/libevdispatch/libev/ev_vars.h +157 -0
  48. data/ext/revdispatch/libevdispatch/libev/ev_win32.c +125 -0
  49. data/ext/revdispatch/libevdispatch/libev/ev_wrap.h +144 -0
  50. data/ext/revdispatch/libevdispatch/libev/event.c +404 -0
  51. data/ext/revdispatch/libevdispatch/libev/event.h +152 -0
  52. data/ext/revdispatch/libevdispatch/libev/install-sh +294 -0
  53. data/ext/revdispatch/libevdispatch/libev/libev.m4 +28 -0
  54. data/ext/revdispatch/libevdispatch/libev/ltmain.sh +6930 -0
  55. data/ext/revdispatch/libevdispatch/libev/missing +336 -0
  56. data/ext/revdispatch/libevdispatch/libev/mkinstalldirs +111 -0
  57. data/ext/revdispatch/libevdispatch/ltmain.sh +6930 -0
  58. data/ext/revdispatch/libevdispatch/missing +367 -0
  59. data/ext/revdispatch/libevdispatch/src/Makefile.am +11 -0
  60. data/ext/revdispatch/libevdispatch/src/Makefile.in +486 -0
  61. data/ext/revdispatch/libevdispatch/src/ev_dispatch.cc +264 -0
  62. data/ext/revdispatch/libevdispatch/src/ev_dispatch.h +300 -0
  63. data/ext/revdispatch/libevdispatch/src/ev_http.cc +238 -0
  64. data/ext/revdispatch/libevdispatch/src/ev_http.h +65 -0
  65. data/ext/revdispatch/libevdispatch/test/Makefile.am +16 -0
  66. data/ext/revdispatch/libevdispatch/test/Makefile.in +513 -0
  67. data/ext/revdispatch/libevdispatch/test/helper.rb +94 -0
  68. data/ext/revdispatch/libevdispatch/test/key_test.cc +52 -0
  69. data/ext/revdispatch/libevdispatch/test/next_test.cc +86 -0
  70. data/ext/revdispatch/libevdispatch/test/next_test.rb +8 -0
  71. data/ext/revdispatch/libevdispatch/test/server.rb +9 -0
  72. data/ext/revdispatch/revdispatch.cc +151 -0
  73. data/ext/revdispatch/server.rb +60 -0
  74. data/ext/revdispatch/test.rb +100 -0
  75. data/lib/evdispatch/loop.rb +16 -0
  76. data/lib/evdispatch/version.rb +9 -0
  77. data/lib/evdispatch.rb +8 -0
  78. data/log/debug.log +0 -0
  79. data/script/console +10 -0
  80. data/script/destroy +14 -0
  81. data/script/generate +14 -0
  82. data/script/txt2html +74 -0
  83. data/setup.rb +1585 -0
  84. data/tasks/deployment.rake +34 -0
  85. data/tasks/environment.rake +7 -0
  86. data/tasks/extconf/revdispatch.rake +43 -0
  87. data/tasks/extconf.rake +13 -0
  88. data/tasks/website.rake +17 -0
  89. data/test/test_evdispatch.rb +11 -0
  90. data/test/test_helper.rb +3 -0
  91. data/test/test_revdispatch_extn.rb +14 -0
  92. data/website/index.html +128 -0
  93. data/website/index.txt +55 -0
  94. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  95. data/website/stylesheets/screen.css +138 -0
  96. data/website/template.html.erb +49 -0
  97. metadata +157 -0
@@ -0,0 +1,2547 @@
1
+ /*
2
+ * libev event processing core, watcher management
3
+ *
4
+ * Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without modifica-
8
+ * tion, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ * Alternatively, the contents of this file may be used under the terms of
29
+ * the GNU General Public License ("GPL") version 2 or any later version,
30
+ * in which case the provisions of the GPL are applicable instead of
31
+ * the above. If you wish to allow the use of your version of this file
32
+ * only under the terms of the GPL and not to allow others to use your
33
+ * version of this file under the BSD license, indicate your decision
34
+ * by deleting the provisions above and replace them with the notice
35
+ * and other provisions required by the GPL. If you do not delete the
36
+ * provisions above, a recipient may use your version of this file under
37
+ * either the BSD or the GPL.
38
+ */
39
+
40
+ #ifdef __cplusplus
41
+ extern "C" {
42
+ #endif
43
+
44
+ #ifndef EV_STANDALONE
45
+ # ifdef EV_CONFIG_H
46
+ # include EV_CONFIG_H
47
+ # else
48
+ # include "config.h"
49
+ # endif
50
+
51
+ # if HAVE_CLOCK_GETTIME
52
+ # ifndef EV_USE_MONOTONIC
53
+ # define EV_USE_MONOTONIC 1
54
+ # endif
55
+ # ifndef EV_USE_REALTIME
56
+ # define EV_USE_REALTIME 1
57
+ # endif
58
+ # else
59
+ # ifndef EV_USE_MONOTONIC
60
+ # define EV_USE_MONOTONIC 0
61
+ # endif
62
+ # ifndef EV_USE_REALTIME
63
+ # define EV_USE_REALTIME 0
64
+ # endif
65
+ # endif
66
+
67
+ # ifndef EV_USE_NANOSLEEP
68
+ # if HAVE_NANOSLEEP
69
+ # define EV_USE_NANOSLEEP 1
70
+ # else
71
+ # define EV_USE_NANOSLEEP 0
72
+ # endif
73
+ # endif
74
+
75
+ # ifndef EV_USE_SELECT
76
+ # if HAVE_SELECT && HAVE_SYS_SELECT_H
77
+ # define EV_USE_SELECT 1
78
+ # else
79
+ # define EV_USE_SELECT 0
80
+ # endif
81
+ # endif
82
+
83
+ # ifndef EV_USE_POLL
84
+ # if HAVE_POLL && HAVE_POLL_H
85
+ # define EV_USE_POLL 1
86
+ # else
87
+ # define EV_USE_POLL 0
88
+ # endif
89
+ # endif
90
+
91
+ # ifndef EV_USE_EPOLL
92
+ # if HAVE_EPOLL_CTL && HAVE_SYS_EPOLL_H
93
+ # define EV_USE_EPOLL 1
94
+ # else
95
+ # define EV_USE_EPOLL 0
96
+ # endif
97
+ # endif
98
+
99
+ # ifndef EV_USE_KQUEUE
100
+ # if HAVE_KQUEUE && HAVE_SYS_EVENT_H && HAVE_SYS_QUEUE_H
101
+ # define EV_USE_KQUEUE 1
102
+ # else
103
+ # define EV_USE_KQUEUE 0
104
+ # endif
105
+ # endif
106
+
107
+ # ifndef EV_USE_PORT
108
+ # if HAVE_PORT_H && HAVE_PORT_CREATE
109
+ # define EV_USE_PORT 1
110
+ # else
111
+ # define EV_USE_PORT 0
112
+ # endif
113
+ # endif
114
+
115
+ # ifndef EV_USE_INOTIFY
116
+ # if HAVE_INOTIFY_INIT && HAVE_SYS_INOTIFY_H
117
+ # define EV_USE_INOTIFY 1
118
+ # else
119
+ # define EV_USE_INOTIFY 0
120
+ # endif
121
+ # endif
122
+
123
+ #endif
124
+
125
+ #include <math.h>
126
+ #include <stdlib.h>
127
+ #include <fcntl.h>
128
+ #include <stddef.h>
129
+
130
+ #include <stdio.h>
131
+
132
+ #include <assert.h>
133
+ #include <errno.h>
134
+ #include <sys/types.h>
135
+ #include <time.h>
136
+
137
+ #include <signal.h>
138
+
139
+ #ifdef EV_H
140
+ # include EV_H
141
+ #else
142
+ # include "ev.h"
143
+ #endif
144
+
145
+ #ifndef _WIN32
146
+ # include <sys/time.h>
147
+ # include <sys/wait.h>
148
+ # include <unistd.h>
149
+ #else
150
+ # define WIN32_LEAN_AND_MEAN
151
+ # include <windows.h>
152
+ # ifndef EV_SELECT_IS_WINSOCKET
153
+ # define EV_SELECT_IS_WINSOCKET 1
154
+ # endif
155
+ #endif
156
+
157
+ /**/
158
+
159
+ #ifndef EV_USE_MONOTONIC
160
+ # define EV_USE_MONOTONIC 0
161
+ #endif
162
+
163
+ #ifndef EV_USE_REALTIME
164
+ # define EV_USE_REALTIME 0
165
+ #endif
166
+
167
+ #ifndef EV_USE_NANOSLEEP
168
+ # define EV_USE_NANOSLEEP 0
169
+ #endif
170
+
171
+ #ifndef EV_USE_SELECT
172
+ # define EV_USE_SELECT 1
173
+ #endif
174
+
175
+ #ifndef EV_USE_POLL
176
+ # ifdef _WIN32
177
+ # define EV_USE_POLL 0
178
+ # else
179
+ # define EV_USE_POLL 1
180
+ # endif
181
+ #endif
182
+
183
+ #ifndef EV_USE_EPOLL
184
+ # define EV_USE_EPOLL 0
185
+ #endif
186
+
187
+ #ifndef EV_USE_KQUEUE
188
+ # define EV_USE_KQUEUE 0
189
+ #endif
190
+
191
+ #ifndef EV_USE_PORT
192
+ # define EV_USE_PORT 0
193
+ #endif
194
+
195
+ #ifndef EV_USE_INOTIFY
196
+ # define EV_USE_INOTIFY 0
197
+ #endif
198
+
199
+ #ifndef EV_PID_HASHSIZE
200
+ # if EV_MINIMAL
201
+ # define EV_PID_HASHSIZE 1
202
+ # else
203
+ # define EV_PID_HASHSIZE 16
204
+ # endif
205
+ #endif
206
+
207
+ #ifndef EV_INOTIFY_HASHSIZE
208
+ # if EV_MINIMAL
209
+ # define EV_INOTIFY_HASHSIZE 1
210
+ # else
211
+ # define EV_INOTIFY_HASHSIZE 16
212
+ # endif
213
+ #endif
214
+
215
+ /**/
216
+
217
+ #ifndef CLOCK_MONOTONIC
218
+ # undef EV_USE_MONOTONIC
219
+ # define EV_USE_MONOTONIC 0
220
+ #endif
221
+
222
+ #ifndef CLOCK_REALTIME
223
+ # undef EV_USE_REALTIME
224
+ # define EV_USE_REALTIME 0
225
+ #endif
226
+
227
+ #if !EV_STAT_ENABLE
228
+ # undef EV_USE_INOTIFY
229
+ # define EV_USE_INOTIFY 0
230
+ #endif
231
+
232
+ #if !EV_USE_NANOSLEEP
233
+ # ifndef _WIN32
234
+ # include <sys/select.h>
235
+ # endif
236
+ #endif
237
+
238
+ #if EV_USE_INOTIFY
239
+ # include <sys/inotify.h>
240
+ #endif
241
+
242
+ #if EV_SELECT_IS_WINSOCKET
243
+ # include <winsock.h>
244
+ #endif
245
+
246
+ /**/
247
+
248
+ /*
249
+ * This is used to avoid floating point rounding problems.
250
+ * It is added to ev_rt_now when scheduling periodics
251
+ * to ensure progress, time-wise, even when rounding
252
+ * errors are against us.
253
+ * This value is good at least till the year 4000.
254
+ * Better solutions welcome.
255
+ */
256
+ #define TIME_EPSILON 0.0001220703125 /* 1/8192 */
257
+
258
+ #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
259
+ #define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */
260
+ /*#define CLEANUP_INTERVAL (MAX_BLOCKTIME * 5.) /* how often to try to free memory and re-check fds, TODO */
261
+
262
+ #if __GNUC__ >= 4
263
+ # define expect(expr,value) __builtin_expect ((expr),(value))
264
+ # define noinline __attribute__ ((noinline))
265
+ #else
266
+ # define expect(expr,value) (expr)
267
+ # define noinline
268
+ # if __STDC_VERSION__ < 199901L
269
+ # define inline
270
+ # endif
271
+ #endif
272
+
273
+ #define expect_false(expr) expect ((expr) != 0, 0)
274
+ #define expect_true(expr) expect ((expr) != 0, 1)
275
+ #define inline_size static inline
276
+
277
+ #if EV_MINIMAL
278
+ # define inline_speed static noinline
279
+ #else
280
+ # define inline_speed static inline
281
+ #endif
282
+
283
+ #define NUMPRI (EV_MAXPRI - EV_MINPRI + 1)
284
+ #define ABSPRI(w) (((W)w)->priority - EV_MINPRI)
285
+
286
+ #define EMPTY /* required for microsofts broken pseudo-c compiler */
287
+ #define EMPTY2(a,b) /* used to suppress some warnings */
288
+
289
+ typedef ev_watcher *W;
290
+ typedef ev_watcher_list *WL;
291
+ typedef ev_watcher_time *WT;
292
+
293
+ #if EV_USE_MONOTONIC
294
+ /* sig_atomic_t is used to avoid per-thread variables or locking but still */
295
+ /* giving it a reasonably high chance of working on typical architetcures */
296
+ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */
297
+ #endif
298
+
299
+ #ifdef _WIN32
300
+ # include "ev_win32.c"
301
+ #endif
302
+
303
+ /*****************************************************************************/
304
+
305
+ static void (*syserr_cb)(const char *msg);
306
+
307
+ void
308
+ ev_set_syserr_cb (void (*cb)(const char *msg))
309
+ {
310
+ syserr_cb = cb;
311
+ }
312
+
313
+ static void noinline
314
+ syserr (const char *msg)
315
+ {
316
+ if (!msg)
317
+ msg = "(libev) system error";
318
+
319
+ if (syserr_cb)
320
+ syserr_cb (msg);
321
+ else
322
+ {
323
+ perror (msg);
324
+ abort ();
325
+ }
326
+ }
327
+
328
+ static void *(*alloc)(void *ptr, long size);
329
+
330
+ void
331
+ ev_set_allocator (void *(*cb)(void *ptr, long size))
332
+ {
333
+ alloc = cb;
334
+ }
335
+
336
+ inline_speed void *
337
+ ev_realloc (void *ptr, long size)
338
+ {
339
+ ptr = alloc ? alloc (ptr, size) : realloc (ptr, size);
340
+
341
+ if (!ptr && size)
342
+ {
343
+ fprintf (stderr, "libev: cannot allocate %ld bytes, aborting.", size);
344
+ abort ();
345
+ }
346
+
347
+ return ptr;
348
+ }
349
+
350
+ #define ev_malloc(size) ev_realloc (0, (size))
351
+ #define ev_free(ptr) ev_realloc ((ptr), 0)
352
+
353
+ /*****************************************************************************/
354
+
355
+ typedef struct
356
+ {
357
+ WL head;
358
+ unsigned char events;
359
+ unsigned char reify;
360
+ #if EV_SELECT_IS_WINSOCKET
361
+ SOCKET handle;
362
+ #endif
363
+ } ANFD;
364
+
365
+ typedef struct
366
+ {
367
+ W w;
368
+ int events;
369
+ } ANPENDING;
370
+
371
+ #if EV_USE_INOTIFY
372
+ typedef struct
373
+ {
374
+ WL head;
375
+ } ANFS;
376
+ #endif
377
+
378
+ #if EV_MULTIPLICITY
379
+
380
+ struct ev_loop
381
+ {
382
+ ev_tstamp ev_rt_now;
383
+ #define ev_rt_now ((loop)->ev_rt_now)
384
+ #define VAR(name,decl) decl;
385
+ #include "ev_vars.h"
386
+ #undef VAR
387
+ };
388
+ #include "ev_wrap.h"
389
+
390
+ static struct ev_loop default_loop_struct;
391
+ struct ev_loop *ev_default_loop_ptr;
392
+
393
+ #else
394
+
395
+ ev_tstamp ev_rt_now;
396
+ #define VAR(name,decl) static decl;
397
+ #include "ev_vars.h"
398
+ #undef VAR
399
+
400
+ static int ev_default_loop_ptr;
401
+
402
+ #endif
403
+
404
+ /*****************************************************************************/
405
+
406
+ ev_tstamp
407
+ ev_time (void)
408
+ {
409
+ #if EV_USE_REALTIME
410
+ struct timespec ts;
411
+ clock_gettime (CLOCK_REALTIME, &ts);
412
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
413
+ #else
414
+ struct timeval tv;
415
+ gettimeofday (&tv, 0);
416
+ return tv.tv_sec + tv.tv_usec * 1e-6;
417
+ #endif
418
+ }
419
+
420
+ ev_tstamp inline_size
421
+ get_clock (void)
422
+ {
423
+ #if EV_USE_MONOTONIC
424
+ if (expect_true (have_monotonic))
425
+ {
426
+ struct timespec ts;
427
+ clock_gettime (CLOCK_MONOTONIC, &ts);
428
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
429
+ }
430
+ #endif
431
+
432
+ return ev_time ();
433
+ }
434
+
435
+ #if EV_MULTIPLICITY
436
+ ev_tstamp
437
+ ev_now (EV_P)
438
+ {
439
+ return ev_rt_now;
440
+ }
441
+ #endif
442
+
443
+ void
444
+ ev_sleep (ev_tstamp delay)
445
+ {
446
+ if (delay > 0.)
447
+ {
448
+ #if EV_USE_NANOSLEEP
449
+ struct timespec ts;
450
+
451
+ ts.tv_sec = (time_t)delay;
452
+ ts.tv_nsec = (long)((delay - (ev_tstamp)(ts.tv_sec)) * 1e9);
453
+
454
+ nanosleep (&ts, 0);
455
+ #elif defined(_WIN32)
456
+ Sleep ((unsigned long)(delay * 1e3));
457
+ #else
458
+ struct timeval tv;
459
+
460
+ tv.tv_sec = (time_t)delay;
461
+ tv.tv_usec = (long)((delay - (ev_tstamp)(tv.tv_sec)) * 1e6);
462
+
463
+ select (0, 0, 0, 0, &tv);
464
+ #endif
465
+ }
466
+ }
467
+
468
+ /*****************************************************************************/
469
+
470
+ int inline_size
471
+ array_nextsize (int elem, int cur, int cnt)
472
+ {
473
+ int ncur = cur + 1;
474
+
475
+ do
476
+ ncur <<= 1;
477
+ while (cnt > ncur);
478
+
479
+ /* if size > 4096, round to 4096 - 4 * longs to accomodate malloc overhead */
480
+ if (elem * ncur > 4096)
481
+ {
482
+ ncur *= elem;
483
+ ncur = (ncur + elem + 4095 + sizeof (void *) * 4) & ~4095;
484
+ ncur = ncur - sizeof (void *) * 4;
485
+ ncur /= elem;
486
+ }
487
+
488
+ return ncur;
489
+ }
490
+
491
+ static noinline void *
492
+ array_realloc (int elem, void *base, int *cur, int cnt)
493
+ {
494
+ *cur = array_nextsize (elem, *cur, cnt);
495
+ return ev_realloc (base, elem * *cur);
496
+ }
497
+
498
+ #define array_needsize(type,base,cur,cnt,init) \
499
+ if (expect_false ((cnt) > (cur))) \
500
+ { \
501
+ int ocur_ = (cur); \
502
+ (base) = (type *)array_realloc \
503
+ (sizeof (type), (base), &(cur), (cnt)); \
504
+ init ((base) + (ocur_), (cur) - ocur_); \
505
+ }
506
+
507
+ #if 0
508
+ #define array_slim(type,stem) \
509
+ if (stem ## max < array_roundsize (stem ## cnt >> 2)) \
510
+ { \
511
+ stem ## max = array_roundsize (stem ## cnt >> 1); \
512
+ base = (type *)ev_realloc (base, sizeof (type) * (stem ## max));\
513
+ fprintf (stderr, "slimmed down " # stem " to %d\n", stem ## max);/*D*/\
514
+ }
515
+ #endif
516
+
517
+ #define array_free(stem, idx) \
518
+ ev_free (stem ## s idx); stem ## cnt idx = stem ## max idx = 0;
519
+
520
+ /*****************************************************************************/
521
+
522
+ void noinline
523
+ ev_feed_event (EV_P_ void *w, int revents)
524
+ {
525
+ W w_ = (W)w;
526
+ int pri = ABSPRI (w_);
527
+
528
+ if (expect_false (w_->pending))
529
+ pendings [pri][w_->pending - 1].events |= revents;
530
+ else
531
+ {
532
+ w_->pending = ++pendingcnt [pri];
533
+ array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, EMPTY2);
534
+ pendings [pri][w_->pending - 1].w = w_;
535
+ pendings [pri][w_->pending - 1].events = revents;
536
+ }
537
+ }
538
+
539
+ void inline_speed
540
+ queue_events (EV_P_ W *events, int eventcnt, int type)
541
+ {
542
+ int i;
543
+
544
+ for (i = 0; i < eventcnt; ++i)
545
+ ev_feed_event (EV_A_ events [i], type);
546
+ }
547
+
548
+ /*****************************************************************************/
549
+
550
+ void inline_size
551
+ anfds_init (ANFD *base, int count)
552
+ {
553
+ while (count--)
554
+ {
555
+ base->head = 0;
556
+ base->events = EV_NONE;
557
+ base->reify = 0;
558
+
559
+ ++base;
560
+ }
561
+ }
562
+
563
+ void inline_speed
564
+ fd_event (EV_P_ int fd, int revents)
565
+ {
566
+ ANFD *anfd = anfds + fd;
567
+ ev_io *w;
568
+
569
+ for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next)
570
+ {
571
+ int ev = w->events & revents;
572
+
573
+ if (ev)
574
+ ev_feed_event (EV_A_ (W)w, ev);
575
+ }
576
+ }
577
+
578
+ void
579
+ ev_feed_fd_event (EV_P_ int fd, int revents)
580
+ {
581
+ if (fd >= 0 && fd < anfdmax)
582
+ fd_event (EV_A_ fd, revents);
583
+ }
584
+
585
+ void inline_size
586
+ fd_reify (EV_P)
587
+ {
588
+ int i;
589
+
590
+ for (i = 0; i < fdchangecnt; ++i)
591
+ {
592
+ int fd = fdchanges [i];
593
+ ANFD *anfd = anfds + fd;
594
+ ev_io *w;
595
+
596
+ unsigned char events = 0;
597
+
598
+ for (w = (ev_io *)anfd->head; w; w = (ev_io *)((WL)w)->next)
599
+ events |= (unsigned char)w->events;
600
+
601
+ #if EV_SELECT_IS_WINSOCKET
602
+ if (events)
603
+ {
604
+ unsigned long argp;
605
+ #ifdef EV_FD_TO_WIN32_HANDLE
606
+ anfd->handle = EV_FD_TO_WIN32_HANDLE (fd);
607
+ #else
608
+ anfd->handle = _get_osfhandle (fd);
609
+ #endif
610
+ assert (("libev only supports socket fds in this configuration", ioctlsocket (anfd->handle, FIONREAD, &argp) == 0));
611
+ }
612
+ #endif
613
+
614
+ {
615
+ unsigned char o_events = anfd->events;
616
+ unsigned char o_reify = anfd->reify;
617
+
618
+ anfd->reify = 0;
619
+ anfd->events = events;
620
+
621
+ if (o_events != events || o_reify & EV_IOFDSET)
622
+ backend_modify (EV_A_ fd, o_events, events);
623
+ }
624
+ }
625
+
626
+ fdchangecnt = 0;
627
+ }
628
+
629
+ void inline_size
630
+ fd_change (EV_P_ int fd, int flags)
631
+ {
632
+ unsigned char reify = anfds [fd].reify;
633
+ anfds [fd].reify |= flags;
634
+
635
+ if (expect_true (!reify))
636
+ {
637
+ ++fdchangecnt;
638
+ array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2);
639
+ fdchanges [fdchangecnt - 1] = fd;
640
+ }
641
+ }
642
+
643
+ void inline_speed
644
+ fd_kill (EV_P_ int fd)
645
+ {
646
+ ev_io *w;
647
+
648
+ while ((w = (ev_io *)anfds [fd].head))
649
+ {
650
+ ev_io_stop (EV_A_ w);
651
+ ev_feed_event (EV_A_ (W)w, EV_ERROR | EV_READ | EV_WRITE);
652
+ }
653
+ }
654
+
655
+ int inline_size
656
+ fd_valid (int fd)
657
+ {
658
+ #ifdef _WIN32
659
+ return _get_osfhandle (fd) != -1;
660
+ #else
661
+ return fcntl (fd, F_GETFD) != -1;
662
+ #endif
663
+ }
664
+
665
+ /* called on EBADF to verify fds */
666
+ static void noinline
667
+ fd_ebadf (EV_P)
668
+ {
669
+ int fd;
670
+
671
+ for (fd = 0; fd < anfdmax; ++fd)
672
+ if (anfds [fd].events)
673
+ if (!fd_valid (fd) == -1 && errno == EBADF)
674
+ fd_kill (EV_A_ fd);
675
+ }
676
+
677
+ /* called on ENOMEM in select/poll to kill some fds and retry */
678
+ static void noinline
679
+ fd_enomem (EV_P)
680
+ {
681
+ int fd;
682
+
683
+ for (fd = anfdmax; fd--; )
684
+ if (anfds [fd].events)
685
+ {
686
+ fd_kill (EV_A_ fd);
687
+ return;
688
+ }
689
+ }
690
+
691
+ /* usually called after fork if backend needs to re-arm all fds from scratch */
692
+ static void noinline
693
+ fd_rearm_all (EV_P)
694
+ {
695
+ int fd;
696
+
697
+ for (fd = 0; fd < anfdmax; ++fd)
698
+ if (anfds [fd].events)
699
+ {
700
+ anfds [fd].events = 0;
701
+ fd_change (EV_A_ fd, EV_IOFDSET | 1);
702
+ }
703
+ }
704
+
705
+ /*****************************************************************************/
706
+
707
+ void inline_speed
708
+ upheap (WT *heap, int k)
709
+ {
710
+ WT w = heap [k];
711
+
712
+ while (k)
713
+ {
714
+ int p = (k - 1) >> 1;
715
+
716
+ if (heap [p]->at <= w->at)
717
+ break;
718
+
719
+ heap [k] = heap [p];
720
+ ((W)heap [k])->active = k + 1;
721
+ k = p;
722
+ }
723
+
724
+ heap [k] = w;
725
+ ((W)heap [k])->active = k + 1;
726
+ }
727
+
728
+ void inline_speed
729
+ downheap (WT *heap, int N, int k)
730
+ {
731
+ WT w = heap [k];
732
+
733
+ for (;;)
734
+ {
735
+ int c = (k << 1) + 1;
736
+
737
+ if (c >= N)
738
+ break;
739
+
740
+ c += c + 1 < N && heap [c]->at > heap [c + 1]->at
741
+ ? 1 : 0;
742
+
743
+ if (w->at <= heap [c]->at)
744
+ break;
745
+
746
+ heap [k] = heap [c];
747
+ ((W)heap [k])->active = k + 1;
748
+
749
+ k = c;
750
+ }
751
+
752
+ heap [k] = w;
753
+ ((W)heap [k])->active = k + 1;
754
+ }
755
+
756
+ void inline_size
757
+ adjustheap (WT *heap, int N, int k)
758
+ {
759
+ upheap (heap, k);
760
+ downheap (heap, N, k);
761
+ }
762
+
763
+ /*****************************************************************************/
764
+
765
+ typedef struct
766
+ {
767
+ WL head;
768
+ EV_ATOMIC_T gotsig;
769
+ } ANSIG;
770
+
771
+ static ANSIG *signals;
772
+ static int signalmax;
773
+
774
+ static EV_ATOMIC_T gotsig;
775
+
776
+ void inline_size
777
+ signals_init (ANSIG *base, int count)
778
+ {
779
+ while (count--)
780
+ {
781
+ base->head = 0;
782
+ base->gotsig = 0;
783
+
784
+ ++base;
785
+ }
786
+ }
787
+
788
+ /*****************************************************************************/
789
+
790
+ void inline_speed
791
+ fd_intern (int fd)
792
+ {
793
+ #ifdef _WIN32
794
+ int arg = 1;
795
+ ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg);
796
+ #else
797
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
798
+ fcntl (fd, F_SETFL, O_NONBLOCK);
799
+ #endif
800
+ }
801
+
802
+ static void noinline
803
+ evpipe_init (EV_P)
804
+ {
805
+ if (!ev_is_active (&pipeev))
806
+ {
807
+ while (pipe (evpipe))
808
+ syserr ("(libev) error creating signal/async pipe");
809
+
810
+ fd_intern (evpipe [0]);
811
+ fd_intern (evpipe [1]);
812
+
813
+ ev_io_set (&pipeev, evpipe [0], EV_READ);
814
+ ev_io_start (EV_A_ &pipeev);
815
+ ev_unref (EV_A); /* watcher should not keep loop alive */
816
+ }
817
+ }
818
+
819
+ void inline_size
820
+ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
821
+ {
822
+ if (!*flag)
823
+ {
824
+ int old_errno = errno; /* save errno because write might clobber it */
825
+
826
+ *flag = 1;
827
+ write (evpipe [1], &old_errno, 1);
828
+
829
+ errno = old_errno;
830
+ }
831
+ }
832
+
833
+ static void
834
+ pipecb (EV_P_ ev_io *iow, int revents)
835
+ {
836
+ {
837
+ int dummy;
838
+ read (evpipe [0], &dummy, 1);
839
+ }
840
+
841
+ if (gotsig && ev_is_default_loop (EV_A))
842
+ {
843
+ int signum;
844
+ gotsig = 0;
845
+
846
+ for (signum = signalmax; signum--; )
847
+ if (signals [signum].gotsig)
848
+ ev_feed_signal_event (EV_A_ signum + 1);
849
+ }
850
+
851
+ #if EV_ASYNC_ENABLE
852
+ if (gotasync)
853
+ {
854
+ int i;
855
+ gotasync = 0;
856
+
857
+ for (i = asynccnt; i--; )
858
+ if (asyncs [i]->sent)
859
+ {
860
+ asyncs [i]->sent = 0;
861
+ ev_feed_event (EV_A_ asyncs [i], EV_ASYNC);
862
+ }
863
+ }
864
+ #endif
865
+ }
866
+
867
+ /*****************************************************************************/
868
+
869
+ static void
870
+ ev_sighandler (int signum)
871
+ {
872
+ #if EV_MULTIPLICITY
873
+ struct ev_loop *loop = &default_loop_struct;
874
+ #endif
875
+
876
+ #if _WIN32
877
+ signal (signum, ev_sighandler);
878
+ #endif
879
+
880
+ signals [signum - 1].gotsig = 1;
881
+ evpipe_write (EV_A_ &gotsig);
882
+ }
883
+
884
+ void noinline
885
+ ev_feed_signal_event (EV_P_ int signum)
886
+ {
887
+ WL w;
888
+
889
+ #if EV_MULTIPLICITY
890
+ assert (("feeding signal events is only supported in the default loop", loop == ev_default_loop_ptr));
891
+ #endif
892
+
893
+ --signum;
894
+
895
+ if (signum < 0 || signum >= signalmax)
896
+ return;
897
+
898
+ signals [signum].gotsig = 0;
899
+
900
+ for (w = signals [signum].head; w; w = w->next)
901
+ ev_feed_event (EV_A_ (W)w, EV_SIGNAL);
902
+ }
903
+
904
+ /*****************************************************************************/
905
+
906
+ static WL childs [EV_PID_HASHSIZE];
907
+
908
+ #ifndef _WIN32
909
+
910
+ static ev_signal childev;
911
+
912
+ #ifndef WIFCONTINUED
913
+ # define WIFCONTINUED(status) 0
914
+ #endif
915
+
916
+ void inline_speed
917
+ child_reap (EV_P_ int chain, int pid, int status)
918
+ {
919
+ ev_child *w;
920
+ int traced = WIFSTOPPED (status) || WIFCONTINUED (status);
921
+
922
+ for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next)
923
+ {
924
+ if ((w->pid == pid || !w->pid)
925
+ && (!traced || (w->flags & 1)))
926
+ {
927
+ ev_set_priority (w, EV_MAXPRI); /* need to do it *now*, this *must* be the same prio as the signal watcher itself */
928
+ w->rpid = pid;
929
+ w->rstatus = status;
930
+ ev_feed_event (EV_A_ (W)w, EV_CHILD);
931
+ }
932
+ }
933
+ }
934
+
935
+ #ifndef WCONTINUED
936
+ # define WCONTINUED 0
937
+ #endif
938
+
939
+ static void
940
+ childcb (EV_P_ ev_signal *sw, int revents)
941
+ {
942
+ int pid, status;
943
+
944
+ /* some systems define WCONTINUED but then fail to support it (linux 2.4) */
945
+ if (0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED | WCONTINUED)))
946
+ if (!WCONTINUED
947
+ || errno != EINVAL
948
+ || 0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED)))
949
+ return;
950
+
951
+ /* make sure we are called again until all children have been reaped */
952
+ /* we need to do it this way so that the callback gets called before we continue */
953
+ ev_feed_event (EV_A_ (W)sw, EV_SIGNAL);
954
+
955
+ child_reap (EV_A_ pid, pid, status);
956
+ if (EV_PID_HASHSIZE > 1)
957
+ child_reap (EV_A_ 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */
958
+ }
959
+
960
+ #endif
961
+
962
+ /*****************************************************************************/
963
+
964
+ #if EV_USE_PORT
965
+ # include "ev_port.c"
966
+ #endif
967
+ #if EV_USE_KQUEUE
968
+ # include "ev_kqueue.c"
969
+ #endif
970
+ #if EV_USE_EPOLL
971
+ # include "ev_epoll.c"
972
+ #endif
973
+ #if EV_USE_POLL
974
+ # include "ev_poll.c"
975
+ #endif
976
+ #if EV_USE_SELECT
977
+ # include "ev_select.c"
978
+ #endif
979
+
980
+ int
981
+ ev_version_major (void)
982
+ {
983
+ return EV_VERSION_MAJOR;
984
+ }
985
+
986
+ int
987
+ ev_version_minor (void)
988
+ {
989
+ return EV_VERSION_MINOR;
990
+ }
991
+
992
+ /* return true if we are running with elevated privileges and should ignore env variables */
993
+ int inline_size
994
+ enable_secure (void)
995
+ {
996
+ #ifdef _WIN32
997
+ return 0;
998
+ #else
999
+ return getuid () != geteuid ()
1000
+ || getgid () != getegid ();
1001
+ #endif
1002
+ }
1003
+
1004
+ unsigned int
1005
+ ev_supported_backends (void)
1006
+ {
1007
+ unsigned int flags = 0;
1008
+
1009
+ if (EV_USE_PORT ) flags |= EVBACKEND_PORT;
1010
+ if (EV_USE_KQUEUE) flags |= EVBACKEND_KQUEUE;
1011
+ if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL;
1012
+ if (EV_USE_POLL ) flags |= EVBACKEND_POLL;
1013
+ if (EV_USE_SELECT) flags |= EVBACKEND_SELECT;
1014
+
1015
+ return flags;
1016
+ }
1017
+
1018
+ unsigned int
1019
+ ev_recommended_backends (void)
1020
+ {
1021
+ unsigned int flags = ev_supported_backends ();
1022
+
1023
+ #ifndef __NetBSD__
1024
+ /* kqueue is borked on everything but netbsd apparently */
1025
+ /* it usually doesn't work correctly on anything but sockets and pipes */
1026
+ flags &= ~EVBACKEND_KQUEUE;
1027
+ #endif
1028
+ #ifdef __APPLE__
1029
+ // flags &= ~EVBACKEND_KQUEUE; for documentation
1030
+ flags &= ~EVBACKEND_POLL;
1031
+ #endif
1032
+
1033
+ return flags;
1034
+ }
1035
+
1036
+ unsigned int
1037
+ ev_embeddable_backends (void)
1038
+ {
1039
+ int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT;
1040
+
1041
+ /* epoll embeddability broken on all linux versions up to at least 2.6.23 */
1042
+ /* please fix it and tell me how to detect the fix */
1043
+ flags &= ~EVBACKEND_EPOLL;
1044
+
1045
+ return flags;
1046
+ }
1047
+
1048
+ unsigned int
1049
+ ev_backend (EV_P)
1050
+ {
1051
+ return backend;
1052
+ }
1053
+
1054
+ unsigned int
1055
+ ev_loop_count (EV_P)
1056
+ {
1057
+ return loop_count;
1058
+ }
1059
+
1060
+ void
1061
+ ev_set_io_collect_interval (EV_P_ ev_tstamp interval)
1062
+ {
1063
+ io_blocktime = interval;
1064
+ }
1065
+
1066
+ void
1067
+ ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval)
1068
+ {
1069
+ timeout_blocktime = interval;
1070
+ }
1071
+
1072
+ static void noinline
1073
+ loop_init (EV_P_ unsigned int flags)
1074
+ {
1075
+ if (!backend)
1076
+ {
1077
+ #if EV_USE_MONOTONIC
1078
+ {
1079
+ struct timespec ts;
1080
+ if (!clock_gettime (CLOCK_MONOTONIC, &ts))
1081
+ have_monotonic = 1;
1082
+ }
1083
+ #endif
1084
+
1085
+ ev_rt_now = ev_time ();
1086
+ mn_now = get_clock ();
1087
+ now_floor = mn_now;
1088
+ rtmn_diff = ev_rt_now - mn_now;
1089
+
1090
+ io_blocktime = 0.;
1091
+ timeout_blocktime = 0.;
1092
+ backend = 0;
1093
+ backend_fd = -1;
1094
+ gotasync = 0;
1095
+ #if EV_USE_INOTIFY
1096
+ fs_fd = -2;
1097
+ #endif
1098
+
1099
+ /* pid check not overridable via env */
1100
+ #ifndef _WIN32
1101
+ if (flags & EVFLAG_FORKCHECK)
1102
+ curpid = getpid ();
1103
+ #endif
1104
+
1105
+ if (!(flags & EVFLAG_NOENV)
1106
+ && !enable_secure ()
1107
+ && getenv ("LIBEV_FLAGS"))
1108
+ flags = atoi (getenv ("LIBEV_FLAGS"));
1109
+
1110
+ if (!(flags & 0x0000ffffUL))
1111
+ flags |= ev_recommended_backends ();
1112
+
1113
+ #if EV_USE_PORT
1114
+ if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
1115
+ #endif
1116
+ #if EV_USE_KQUEUE
1117
+ if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
1118
+ #endif
1119
+ #if EV_USE_EPOLL
1120
+ if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);
1121
+ #endif
1122
+ #if EV_USE_POLL
1123
+ if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
1124
+ #endif
1125
+ #if EV_USE_SELECT
1126
+ if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
1127
+ #endif
1128
+
1129
+ ev_init (&pipeev, pipecb);
1130
+ ev_set_priority (&pipeev, EV_MAXPRI);
1131
+ }
1132
+ }
1133
+
1134
+ static void noinline
1135
+ loop_destroy (EV_P)
1136
+ {
1137
+ int i;
1138
+
1139
+ if (ev_is_active (&pipeev))
1140
+ {
1141
+ ev_ref (EV_A); /* signal watcher */
1142
+ ev_io_stop (EV_A_ &pipeev);
1143
+
1144
+ close (evpipe [0]); evpipe [0] = 0;
1145
+ close (evpipe [1]); evpipe [1] = 0;
1146
+ }
1147
+
1148
+ #if EV_USE_INOTIFY
1149
+ if (fs_fd >= 0)
1150
+ close (fs_fd);
1151
+ #endif
1152
+
1153
+ if (backend_fd >= 0)
1154
+ close (backend_fd);
1155
+
1156
+ #if EV_USE_PORT
1157
+ if (backend == EVBACKEND_PORT ) port_destroy (EV_A);
1158
+ #endif
1159
+ #if EV_USE_KQUEUE
1160
+ if (backend == EVBACKEND_KQUEUE) kqueue_destroy (EV_A);
1161
+ #endif
1162
+ #if EV_USE_EPOLL
1163
+ if (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A);
1164
+ #endif
1165
+ #if EV_USE_POLL
1166
+ if (backend == EVBACKEND_POLL ) poll_destroy (EV_A);
1167
+ #endif
1168
+ #if EV_USE_SELECT
1169
+ if (backend == EVBACKEND_SELECT) select_destroy (EV_A);
1170
+ #endif
1171
+
1172
+ for (i = NUMPRI; i--; )
1173
+ {
1174
+ array_free (pending, [i]);
1175
+ #if EV_IDLE_ENABLE
1176
+ array_free (idle, [i]);
1177
+ #endif
1178
+ }
1179
+
1180
+ ev_free (anfds); anfdmax = 0;
1181
+
1182
+ /* have to use the microsoft-never-gets-it-right macro */
1183
+ array_free (fdchange, EMPTY);
1184
+ array_free (timer, EMPTY);
1185
+ #if EV_PERIODIC_ENABLE
1186
+ array_free (periodic, EMPTY);
1187
+ #endif
1188
+ #if EV_FORK_ENABLE
1189
+ array_free (fork, EMPTY);
1190
+ #endif
1191
+ array_free (prepare, EMPTY);
1192
+ array_free (check, EMPTY);
1193
+ #if EV_ASYNC_ENABLE
1194
+ array_free (async, EMPTY);
1195
+ #endif
1196
+
1197
+ backend = 0;
1198
+ }
1199
+
1200
+ void inline_size infy_fork (EV_P);
1201
+
1202
+ void inline_size
1203
+ loop_fork (EV_P)
1204
+ {
1205
+ #if EV_USE_PORT
1206
+ if (backend == EVBACKEND_PORT ) port_fork (EV_A);
1207
+ #endif
1208
+ #if EV_USE_KQUEUE
1209
+ if (backend == EVBACKEND_KQUEUE) kqueue_fork (EV_A);
1210
+ #endif
1211
+ #if EV_USE_EPOLL
1212
+ if (backend == EVBACKEND_EPOLL ) epoll_fork (EV_A);
1213
+ #endif
1214
+ #if EV_USE_INOTIFY
1215
+ infy_fork (EV_A);
1216
+ #endif
1217
+
1218
+ if (ev_is_active (&pipeev))
1219
+ {
1220
+ /* this "locks" the handlers against writing to the pipe */
1221
+ /* while we modify the fd vars */
1222
+ gotsig = 1;
1223
+ #if EV_ASYNC_ENABLE
1224
+ gotasync = 1;
1225
+ #endif
1226
+
1227
+ ev_ref (EV_A);
1228
+ ev_io_stop (EV_A_ &pipeev);
1229
+ close (evpipe [0]);
1230
+ close (evpipe [1]);
1231
+
1232
+ evpipe_init (EV_A);
1233
+ /* now iterate over everything, in case we missed something */
1234
+ pipecb (EV_A_ &pipeev, EV_READ);
1235
+ }
1236
+
1237
+ postfork = 0;
1238
+ }
1239
+
1240
+ #if EV_MULTIPLICITY
1241
+ struct ev_loop *
1242
+ ev_loop_new (unsigned int flags)
1243
+ {
1244
+ struct ev_loop *loop = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
1245
+
1246
+ memset (loop, 0, sizeof (struct ev_loop));
1247
+
1248
+ loop_init (EV_A_ flags);
1249
+
1250
+ if (ev_backend (EV_A))
1251
+ return loop;
1252
+
1253
+ return 0;
1254
+ }
1255
+
1256
+ void
1257
+ ev_loop_destroy (EV_P)
1258
+ {
1259
+ loop_destroy (EV_A);
1260
+ ev_free (loop);
1261
+ }
1262
+
1263
+ void
1264
+ ev_loop_fork (EV_P)
1265
+ {
1266
+ postfork = 1; /* must be in line with ev_default_fork */
1267
+ }
1268
+
1269
+ #endif
1270
+
1271
+ #if EV_MULTIPLICITY
1272
+ struct ev_loop *
1273
+ ev_default_loop_init (unsigned int flags)
1274
+ #else
1275
+ int
1276
+ ev_default_loop (unsigned int flags)
1277
+ #endif
1278
+ {
1279
+ if (!ev_default_loop_ptr)
1280
+ {
1281
+ #if EV_MULTIPLICITY
1282
+ struct ev_loop *loop = ev_default_loop_ptr = &default_loop_struct;
1283
+ #else
1284
+ ev_default_loop_ptr = 1;
1285
+ #endif
1286
+
1287
+ loop_init (EV_A_ flags);
1288
+
1289
+ if (ev_backend (EV_A))
1290
+ {
1291
+ #ifndef _WIN32
1292
+ ev_signal_init (&childev, childcb, SIGCHLD);
1293
+ ev_set_priority (&childev, EV_MAXPRI);
1294
+ ev_signal_start (EV_A_ &childev);
1295
+ ev_unref (EV_A); /* child watcher should not keep loop alive */
1296
+ #endif
1297
+ }
1298
+ else
1299
+ ev_default_loop_ptr = 0;
1300
+ }
1301
+
1302
+ return ev_default_loop_ptr;
1303
+ }
1304
+
1305
+ void
1306
+ ev_default_destroy (void)
1307
+ {
1308
+ #if EV_MULTIPLICITY
1309
+ struct ev_loop *loop = ev_default_loop_ptr;
1310
+ #endif
1311
+
1312
+ #ifndef _WIN32
1313
+ ev_ref (EV_A); /* child watcher */
1314
+ ev_signal_stop (EV_A_ &childev);
1315
+ #endif
1316
+
1317
+ loop_destroy (EV_A);
1318
+ }
1319
+
1320
+ void
1321
+ ev_default_fork (void)
1322
+ {
1323
+ #if EV_MULTIPLICITY
1324
+ struct ev_loop *loop = ev_default_loop_ptr;
1325
+ #endif
1326
+
1327
+ if (backend)
1328
+ postfork = 1; /* must be in line with ev_loop_fork */
1329
+ }
1330
+
1331
+ /*****************************************************************************/
1332
+
1333
+ void
1334
+ ev_invoke (EV_P_ void *w, int revents)
1335
+ {
1336
+ EV_CB_INVOKE ((W)w, revents);
1337
+ }
1338
+
1339
+ void inline_speed
1340
+ call_pending (EV_P)
1341
+ {
1342
+ int pri;
1343
+
1344
+ for (pri = NUMPRI; pri--; )
1345
+ while (pendingcnt [pri])
1346
+ {
1347
+ ANPENDING *p = pendings [pri] + --pendingcnt [pri];
1348
+
1349
+ if (expect_true (p->w))
1350
+ {
1351
+ /*assert (("non-pending watcher on pending list", p->w->pending));*/
1352
+
1353
+ p->w->pending = 0;
1354
+ EV_CB_INVOKE (p->w, p->events);
1355
+ }
1356
+ }
1357
+ }
1358
+
1359
+ void inline_size
1360
+ timers_reify (EV_P)
1361
+ {
1362
+ while (timercnt && ((WT)timers [0])->at <= mn_now)
1363
+ {
1364
+ ev_timer *w = (ev_timer *)timers [0];
1365
+
1366
+ /*assert (("inactive timer on timer heap detected", ev_is_active (w)));*/
1367
+
1368
+ /* first reschedule or stop timer */
1369
+ if (w->repeat)
1370
+ {
1371
+ assert (("negative ev_timer repeat value found while processing timers", w->repeat > 0.));
1372
+
1373
+ ((WT)w)->at += w->repeat;
1374
+ if (((WT)w)->at < mn_now)
1375
+ ((WT)w)->at = mn_now;
1376
+
1377
+ downheap (timers, timercnt, 0);
1378
+ }
1379
+ else
1380
+ ev_timer_stop (EV_A_ w); /* nonrepeating: stop timer */
1381
+
1382
+ ev_feed_event (EV_A_ (W)w, EV_TIMEOUT);
1383
+ }
1384
+ }
1385
+
1386
+ #if EV_PERIODIC_ENABLE
1387
+ void inline_size
1388
+ periodics_reify (EV_P)
1389
+ {
1390
+ while (periodiccnt && ((WT)periodics [0])->at <= ev_rt_now)
1391
+ {
1392
+ ev_periodic *w = (ev_periodic *)periodics [0];
1393
+
1394
+ /*assert (("inactive timer on periodic heap detected", ev_is_active (w)));*/
1395
+
1396
+ /* first reschedule or stop timer */
1397
+ if (w->reschedule_cb)
1398
+ {
1399
+ ((WT)w)->at = w->reschedule_cb (w, ev_rt_now + TIME_EPSILON);
1400
+ assert (("ev_periodic reschedule callback returned time in the past", ((WT)w)->at > ev_rt_now));
1401
+ downheap (periodics, periodiccnt, 0);
1402
+ }
1403
+ else if (w->interval)
1404
+ {
1405
+ ((WT)w)->at = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
1406
+ if (((WT)w)->at - ev_rt_now <= TIME_EPSILON) ((WT)w)->at += w->interval;
1407
+ assert (("ev_periodic timeout in the past detected while processing timers, negative interval?", ((WT)w)->at > ev_rt_now));
1408
+ downheap (periodics, periodiccnt, 0);
1409
+ }
1410
+ else
1411
+ ev_periodic_stop (EV_A_ w); /* nonrepeating: stop timer */
1412
+
1413
+ ev_feed_event (EV_A_ (W)w, EV_PERIODIC);
1414
+ }
1415
+ }
1416
+
1417
+ static void noinline
1418
+ periodics_reschedule (EV_P)
1419
+ {
1420
+ int i;
1421
+
1422
+ /* adjust periodics after time jump */
1423
+ for (i = 0; i < periodiccnt; ++i)
1424
+ {
1425
+ ev_periodic *w = (ev_periodic *)periodics [i];
1426
+
1427
+ if (w->reschedule_cb)
1428
+ ((WT)w)->at = w->reschedule_cb (w, ev_rt_now);
1429
+ else if (w->interval)
1430
+ ((WT)w)->at = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
1431
+ }
1432
+
1433
+ /* now rebuild the heap */
1434
+ for (i = periodiccnt >> 1; i--; )
1435
+ downheap (periodics, periodiccnt, i);
1436
+ }
1437
+ #endif
1438
+
1439
+ #if EV_IDLE_ENABLE
1440
+ void inline_size
1441
+ idle_reify (EV_P)
1442
+ {
1443
+ if (expect_false (idleall))
1444
+ {
1445
+ int pri;
1446
+
1447
+ for (pri = NUMPRI; pri--; )
1448
+ {
1449
+ if (pendingcnt [pri])
1450
+ break;
1451
+
1452
+ if (idlecnt [pri])
1453
+ {
1454
+ queue_events (EV_A_ (W *)idles [pri], idlecnt [pri], EV_IDLE);
1455
+ break;
1456
+ }
1457
+ }
1458
+ }
1459
+ }
1460
+ #endif
1461
+
1462
+ void inline_speed
1463
+ time_update (EV_P_ ev_tstamp max_block)
1464
+ {
1465
+ int i;
1466
+
1467
+ #if EV_USE_MONOTONIC
1468
+ if (expect_true (have_monotonic))
1469
+ {
1470
+ ev_tstamp odiff = rtmn_diff;
1471
+
1472
+ mn_now = get_clock ();
1473
+
1474
+ /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */
1475
+ /* interpolate in the meantime */
1476
+ if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5))
1477
+ {
1478
+ ev_rt_now = rtmn_diff + mn_now;
1479
+ return;
1480
+ }
1481
+
1482
+ now_floor = mn_now;
1483
+ ev_rt_now = ev_time ();
1484
+
1485
+ /* loop a few times, before making important decisions.
1486
+ * on the choice of "4": one iteration isn't enough,
1487
+ * in case we get preempted during the calls to
1488
+ * ev_time and get_clock. a second call is almost guaranteed
1489
+ * to succeed in that case, though. and looping a few more times
1490
+ * doesn't hurt either as we only do this on time-jumps or
1491
+ * in the unlikely event of having been preempted here.
1492
+ */
1493
+ for (i = 4; --i; )
1494
+ {
1495
+ rtmn_diff = ev_rt_now - mn_now;
1496
+
1497
+ if (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP)
1498
+ return; /* all is well */
1499
+
1500
+ ev_rt_now = ev_time ();
1501
+ mn_now = get_clock ();
1502
+ now_floor = mn_now;
1503
+ }
1504
+
1505
+ # if EV_PERIODIC_ENABLE
1506
+ periodics_reschedule (EV_A);
1507
+ # endif
1508
+ /* no timer adjustment, as the monotonic clock doesn't jump */
1509
+ /* timers_reschedule (EV_A_ rtmn_diff - odiff) */
1510
+ }
1511
+ else
1512
+ #endif
1513
+ {
1514
+ ev_rt_now = ev_time ();
1515
+
1516
+ if (expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + MIN_TIMEJUMP))
1517
+ {
1518
+ #if EV_PERIODIC_ENABLE
1519
+ periodics_reschedule (EV_A);
1520
+ #endif
1521
+ /* adjust timers. this is easy, as the offset is the same for all of them */
1522
+ for (i = 0; i < timercnt; ++i)
1523
+ ((WT)timers [i])->at += ev_rt_now - mn_now;
1524
+ }
1525
+
1526
+ mn_now = ev_rt_now;
1527
+ }
1528
+ }
1529
+
1530
+ void
1531
+ ev_ref (EV_P)
1532
+ {
1533
+ ++activecnt;
1534
+ }
1535
+
1536
+ void
1537
+ ev_unref (EV_P)
1538
+ {
1539
+ --activecnt;
1540
+ }
1541
+
1542
+ static int loop_done;
1543
+
1544
+ void
1545
+ ev_loop (EV_P_ int flags)
1546
+ {
1547
+ loop_done = EVUNLOOP_CANCEL;
1548
+
1549
+ call_pending (EV_A); /* in case we recurse, ensure ordering stays nice and clean */
1550
+
1551
+ do
1552
+ {
1553
+ #ifndef _WIN32
1554
+ if (expect_false (curpid)) /* penalise the forking check even more */
1555
+ if (expect_false (getpid () != curpid))
1556
+ {
1557
+ curpid = getpid ();
1558
+ postfork = 1;
1559
+ }
1560
+ #endif
1561
+
1562
+ #if EV_FORK_ENABLE
1563
+ /* we might have forked, so queue fork handlers */
1564
+ if (expect_false (postfork))
1565
+ if (forkcnt)
1566
+ {
1567
+ queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
1568
+ call_pending (EV_A);
1569
+ }
1570
+ #endif
1571
+
1572
+ /* queue prepare watchers (and execute them) */
1573
+ if (expect_false (preparecnt))
1574
+ {
1575
+ queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
1576
+ call_pending (EV_A);
1577
+ }
1578
+
1579
+ if (expect_false (!activecnt))
1580
+ break;
1581
+
1582
+ /* we might have forked, so reify kernel state if necessary */
1583
+ if (expect_false (postfork))
1584
+ loop_fork (EV_A);
1585
+
1586
+ /* update fd-related kernel structures */
1587
+ fd_reify (EV_A);
1588
+
1589
+ /* calculate blocking time */
1590
+ {
1591
+ ev_tstamp waittime = 0.;
1592
+ ev_tstamp sleeptime = 0.;
1593
+
1594
+ if (expect_true (!(flags & EVLOOP_NONBLOCK || idleall || !activecnt)))
1595
+ {
1596
+ /* update time to cancel out callback processing overhead */
1597
+ time_update (EV_A_ 1e100);
1598
+
1599
+ waittime = MAX_BLOCKTIME;
1600
+
1601
+ if (timercnt)
1602
+ {
1603
+ ev_tstamp to = ((WT)timers [0])->at - mn_now + backend_fudge;
1604
+ if (waittime > to) waittime = to;
1605
+ }
1606
+
1607
+ #if EV_PERIODIC_ENABLE
1608
+ if (periodiccnt)
1609
+ {
1610
+ ev_tstamp to = ((WT)periodics [0])->at - ev_rt_now + backend_fudge;
1611
+ if (waittime > to) waittime = to;
1612
+ }
1613
+ #endif
1614
+
1615
+ if (expect_false (waittime < timeout_blocktime))
1616
+ waittime = timeout_blocktime;
1617
+
1618
+ sleeptime = waittime - backend_fudge;
1619
+
1620
+ if (expect_true (sleeptime > io_blocktime))
1621
+ sleeptime = io_blocktime;
1622
+
1623
+ if (sleeptime)
1624
+ {
1625
+ ev_sleep (sleeptime);
1626
+ waittime -= sleeptime;
1627
+ }
1628
+ }
1629
+
1630
+ ++loop_count;
1631
+ backend_poll (EV_A_ waittime);
1632
+
1633
+ /* update ev_rt_now, do magic */
1634
+ time_update (EV_A_ waittime + sleeptime);
1635
+ }
1636
+
1637
+ /* queue pending timers and reschedule them */
1638
+ timers_reify (EV_A); /* relative timers called last */
1639
+ #if EV_PERIODIC_ENABLE
1640
+ periodics_reify (EV_A); /* absolute timers called first */
1641
+ #endif
1642
+
1643
+ #if EV_IDLE_ENABLE
1644
+ /* queue idle watchers unless other events are pending */
1645
+ idle_reify (EV_A);
1646
+ #endif
1647
+
1648
+ /* queue check watchers, to be executed first */
1649
+ if (expect_false (checkcnt))
1650
+ queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
1651
+
1652
+ call_pending (EV_A);
1653
+ }
1654
+ while (expect_true (
1655
+ activecnt
1656
+ && !loop_done
1657
+ && !(flags & (EVLOOP_ONESHOT | EVLOOP_NONBLOCK))
1658
+ ));
1659
+
1660
+ if (loop_done == EVUNLOOP_ONE)
1661
+ loop_done = EVUNLOOP_CANCEL;
1662
+ }
1663
+
1664
+ void
1665
+ ev_unloop (EV_P_ int how)
1666
+ {
1667
+ loop_done = how;
1668
+ }
1669
+
1670
+ /*****************************************************************************/
1671
+
1672
+ void inline_size
1673
+ wlist_add (WL *head, WL elem)
1674
+ {
1675
+ elem->next = *head;
1676
+ *head = elem;
1677
+ }
1678
+
1679
+ void inline_size
1680
+ wlist_del (WL *head, WL elem)
1681
+ {
1682
+ while (*head)
1683
+ {
1684
+ if (*head == elem)
1685
+ {
1686
+ *head = elem->next;
1687
+ return;
1688
+ }
1689
+
1690
+ head = &(*head)->next;
1691
+ }
1692
+ }
1693
+
1694
+ void inline_speed
1695
+ clear_pending (EV_P_ W w)
1696
+ {
1697
+ if (w->pending)
1698
+ {
1699
+ pendings [ABSPRI (w)][w->pending - 1].w = 0;
1700
+ w->pending = 0;
1701
+ }
1702
+ }
1703
+
1704
+ int
1705
+ ev_clear_pending (EV_P_ void *w)
1706
+ {
1707
+ W w_ = (W)w;
1708
+ int pending = w_->pending;
1709
+
1710
+ if (expect_true (pending))
1711
+ {
1712
+ ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1;
1713
+ w_->pending = 0;
1714
+ p->w = 0;
1715
+ return p->events;
1716
+ }
1717
+ else
1718
+ return 0;
1719
+ }
1720
+
1721
+ void inline_size
1722
+ pri_adjust (EV_P_ W w)
1723
+ {
1724
+ int pri = w->priority;
1725
+ pri = pri < EV_MINPRI ? EV_MINPRI : pri;
1726
+ pri = pri > EV_MAXPRI ? EV_MAXPRI : pri;
1727
+ w->priority = pri;
1728
+ }
1729
+
1730
+ void inline_speed
1731
+ ev_start (EV_P_ W w, int active)
1732
+ {
1733
+ pri_adjust (EV_A_ w);
1734
+ w->active = active;
1735
+ ev_ref (EV_A);
1736
+ }
1737
+
1738
+ void inline_size
1739
+ ev_stop (EV_P_ W w)
1740
+ {
1741
+ ev_unref (EV_A);
1742
+ w->active = 0;
1743
+ }
1744
+
1745
+ /*****************************************************************************/
1746
+
1747
+ void noinline
1748
+ ev_io_start (EV_P_ ev_io *w)
1749
+ {
1750
+ int fd = w->fd;
1751
+
1752
+ if (expect_false (ev_is_active (w)))
1753
+ return;
1754
+
1755
+ assert (("ev_io_start called with negative fd", fd >= 0));
1756
+
1757
+ ev_start (EV_A_ (W)w, 1);
1758
+ array_needsize (ANFD, anfds, anfdmax, fd + 1, anfds_init);
1759
+ wlist_add (&anfds[fd].head, (WL)w);
1760
+
1761
+ fd_change (EV_A_ fd, w->events & EV_IOFDSET | 1);
1762
+ w->events &= ~EV_IOFDSET;
1763
+ }
1764
+
1765
+ void noinline
1766
+ ev_io_stop (EV_P_ ev_io *w)
1767
+ {
1768
+ clear_pending (EV_A_ (W)w);
1769
+ if (expect_false (!ev_is_active (w)))
1770
+ return;
1771
+
1772
+ assert (("ev_io_start called with illegal fd (must stay constant after start!)", w->fd >= 0 && w->fd < anfdmax));
1773
+
1774
+ wlist_del (&anfds[w->fd].head, (WL)w);
1775
+ ev_stop (EV_A_ (W)w);
1776
+
1777
+ fd_change (EV_A_ w->fd, 1);
1778
+ }
1779
+
1780
+ void noinline
1781
+ ev_timer_start (EV_P_ ev_timer *w)
1782
+ {
1783
+ if (expect_false (ev_is_active (w)))
1784
+ return;
1785
+
1786
+ ((WT)w)->at += mn_now;
1787
+
1788
+ assert (("ev_timer_start called with negative timer repeat value", w->repeat >= 0.));
1789
+
1790
+ ev_start (EV_A_ (W)w, ++timercnt);
1791
+ array_needsize (WT, timers, timermax, timercnt, EMPTY2);
1792
+ timers [timercnt - 1] = (WT)w;
1793
+ upheap (timers, timercnt - 1);
1794
+
1795
+ /*assert (("internal timer heap corruption", timers [((W)w)->active - 1] == w));*/
1796
+ }
1797
+
1798
+ void noinline
1799
+ ev_timer_stop (EV_P_ ev_timer *w)
1800
+ {
1801
+ clear_pending (EV_A_ (W)w);
1802
+ if (expect_false (!ev_is_active (w)))
1803
+ return;
1804
+
1805
+ assert (("internal timer heap corruption", timers [((W)w)->active - 1] == (WT)w));
1806
+
1807
+ {
1808
+ int active = ((W)w)->active;
1809
+
1810
+ if (expect_true (--active < --timercnt))
1811
+ {
1812
+ timers [active] = timers [timercnt];
1813
+ adjustheap (timers, timercnt, active);
1814
+ }
1815
+ }
1816
+
1817
+ ((WT)w)->at -= mn_now;
1818
+
1819
+ ev_stop (EV_A_ (W)w);
1820
+ }
1821
+
1822
+ void noinline
1823
+ ev_timer_again (EV_P_ ev_timer *w)
1824
+ {
1825
+ if (ev_is_active (w))
1826
+ {
1827
+ if (w->repeat)
1828
+ {
1829
+ ((WT)w)->at = mn_now + w->repeat;
1830
+ adjustheap (timers, timercnt, ((W)w)->active - 1);
1831
+ }
1832
+ else
1833
+ ev_timer_stop (EV_A_ w);
1834
+ }
1835
+ else if (w->repeat)
1836
+ {
1837
+ w->at = w->repeat;
1838
+ ev_timer_start (EV_A_ w);
1839
+ }
1840
+ }
1841
+
1842
+ #if EV_PERIODIC_ENABLE
1843
+ void noinline
1844
+ ev_periodic_start (EV_P_ ev_periodic *w)
1845
+ {
1846
+ if (expect_false (ev_is_active (w)))
1847
+ return;
1848
+
1849
+ if (w->reschedule_cb)
1850
+ ((WT)w)->at = w->reschedule_cb (w, ev_rt_now);
1851
+ else if (w->interval)
1852
+ {
1853
+ assert (("ev_periodic_start called with negative interval value", w->interval >= 0.));
1854
+ /* this formula differs from the one in periodic_reify because we do not always round up */
1855
+ ((WT)w)->at = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
1856
+ }
1857
+ else
1858
+ ((WT)w)->at = w->offset;
1859
+
1860
+ ev_start (EV_A_ (W)w, ++periodiccnt);
1861
+ array_needsize (WT, periodics, periodicmax, periodiccnt, EMPTY2);
1862
+ periodics [periodiccnt - 1] = (WT)w;
1863
+ upheap (periodics, periodiccnt - 1);
1864
+
1865
+ /*assert (("internal periodic heap corruption", periodics [((W)w)->active - 1] == w));*/
1866
+ }
1867
+
1868
+ void noinline
1869
+ ev_periodic_stop (EV_P_ ev_periodic *w)
1870
+ {
1871
+ clear_pending (EV_A_ (W)w);
1872
+ if (expect_false (!ev_is_active (w)))
1873
+ return;
1874
+
1875
+ assert (("internal periodic heap corruption", periodics [((W)w)->active - 1] == (WT)w));
1876
+
1877
+ {
1878
+ int active = ((W)w)->active;
1879
+
1880
+ if (expect_true (--active < --periodiccnt))
1881
+ {
1882
+ periodics [active] = periodics [periodiccnt];
1883
+ adjustheap (periodics, periodiccnt, active);
1884
+ }
1885
+ }
1886
+
1887
+ ev_stop (EV_A_ (W)w);
1888
+ }
1889
+
1890
+ void noinline
1891
+ ev_periodic_again (EV_P_ ev_periodic *w)
1892
+ {
1893
+ /* TODO: use adjustheap and recalculation */
1894
+ ev_periodic_stop (EV_A_ w);
1895
+ ev_periodic_start (EV_A_ w);
1896
+ }
1897
+ #endif
1898
+
1899
+ #ifndef SA_RESTART
1900
+ # define SA_RESTART 0
1901
+ #endif
1902
+
1903
+ void noinline
1904
+ ev_signal_start (EV_P_ ev_signal *w)
1905
+ {
1906
+ #if EV_MULTIPLICITY
1907
+ assert (("signal watchers are only supported in the default loop", loop == ev_default_loop_ptr));
1908
+ #endif
1909
+ if (expect_false (ev_is_active (w)))
1910
+ return;
1911
+
1912
+ assert (("ev_signal_start called with illegal signal number", w->signum > 0));
1913
+
1914
+ evpipe_init (EV_A);
1915
+
1916
+ {
1917
+ #ifndef _WIN32
1918
+ sigset_t full, prev;
1919
+ sigfillset (&full);
1920
+ sigprocmask (SIG_SETMASK, &full, &prev);
1921
+ #endif
1922
+
1923
+ array_needsize (ANSIG, signals, signalmax, w->signum, signals_init);
1924
+
1925
+ #ifndef _WIN32
1926
+ sigprocmask (SIG_SETMASK, &prev, 0);
1927
+ #endif
1928
+ }
1929
+
1930
+ ev_start (EV_A_ (W)w, 1);
1931
+ wlist_add (&signals [w->signum - 1].head, (WL)w);
1932
+
1933
+ if (!((WL)w)->next)
1934
+ {
1935
+ #if _WIN32
1936
+ signal (w->signum, ev_sighandler);
1937
+ #else
1938
+ struct sigaction sa;
1939
+ sa.sa_handler = ev_sighandler;
1940
+ sigfillset (&sa.sa_mask);
1941
+ sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
1942
+ sigaction (w->signum, &sa, 0);
1943
+ #endif
1944
+ }
1945
+ }
1946
+
1947
+ void noinline
1948
+ ev_signal_stop (EV_P_ ev_signal *w)
1949
+ {
1950
+ clear_pending (EV_A_ (W)w);
1951
+ if (expect_false (!ev_is_active (w)))
1952
+ return;
1953
+
1954
+ wlist_del (&signals [w->signum - 1].head, (WL)w);
1955
+ ev_stop (EV_A_ (W)w);
1956
+
1957
+ if (!signals [w->signum - 1].head)
1958
+ signal (w->signum, SIG_DFL);
1959
+ }
1960
+
1961
+ void
1962
+ ev_child_start (EV_P_ ev_child *w)
1963
+ {
1964
+ #if EV_MULTIPLICITY
1965
+ assert (("child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
1966
+ #endif
1967
+ if (expect_false (ev_is_active (w)))
1968
+ return;
1969
+
1970
+ ev_start (EV_A_ (W)w, 1);
1971
+ wlist_add (&childs [w->pid & (EV_PID_HASHSIZE - 1)], (WL)w);
1972
+ }
1973
+
1974
+ void
1975
+ ev_child_stop (EV_P_ ev_child *w)
1976
+ {
1977
+ clear_pending (EV_A_ (W)w);
1978
+ if (expect_false (!ev_is_active (w)))
1979
+ return;
1980
+
1981
+ wlist_del (&childs [w->pid & (EV_PID_HASHSIZE - 1)], (WL)w);
1982
+ ev_stop (EV_A_ (W)w);
1983
+ }
1984
+
1985
+ #if EV_STAT_ENABLE
1986
+
1987
+ # ifdef _WIN32
1988
+ # undef lstat
1989
+ # define lstat(a,b) _stati64 (a,b)
1990
+ # endif
1991
+
1992
+ #define DEF_STAT_INTERVAL 5.0074891
1993
+ #define MIN_STAT_INTERVAL 0.1074891
1994
+
1995
+ static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents);
1996
+
1997
+ #if EV_USE_INOTIFY
1998
+ # define EV_INOTIFY_BUFSIZE 8192
1999
+
2000
+ static void noinline
2001
+ infy_add (EV_P_ ev_stat *w)
2002
+ {
2003
+ w->wd = inotify_add_watch (fs_fd, w->path, IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY | IN_DONT_FOLLOW | IN_MASK_ADD);
2004
+
2005
+ if (w->wd < 0)
2006
+ {
2007
+ ev_timer_start (EV_A_ &w->timer); /* this is not race-free, so we still need to recheck periodically */
2008
+
2009
+ /* monitor some parent directory for speedup hints */
2010
+ if ((errno == ENOENT || errno == EACCES) && strlen (w->path) < 4096)
2011
+ {
2012
+ char path [4096];
2013
+ strcpy (path, w->path);
2014
+
2015
+ do
2016
+ {
2017
+ int mask = IN_MASK_ADD | IN_DELETE_SELF | IN_MOVE_SELF
2018
+ | (errno == EACCES ? IN_ATTRIB : IN_CREATE | IN_MOVED_TO);
2019
+
2020
+ char *pend = strrchr (path, '/');
2021
+
2022
+ if (!pend)
2023
+ break; /* whoops, no '/', complain to your admin */
2024
+
2025
+ *pend = 0;
2026
+ w->wd = inotify_add_watch (fs_fd, path, mask);
2027
+ }
2028
+ while (w->wd < 0 && (errno == ENOENT || errno == EACCES));
2029
+ }
2030
+ }
2031
+ else
2032
+ ev_timer_stop (EV_A_ &w->timer); /* we can watch this in a race-free way */
2033
+
2034
+ if (w->wd >= 0)
2035
+ wlist_add (&fs_hash [w->wd & (EV_INOTIFY_HASHSIZE - 1)].head, (WL)w);
2036
+ }
2037
+
2038
+ static void noinline
2039
+ infy_del (EV_P_ ev_stat *w)
2040
+ {
2041
+ int slot;
2042
+ int wd = w->wd;
2043
+
2044
+ if (wd < 0)
2045
+ return;
2046
+
2047
+ w->wd = -2;
2048
+ slot = wd & (EV_INOTIFY_HASHSIZE - 1);
2049
+ wlist_del (&fs_hash [slot].head, (WL)w);
2050
+
2051
+ /* remove this watcher, if others are watching it, they will rearm */
2052
+ inotify_rm_watch (fs_fd, wd);
2053
+ }
2054
+
2055
+ static void noinline
2056
+ infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev)
2057
+ {
2058
+ if (slot < 0)
2059
+ /* overflow, need to check for all hahs slots */
2060
+ for (slot = 0; slot < EV_INOTIFY_HASHSIZE; ++slot)
2061
+ infy_wd (EV_A_ slot, wd, ev);
2062
+ else
2063
+ {
2064
+ WL w_;
2065
+
2066
+ for (w_ = fs_hash [slot & (EV_INOTIFY_HASHSIZE - 1)].head; w_; )
2067
+ {
2068
+ ev_stat *w = (ev_stat *)w_;
2069
+ w_ = w_->next; /* lets us remove this watcher and all before it */
2070
+
2071
+ if (w->wd == wd || wd == -1)
2072
+ {
2073
+ if (ev->mask & (IN_IGNORED | IN_UNMOUNT | IN_DELETE_SELF))
2074
+ {
2075
+ w->wd = -1;
2076
+ infy_add (EV_A_ w); /* re-add, no matter what */
2077
+ }
2078
+
2079
+ stat_timer_cb (EV_A_ &w->timer, 0);
2080
+ }
2081
+ }
2082
+ }
2083
+ }
2084
+
2085
+ static void
2086
+ infy_cb (EV_P_ ev_io *w, int revents)
2087
+ {
2088
+ char buf [EV_INOTIFY_BUFSIZE];
2089
+ struct inotify_event *ev = (struct inotify_event *)buf;
2090
+ int ofs;
2091
+ int len = read (fs_fd, buf, sizeof (buf));
2092
+
2093
+ for (ofs = 0; ofs < len; ofs += sizeof (struct inotify_event) + ev->len)
2094
+ infy_wd (EV_A_ ev->wd, ev->wd, ev);
2095
+ }
2096
+
2097
+ void inline_size
2098
+ infy_init (EV_P)
2099
+ {
2100
+ if (fs_fd != -2)
2101
+ return;
2102
+
2103
+ fs_fd = inotify_init ();
2104
+
2105
+ if (fs_fd >= 0)
2106
+ {
2107
+ ev_io_init (&fs_w, infy_cb, fs_fd, EV_READ);
2108
+ ev_set_priority (&fs_w, EV_MAXPRI);
2109
+ ev_io_start (EV_A_ &fs_w);
2110
+ }
2111
+ }
2112
+
2113
+ void inline_size
2114
+ infy_fork (EV_P)
2115
+ {
2116
+ int slot;
2117
+
2118
+ if (fs_fd < 0)
2119
+ return;
2120
+
2121
+ close (fs_fd);
2122
+ fs_fd = inotify_init ();
2123
+
2124
+ for (slot = 0; slot < EV_INOTIFY_HASHSIZE; ++slot)
2125
+ {
2126
+ WL w_ = fs_hash [slot].head;
2127
+ fs_hash [slot].head = 0;
2128
+
2129
+ while (w_)
2130
+ {
2131
+ ev_stat *w = (ev_stat *)w_;
2132
+ w_ = w_->next; /* lets us add this watcher */
2133
+
2134
+ w->wd = -1;
2135
+
2136
+ if (fs_fd >= 0)
2137
+ infy_add (EV_A_ w); /* re-add, no matter what */
2138
+ else
2139
+ ev_timer_start (EV_A_ &w->timer);
2140
+ }
2141
+
2142
+ }
2143
+ }
2144
+
2145
+ #endif
2146
+
2147
+ void
2148
+ ev_stat_stat (EV_P_ ev_stat *w)
2149
+ {
2150
+ if (lstat (w->path, &w->attr) < 0)
2151
+ w->attr.st_nlink = 0;
2152
+ else if (!w->attr.st_nlink)
2153
+ w->attr.st_nlink = 1;
2154
+ }
2155
+
2156
+ static void noinline
2157
+ stat_timer_cb (EV_P_ ev_timer *w_, int revents)
2158
+ {
2159
+ ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
2160
+
2161
+ /* we copy this here each the time so that */
2162
+ /* prev has the old value when the callback gets invoked */
2163
+ w->prev = w->attr;
2164
+ ev_stat_stat (EV_A_ w);
2165
+
2166
+ /* memcmp doesn't work on netbsd, they.... do stuff to their struct stat */
2167
+ if (
2168
+ w->prev.st_dev != w->attr.st_dev
2169
+ || w->prev.st_ino != w->attr.st_ino
2170
+ || w->prev.st_mode != w->attr.st_mode
2171
+ || w->prev.st_nlink != w->attr.st_nlink
2172
+ || w->prev.st_uid != w->attr.st_uid
2173
+ || w->prev.st_gid != w->attr.st_gid
2174
+ || w->prev.st_rdev != w->attr.st_rdev
2175
+ || w->prev.st_size != w->attr.st_size
2176
+ || w->prev.st_atime != w->attr.st_atime
2177
+ || w->prev.st_mtime != w->attr.st_mtime
2178
+ || w->prev.st_ctime != w->attr.st_ctime
2179
+ ) {
2180
+ #if EV_USE_INOTIFY
2181
+ infy_del (EV_A_ w);
2182
+ infy_add (EV_A_ w);
2183
+ ev_stat_stat (EV_A_ w); /* avoid race... */
2184
+ #endif
2185
+
2186
+ ev_feed_event (EV_A_ w, EV_STAT);
2187
+ }
2188
+ }
2189
+
2190
+ void
2191
+ ev_stat_start (EV_P_ ev_stat *w)
2192
+ {
2193
+ if (expect_false (ev_is_active (w)))
2194
+ return;
2195
+
2196
+ /* since we use memcmp, we need to clear any padding data etc. */
2197
+ memset (&w->prev, 0, sizeof (ev_statdata));
2198
+ memset (&w->attr, 0, sizeof (ev_statdata));
2199
+
2200
+ ev_stat_stat (EV_A_ w);
2201
+
2202
+ if (w->interval < MIN_STAT_INTERVAL)
2203
+ w->interval = w->interval ? MIN_STAT_INTERVAL : DEF_STAT_INTERVAL;
2204
+
2205
+ ev_timer_init (&w->timer, stat_timer_cb, w->interval, w->interval);
2206
+ ev_set_priority (&w->timer, ev_priority (w));
2207
+
2208
+ #if EV_USE_INOTIFY
2209
+ infy_init (EV_A);
2210
+
2211
+ if (fs_fd >= 0)
2212
+ infy_add (EV_A_ w);
2213
+ else
2214
+ #endif
2215
+ ev_timer_start (EV_A_ &w->timer);
2216
+
2217
+ ev_start (EV_A_ (W)w, 1);
2218
+ }
2219
+
2220
+ void
2221
+ ev_stat_stop (EV_P_ ev_stat *w)
2222
+ {
2223
+ clear_pending (EV_A_ (W)w);
2224
+ if (expect_false (!ev_is_active (w)))
2225
+ return;
2226
+
2227
+ #if EV_USE_INOTIFY
2228
+ infy_del (EV_A_ w);
2229
+ #endif
2230
+ ev_timer_stop (EV_A_ &w->timer);
2231
+
2232
+ ev_stop (EV_A_ (W)w);
2233
+ }
2234
+ #endif
2235
+
2236
+ #if EV_IDLE_ENABLE
2237
+ void
2238
+ ev_idle_start (EV_P_ ev_idle *w)
2239
+ {
2240
+ if (expect_false (ev_is_active (w)))
2241
+ return;
2242
+
2243
+ pri_adjust (EV_A_ (W)w);
2244
+
2245
+ {
2246
+ int active = ++idlecnt [ABSPRI (w)];
2247
+
2248
+ ++idleall;
2249
+ ev_start (EV_A_ (W)w, active);
2250
+
2251
+ array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, EMPTY2);
2252
+ idles [ABSPRI (w)][active - 1] = w;
2253
+ }
2254
+ }
2255
+
2256
+ void
2257
+ ev_idle_stop (EV_P_ ev_idle *w)
2258
+ {
2259
+ clear_pending (EV_A_ (W)w);
2260
+ if (expect_false (!ev_is_active (w)))
2261
+ return;
2262
+
2263
+ {
2264
+ int active = ((W)w)->active;
2265
+
2266
+ idles [ABSPRI (w)][active - 1] = idles [ABSPRI (w)][--idlecnt [ABSPRI (w)]];
2267
+ ((W)idles [ABSPRI (w)][active - 1])->active = active;
2268
+
2269
+ ev_stop (EV_A_ (W)w);
2270
+ --idleall;
2271
+ }
2272
+ }
2273
+ #endif
2274
+
2275
+ void
2276
+ ev_prepare_start (EV_P_ ev_prepare *w)
2277
+ {
2278
+ if (expect_false (ev_is_active (w)))
2279
+ return;
2280
+
2281
+ ev_start (EV_A_ (W)w, ++preparecnt);
2282
+ array_needsize (ev_prepare *, prepares, preparemax, preparecnt, EMPTY2);
2283
+ prepares [preparecnt - 1] = w;
2284
+ }
2285
+
2286
+ void
2287
+ ev_prepare_stop (EV_P_ ev_prepare *w)
2288
+ {
2289
+ clear_pending (EV_A_ (W)w);
2290
+ if (expect_false (!ev_is_active (w)))
2291
+ return;
2292
+
2293
+ {
2294
+ int active = ((W)w)->active;
2295
+ prepares [active - 1] = prepares [--preparecnt];
2296
+ ((W)prepares [active - 1])->active = active;
2297
+ }
2298
+
2299
+ ev_stop (EV_A_ (W)w);
2300
+ }
2301
+
2302
+ void
2303
+ ev_check_start (EV_P_ ev_check *w)
2304
+ {
2305
+ if (expect_false (ev_is_active (w)))
2306
+ return;
2307
+
2308
+ ev_start (EV_A_ (W)w, ++checkcnt);
2309
+ array_needsize (ev_check *, checks, checkmax, checkcnt, EMPTY2);
2310
+ checks [checkcnt - 1] = w;
2311
+ }
2312
+
2313
+ void
2314
+ ev_check_stop (EV_P_ ev_check *w)
2315
+ {
2316
+ clear_pending (EV_A_ (W)w);
2317
+ if (expect_false (!ev_is_active (w)))
2318
+ return;
2319
+
2320
+ {
2321
+ int active = ((W)w)->active;
2322
+ checks [active - 1] = checks [--checkcnt];
2323
+ ((W)checks [active - 1])->active = active;
2324
+ }
2325
+
2326
+ ev_stop (EV_A_ (W)w);
2327
+ }
2328
+
2329
+ #if EV_EMBED_ENABLE
2330
+ void noinline
2331
+ ev_embed_sweep (EV_P_ ev_embed *w)
2332
+ {
2333
+ ev_loop (w->other, EVLOOP_NONBLOCK);
2334
+ }
2335
+
2336
+ static void
2337
+ embed_io_cb (EV_P_ ev_io *io, int revents)
2338
+ {
2339
+ ev_embed *w = (ev_embed *)(((char *)io) - offsetof (ev_embed, io));
2340
+
2341
+ if (ev_cb (w))
2342
+ ev_feed_event (EV_A_ (W)w, EV_EMBED);
2343
+ else
2344
+ ev_loop (w->other, EVLOOP_NONBLOCK);
2345
+ }
2346
+
2347
+ static void
2348
+ embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents)
2349
+ {
2350
+ ev_embed *w = (ev_embed *)(((char *)prepare) - offsetof (ev_embed, prepare));
2351
+
2352
+ {
2353
+ struct ev_loop *loop = w->other;
2354
+
2355
+ while (fdchangecnt)
2356
+ {
2357
+ fd_reify (EV_A);
2358
+ ev_loop (EV_A_ EVLOOP_NONBLOCK);
2359
+ }
2360
+ }
2361
+ }
2362
+
2363
+ #if 0
2364
+ static void
2365
+ embed_idle_cb (EV_P_ ev_idle *idle, int revents)
2366
+ {
2367
+ ev_idle_stop (EV_A_ idle);
2368
+ }
2369
+ #endif
2370
+
2371
+ void
2372
+ ev_embed_start (EV_P_ ev_embed *w)
2373
+ {
2374
+ if (expect_false (ev_is_active (w)))
2375
+ return;
2376
+
2377
+ {
2378
+ struct ev_loop *loop = w->other;
2379
+ assert (("loop to be embedded is not embeddable", backend & ev_embeddable_backends ()));
2380
+ ev_io_init (&w->io, embed_io_cb, backend_fd, EV_READ);
2381
+ }
2382
+
2383
+ ev_set_priority (&w->io, ev_priority (w));
2384
+ ev_io_start (EV_A_ &w->io);
2385
+
2386
+ ev_prepare_init (&w->prepare, embed_prepare_cb);
2387
+ ev_set_priority (&w->prepare, EV_MINPRI);
2388
+ ev_prepare_start (EV_A_ &w->prepare);
2389
+
2390
+ /*ev_idle_init (&w->idle, e,bed_idle_cb);*/
2391
+
2392
+ ev_start (EV_A_ (W)w, 1);
2393
+ }
2394
+
2395
+ void
2396
+ ev_embed_stop (EV_P_ ev_embed *w)
2397
+ {
2398
+ clear_pending (EV_A_ (W)w);
2399
+ if (expect_false (!ev_is_active (w)))
2400
+ return;
2401
+
2402
+ ev_io_stop (EV_A_ &w->io);
2403
+ ev_prepare_stop (EV_A_ &w->prepare);
2404
+
2405
+ ev_stop (EV_A_ (W)w);
2406
+ }
2407
+ #endif
2408
+
2409
+ #if EV_FORK_ENABLE
2410
+ void
2411
+ ev_fork_start (EV_P_ ev_fork *w)
2412
+ {
2413
+ if (expect_false (ev_is_active (w)))
2414
+ return;
2415
+
2416
+ ev_start (EV_A_ (W)w, ++forkcnt);
2417
+ array_needsize (ev_fork *, forks, forkmax, forkcnt, EMPTY2);
2418
+ forks [forkcnt - 1] = w;
2419
+ }
2420
+
2421
+ void
2422
+ ev_fork_stop (EV_P_ ev_fork *w)
2423
+ {
2424
+ clear_pending (EV_A_ (W)w);
2425
+ if (expect_false (!ev_is_active (w)))
2426
+ return;
2427
+
2428
+ {
2429
+ int active = ((W)w)->active;
2430
+ forks [active - 1] = forks [--forkcnt];
2431
+ ((W)forks [active - 1])->active = active;
2432
+ }
2433
+
2434
+ ev_stop (EV_A_ (W)w);
2435
+ }
2436
+ #endif
2437
+
2438
+ #if EV_ASYNC_ENABLE
2439
+ void
2440
+ ev_async_start (EV_P_ ev_async *w)
2441
+ {
2442
+ if (expect_false (ev_is_active (w)))
2443
+ return;
2444
+
2445
+ evpipe_init (EV_A);
2446
+
2447
+ ev_start (EV_A_ (W)w, ++asynccnt);
2448
+ array_needsize (ev_async *, asyncs, asyncmax, asynccnt, EMPTY2);
2449
+ asyncs [asynccnt - 1] = w;
2450
+ }
2451
+
2452
+ void
2453
+ ev_async_stop (EV_P_ ev_async *w)
2454
+ {
2455
+ clear_pending (EV_A_ (W)w);
2456
+ if (expect_false (!ev_is_active (w)))
2457
+ return;
2458
+
2459
+ {
2460
+ int active = ((W)w)->active;
2461
+ asyncs [active - 1] = asyncs [--asynccnt];
2462
+ ((W)asyncs [active - 1])->active = active;
2463
+ }
2464
+
2465
+ ev_stop (EV_A_ (W)w);
2466
+ }
2467
+
2468
+ void
2469
+ ev_async_send (EV_P_ ev_async *w)
2470
+ {
2471
+ w->sent = 1;
2472
+ evpipe_write (EV_A_ &gotasync);
2473
+ }
2474
+ #endif
2475
+
2476
+ /*****************************************************************************/
2477
+
2478
+ struct ev_once
2479
+ {
2480
+ ev_io io;
2481
+ ev_timer to;
2482
+ void (*cb)(int revents, void *arg);
2483
+ void *arg;
2484
+ };
2485
+
2486
+ static void
2487
+ once_cb (EV_P_ struct ev_once *once, int revents)
2488
+ {
2489
+ void (*cb)(int revents, void *arg) = once->cb;
2490
+ void *arg = once->arg;
2491
+
2492
+ ev_io_stop (EV_A_ &once->io);
2493
+ ev_timer_stop (EV_A_ &once->to);
2494
+ ev_free (once);
2495
+
2496
+ cb (revents, arg);
2497
+ }
2498
+
2499
+ static void
2500
+ once_cb_io (EV_P_ ev_io *w, int revents)
2501
+ {
2502
+ once_cb (EV_A_ (struct ev_once *)(((char *)w) - offsetof (struct ev_once, io)), revents);
2503
+ }
2504
+
2505
+ static void
2506
+ once_cb_to (EV_P_ ev_timer *w, int revents)
2507
+ {
2508
+ once_cb (EV_A_ (struct ev_once *)(((char *)w) - offsetof (struct ev_once, to)), revents);
2509
+ }
2510
+
2511
+ void
2512
+ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg)
2513
+ {
2514
+ struct ev_once *once = (struct ev_once *)ev_malloc (sizeof (struct ev_once));
2515
+
2516
+ if (expect_false (!once))
2517
+ {
2518
+ cb (EV_ERROR | EV_READ | EV_WRITE | EV_TIMEOUT, arg);
2519
+ return;
2520
+ }
2521
+
2522
+ once->cb = cb;
2523
+ once->arg = arg;
2524
+
2525
+ ev_init (&once->io, once_cb_io);
2526
+ if (fd >= 0)
2527
+ {
2528
+ ev_io_set (&once->io, fd, events);
2529
+ ev_io_start (EV_A_ &once->io);
2530
+ }
2531
+
2532
+ ev_init (&once->to, once_cb_to);
2533
+ if (timeout >= 0.)
2534
+ {
2535
+ ev_timer_set (&once->to, timeout, 0.);
2536
+ ev_timer_start (EV_A_ &once->to);
2537
+ }
2538
+ }
2539
+
2540
+ #if EV_MULTIPLICITY
2541
+ #include "ev_wrap.h"
2542
+ #endif
2543
+
2544
+ #ifdef __cplusplus
2545
+ }
2546
+ #endif
2547
+