cool.io 1.0.0 → 1.9.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 (83) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/test.yaml +54 -0
  3. data/.gitignore +30 -0
  4. data/.rspec +3 -0
  5. data/{CHANGES → CHANGES.md} +175 -79
  6. data/{README.markdown → README.md} +43 -49
  7. data/Rakefile +44 -69
  8. data/appveyor.yml +18 -0
  9. data/cool.io.gemspec +18 -131
  10. data/examples/callbacked_echo_server.rb +24 -0
  11. data/ext/cool.io/buffer.c +781 -0
  12. data/ext/cool.io/cool.io.h +13 -0
  13. data/ext/cool.io/cool.io_ext.c +1 -0
  14. data/ext/cool.io/ev_wrap.h +4 -2
  15. data/ext/cool.io/extconf.rb +27 -16
  16. data/ext/cool.io/iowatcher.c +17 -8
  17. data/ext/cool.io/loop.c +36 -84
  18. data/ext/cool.io/stat_watcher.c +103 -25
  19. data/ext/cool.io/timer_watcher.c +3 -3
  20. data/ext/cool.io/utils.c +5 -0
  21. data/ext/cool.io/watcher.h +1 -1
  22. data/ext/libev/Changes +152 -3
  23. data/ext/libev/LICENSE +2 -1
  24. data/ext/libev/README +8 -8
  25. data/ext/libev/ev.c +1719 -348
  26. data/ext/libev/ev.h +146 -118
  27. data/ext/libev/ev_epoll.c +71 -20
  28. data/ext/libev/ev_kqueue.c +36 -16
  29. data/ext/libev/ev_poll.c +14 -11
  30. data/ext/libev/ev_port.c +43 -18
  31. data/ext/libev/ev_select.c +82 -25
  32. data/ext/libev/ev_vars.h +28 -21
  33. data/ext/libev/ev_win32.c +19 -10
  34. data/ext/libev/ev_wrap.h +166 -152
  35. data/ext/libev/test_libev_win32.c +1 -1
  36. data/gems.rb +9 -0
  37. data/lib/cool.io/async_watcher.rb +1 -1
  38. data/lib/cool.io/custom_require.rb +9 -0
  39. data/lib/cool.io/dns_resolver.rb +30 -22
  40. data/lib/cool.io/dsl.rb +32 -28
  41. data/lib/cool.io/io.rb +55 -35
  42. data/lib/cool.io/iowatcher.rb +1 -1
  43. data/lib/cool.io/listener.rb +35 -17
  44. data/lib/cool.io/loop.rb +17 -25
  45. data/lib/cool.io/meta.rb +6 -5
  46. data/lib/cool.io/server.rb +5 -4
  47. data/lib/cool.io/socket.rb +41 -30
  48. data/lib/cool.io/timer_watcher.rb +1 -1
  49. data/lib/cool.io/version.rb +7 -0
  50. data/lib/cool.io.rb +11 -10
  51. data/lib/coolio.rb +1 -1
  52. data/libev_ruby_gil.diff +175 -0
  53. data/libev_win_select.diff +130 -0
  54. data/spec/async_watcher_spec.rb +5 -5
  55. data/spec/dns_spec.rb +27 -8
  56. data/spec/iobuffer_spec.rb +147 -0
  57. data/spec/spec_helper.rb +15 -1
  58. data/spec/stat_watcher_spec.rb +81 -0
  59. data/spec/tcp_server_spec.rb +225 -0
  60. data/spec/tcp_socket_spec.rb +185 -0
  61. data/spec/timer_watcher_spec.rb +23 -19
  62. data/spec/udp_socket_spec.rb +58 -0
  63. data/spec/unix_listener_spec.rb +8 -8
  64. data/spec/unix_server_spec.rb +10 -8
  65. metadata +109 -112
  66. data/VERSION +0 -1
  67. data/examples/httpclient.rb +0 -38
  68. data/ext/http11_client/.gitignore +0 -5
  69. data/ext/http11_client/LICENSE +0 -31
  70. data/ext/http11_client/ext_help.h +0 -14
  71. data/ext/http11_client/extconf.rb +0 -6
  72. data/ext/http11_client/http11_client.c +0 -300
  73. data/ext/http11_client/http11_parser.c +0 -403
  74. data/ext/http11_client/http11_parser.h +0 -48
  75. data/ext/http11_client/http11_parser.rl +0 -173
  76. data/lib/cool.io/eventmachine.rb +0 -234
  77. data/lib/cool.io/http_client.rb +0 -419
  78. data/lib/rev.rb +0 -4
  79. data/spec/possible_tests/schedules_other_threads.rb +0 -48
  80. data/spec/possible_tests/test_on_resolve_failed.rb +0 -9
  81. data/spec/possible_tests/test_resolves.rb +0 -27
  82. data/spec/possible_tests/test_write_during_resolve.rb +0 -27
  83. data/spec/possible_tests/works_straight.rb +0 -71
data/ext/libev/ev.c CHANGED
@@ -1,19 +1,19 @@
1
1
  /*
2
2
  * libev event processing core, watcher management
3
3
  *
4
- * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008,2009,2010,2011,2012,2013 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-
8
8
  * tion, are permitted provided that the following conditions are met:
9
- *
9
+ *
10
10
  * 1. Redistributions of source code must retain the above copyright notice,
11
11
  * this list of conditions and the following disclaimer.
12
- *
12
+ *
13
13
  * 2. Redistributions in binary form must reproduce the above copyright
14
14
  * notice, this list of conditions and the following disclaimer in the
15
15
  * documentation and/or other materials provided with the distribution.
16
- *
16
+ *
17
17
  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
18
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
19
  * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
@@ -37,6 +37,13 @@
37
37
  * either the BSD or the GPL.
38
38
  */
39
39
 
40
+ /* ########## COOLIO PATCHERY HO! ########## */
41
+ #include "ruby.h"
42
+ #if defined(HAVE_RUBY_THREAD_H)
43
+ #include "ruby/thread.h"
44
+ #endif
45
+ /* ######################################## */
46
+
40
47
  /* this big block deduces configuration from config.h */
41
48
  #ifndef EV_STANDALONE
42
49
  # ifdef EV_CONFIG_H
@@ -45,6 +52,12 @@
45
52
  # include "config.h"
46
53
  # endif
47
54
 
55
+ # if HAVE_FLOOR
56
+ # ifndef EV_USE_FLOOR
57
+ # define EV_USE_FLOOR 1
58
+ # endif
59
+ # endif
60
+
48
61
  # if HAVE_CLOCK_SYSCALL
49
62
  # ifndef EV_USE_CLOCK_SYSCALL
50
63
  # define EV_USE_CLOCK_SYSCALL 1
@@ -55,7 +68,7 @@
55
68
  # define EV_USE_MONOTONIC 1
56
69
  # endif
57
70
  # endif
58
- # elif !defined(EV_USE_CLOCK_SYSCALL)
71
+ # elif !defined EV_USE_CLOCK_SYSCALL
59
72
  # define EV_USE_CLOCK_SYSCALL 0
60
73
  # endif
61
74
 
@@ -101,7 +114,7 @@
101
114
  # undef EV_USE_POLL
102
115
  # define EV_USE_POLL 0
103
116
  # endif
104
-
117
+
105
118
  # if HAVE_EPOLL_CTL && HAVE_SYS_EPOLL_H
106
119
  # ifndef EV_USE_EPOLL
107
120
  # define EV_USE_EPOLL EV_FEATURE_BACKENDS
@@ -110,7 +123,7 @@
110
123
  # undef EV_USE_EPOLL
111
124
  # define EV_USE_EPOLL 0
112
125
  # endif
113
-
126
+
114
127
  # if HAVE_KQUEUE && HAVE_SYS_EVENT_H
115
128
  # ifndef EV_USE_KQUEUE
116
129
  # define EV_USE_KQUEUE EV_FEATURE_BACKENDS
@@ -119,7 +132,7 @@
119
132
  # undef EV_USE_KQUEUE
120
133
  # define EV_USE_KQUEUE 0
121
134
  # endif
122
-
135
+
123
136
  # if HAVE_PORT_H && HAVE_PORT_CREATE
124
137
  # ifndef EV_USE_PORT
125
138
  # define EV_USE_PORT EV_FEATURE_BACKENDS
@@ -155,10 +168,9 @@
155
168
  # undef EV_USE_EVENTFD
156
169
  # define EV_USE_EVENTFD 0
157
170
  # endif
158
-
171
+
159
172
  #endif
160
173
 
161
- #include <math.h>
162
174
  #include <stdlib.h>
163
175
  #include <string.h>
164
176
  #include <fcntl.h>
@@ -180,7 +192,16 @@
180
192
  # include "ev.h"
181
193
  #endif
182
194
 
183
- EV_CPP(extern "C" {)
195
+ #if EV_NO_THREADS
196
+ # undef EV_NO_SMP
197
+ # define EV_NO_SMP 1
198
+ # undef ECB_NO_THREADS
199
+ # define ECB_NO_THREADS 1
200
+ #endif
201
+ #if EV_NO_SMP
202
+ # undef EV_NO_SMP
203
+ # define ECB_NO_SMP 1
204
+ #endif
184
205
 
185
206
  #ifndef _WIN32
186
207
  # include <sys/time.h>
@@ -189,6 +210,8 @@ EV_CPP(extern "C" {)
189
210
  #else
190
211
  # include <io.h>
191
212
  # define WIN32_LEAN_AND_MEAN
213
+ # define FD_SETSIZE 1024
214
+ # include <winsock2.h>
192
215
  # include <windows.h>
193
216
  # ifndef EV_SELECT_IS_WINSOCKET
194
217
  # define EV_SELECT_IS_WINSOCKET 1
@@ -207,43 +230,53 @@ EV_CPP(extern "C" {)
207
230
  /* this block tries to deduce configuration from header-defined symbols and defaults */
208
231
 
209
232
  /* try to deduce the maximum number of signals on this platform */
210
- #if defined (EV_NSIG)
233
+ #if defined EV_NSIG
211
234
  /* use what's provided */
212
- #elif defined (NSIG)
235
+ #elif defined NSIG
213
236
  # define EV_NSIG (NSIG)
214
- #elif defined(_NSIG)
237
+ #elif defined _NSIG
215
238
  # define EV_NSIG (_NSIG)
216
- #elif defined (SIGMAX)
239
+ #elif defined SIGMAX
217
240
  # define EV_NSIG (SIGMAX+1)
218
- #elif defined (SIG_MAX)
241
+ #elif defined SIG_MAX
219
242
  # define EV_NSIG (SIG_MAX+1)
220
- #elif defined (_SIG_MAX)
243
+ #elif defined _SIG_MAX
221
244
  # define EV_NSIG (_SIG_MAX+1)
222
- #elif defined (MAXSIG)
245
+ #elif defined MAXSIG
223
246
  # define EV_NSIG (MAXSIG+1)
224
- #elif defined (MAX_SIG)
247
+ #elif defined MAX_SIG
225
248
  # define EV_NSIG (MAX_SIG+1)
226
- #elif defined (SIGARRAYSIZE)
249
+ #elif defined SIGARRAYSIZE
227
250
  # define EV_NSIG (SIGARRAYSIZE) /* Assume ary[SIGARRAYSIZE] */
228
- #elif defined (_sys_nsig)
251
+ #elif defined _sys_nsig
229
252
  # define EV_NSIG (_sys_nsig) /* Solaris 2.5 */
230
253
  #else
231
- # error "unable to find value for NSIG, please report"
232
- /* to make it compile regardless, just remove the above line, */
233
- /* but consider reporting it, too! :) */
234
- # define EV_NSIG 65
254
+ # define EV_NSIG (8 * sizeof (sigset_t) + 1)
255
+ #endif
256
+
257
+ #ifndef EV_USE_FLOOR
258
+ # define EV_USE_FLOOR 0
235
259
  #endif
236
260
 
237
261
  #ifndef EV_USE_CLOCK_SYSCALL
238
- # if __linux && __GLIBC__ >= 2
262
+ # if __linux && __GLIBC__ == 2 && __GLIBC_MINOR__ < 17
239
263
  # define EV_USE_CLOCK_SYSCALL EV_FEATURE_OS
240
264
  # else
241
265
  # define EV_USE_CLOCK_SYSCALL 0
242
266
  # endif
243
267
  #endif
244
268
 
269
+ #if !(_POSIX_TIMERS > 0)
270
+ # ifndef EV_USE_MONOTONIC
271
+ # define EV_USE_MONOTONIC 0
272
+ # endif
273
+ # ifndef EV_USE_REALTIME
274
+ # define EV_USE_REALTIME 0
275
+ # endif
276
+ #endif
277
+
245
278
  #ifndef EV_USE_MONOTONIC
246
- # if defined (_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
279
+ # if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
247
280
  # define EV_USE_MONOTONIC EV_FEATURE_OS
248
281
  # else
249
282
  # define EV_USE_MONOTONIC 0
@@ -340,10 +373,26 @@ EV_CPP(extern "C" {)
340
373
  # define EV_HEAP_CACHE_AT EV_FEATURE_DATA
341
374
  #endif
342
375
 
376
+ #ifdef ANDROID
377
+ /* supposedly, android doesn't typedef fd_mask */
378
+ # undef EV_USE_SELECT
379
+ # define EV_USE_SELECT 0
380
+ /* supposedly, we need to include syscall.h, not sys/syscall.h, so just disable */
381
+ # undef EV_USE_CLOCK_SYSCALL
382
+ # define EV_USE_CLOCK_SYSCALL 0
383
+ #endif
384
+
385
+ /* aix's poll.h seems to cause lots of trouble */
386
+ #ifdef _AIX
387
+ /* AIX has a completely broken poll.h header */
388
+ # undef EV_USE_POLL
389
+ # define EV_USE_POLL 0
390
+ #endif
391
+
343
392
  /* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */
344
393
  /* which makes programs even slower. might work on other unices, too. */
345
394
  #if EV_USE_CLOCK_SYSCALL
346
- # include <syscall.h>
395
+ # include <sys/syscall.h>
347
396
  # ifdef SYS_clock_gettime
348
397
  # define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts))
349
398
  # undef EV_USE_MONOTONIC
@@ -356,12 +405,6 @@ EV_CPP(extern "C" {)
356
405
 
357
406
  /* this block fixes any misconfiguration where we know we run into trouble otherwise */
358
407
 
359
- #ifdef _AIX
360
- /* AIX has a completely broken poll.h header */
361
- # undef EV_USE_POLL
362
- # define EV_USE_POLL 0
363
- #endif
364
-
365
408
  #ifndef CLOCK_MONOTONIC
366
409
  # undef EV_USE_MONOTONIC
367
410
  # define EV_USE_MONOTONIC 0
@@ -378,7 +421,8 @@ EV_CPP(extern "C" {)
378
421
  #endif
379
422
 
380
423
  #if !EV_USE_NANOSLEEP
381
- # ifndef _WIN32
424
+ /* hp-ux has it in sys/time.h, which we unconditionally include above */
425
+ # if !defined _WIN32 && !defined __hpux
382
426
  # include <sys/select.h>
383
427
  # endif
384
428
  #endif
@@ -393,10 +437,6 @@ EV_CPP(extern "C" {)
393
437
  # endif
394
438
  #endif
395
439
 
396
- #if EV_SELECT_IS_WINSOCKET
397
- # include <winsock.h>
398
- #endif
399
-
400
440
  #if EV_USE_EVENTFD
401
441
  /* our minimum requirement is glibc 2.7 which has the stub, but not the header */
402
442
  # include <stdint.h>
@@ -444,14 +484,11 @@ struct signalfd_siginfo
444
484
  #endif
445
485
 
446
486
  /*
447
- * This is used to avoid floating point rounding problems.
448
- * It is added to ev_rt_now when scheduling periodics
449
- * to ensure progress, time-wise, even when rounding
450
- * errors are against us.
487
+ * This is used to work around floating point rounding problems.
451
488
  * This value is good at least till the year 4000.
452
- * Better solutions welcome.
453
489
  */
454
- #define TIME_EPSILON 0.0001220703125 /* 1/8192 */
490
+ #define MIN_INTERVAL 0.0001220703125 /* 1/2**13, good till 4000 */
491
+ /*#define MIN_INTERVAL 0.00000095367431640625 /* 1/2**20, good till 2200 */
455
492
 
456
493
  #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
457
494
  #define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */
@@ -459,25 +496,1048 @@ struct signalfd_siginfo
459
496
  #define EV_TV_SET(tv,t) do { tv.tv_sec = (long)t; tv.tv_usec = (long)((t - tv.tv_sec) * 1e6); } while (0)
460
497
  #define EV_TS_SET(ts,t) do { ts.tv_sec = (long)t; ts.tv_nsec = (long)((t - ts.tv_sec) * 1e9); } while (0)
461
498
 
462
- #if __GNUC__ >= 4
463
- # define expect(expr,value) __builtin_expect ((expr),(value))
464
- # define noinline __attribute__ ((noinline))
499
+ /* the following is ecb.h embedded into libev - use update_ev_c to update from an external copy */
500
+ /* ECB.H BEGIN */
501
+ /*
502
+ * libecb - http://software.schmorp.de/pkg/libecb
503
+ *
504
+ * Copyright (©) 2009-2015 Marc Alexander Lehmann <libecb@schmorp.de>
505
+ * Copyright (©) 2011 Emanuele Giaquinta
506
+ * All rights reserved.
507
+ *
508
+ * Redistribution and use in source and binary forms, with or without modifica-
509
+ * tion, are permitted provided that the following conditions are met:
510
+ *
511
+ * 1. Redistributions of source code must retain the above copyright notice,
512
+ * this list of conditions and the following disclaimer.
513
+ *
514
+ * 2. Redistributions in binary form must reproduce the above copyright
515
+ * notice, this list of conditions and the following disclaimer in the
516
+ * documentation and/or other materials provided with the distribution.
517
+ *
518
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
519
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
520
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
521
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
522
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
523
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
524
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
525
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
526
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
527
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
528
+ *
529
+ * Alternatively, the contents of this file may be used under the terms of
530
+ * the GNU General Public License ("GPL") version 2 or any later version,
531
+ * in which case the provisions of the GPL are applicable instead of
532
+ * the above. If you wish to allow the use of your version of this file
533
+ * only under the terms of the GPL and not to allow others to use your
534
+ * version of this file under the BSD license, indicate your decision
535
+ * by deleting the provisions above and replace them with the notice
536
+ * and other provisions required by the GPL. If you do not delete the
537
+ * provisions above, a recipient may use your version of this file under
538
+ * either the BSD or the GPL.
539
+ */
540
+
541
+ #ifndef ECB_H
542
+ #define ECB_H
543
+
544
+ /* 16 bits major, 16 bits minor */
545
+ #define ECB_VERSION 0x00010005
546
+
547
+ #ifdef _WIN32
548
+ typedef signed char int8_t;
549
+ typedef unsigned char uint8_t;
550
+ typedef signed short int16_t;
551
+ typedef unsigned short uint16_t;
552
+ typedef signed int int32_t;
553
+ typedef unsigned int uint32_t;
554
+ #if __GNUC__
555
+ typedef signed long long int64_t;
556
+ typedef unsigned long long uint64_t;
557
+ #else /* _MSC_VER || __BORLANDC__ */
558
+ typedef signed __int64 int64_t;
559
+ typedef unsigned __int64 uint64_t;
560
+ #endif
561
+ #ifdef _WIN64
562
+ #define ECB_PTRSIZE 8
563
+ typedef uint64_t uintptr_t;
564
+ typedef int64_t intptr_t;
565
+ #else
566
+ #define ECB_PTRSIZE 4
567
+ typedef uint32_t uintptr_t;
568
+ typedef int32_t intptr_t;
569
+ #endif
465
570
  #else
466
- # define expect(expr,value) (expr)
467
- # define noinline
468
- # if __STDC_VERSION__ < 199901L && __GNUC__ < 2
469
- # define inline
470
- # endif
571
+ #include <inttypes.h>
572
+ #if (defined INTPTR_MAX ? INTPTR_MAX : ULONG_MAX) > 0xffffffffU
573
+ #define ECB_PTRSIZE 8
574
+ #else
575
+ #define ECB_PTRSIZE 4
576
+ #endif
577
+ #endif
578
+
579
+ #define ECB_GCC_AMD64 (__amd64 || __amd64__ || __x86_64 || __x86_64__)
580
+ #define ECB_MSVC_AMD64 (_M_AMD64 || _M_X64)
581
+
582
+ /* work around x32 idiocy by defining proper macros */
583
+ #if ECB_GCC_AMD64 || ECB_MSVC_AMD64
584
+ #if _ILP32
585
+ #define ECB_AMD64_X32 1
586
+ #else
587
+ #define ECB_AMD64 1
588
+ #endif
589
+ #endif
590
+
591
+ /* many compilers define _GNUC_ to some versions but then only implement
592
+ * what their idiot authors think are the "more important" extensions,
593
+ * causing enormous grief in return for some better fake benchmark numbers.
594
+ * or so.
595
+ * we try to detect these and simply assume they are not gcc - if they have
596
+ * an issue with that they should have done it right in the first place.
597
+ */
598
+ #if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__
599
+ #define ECB_GCC_VERSION(major,minor) 0
600
+ #else
601
+ #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
602
+ #endif
603
+
604
+ #define ECB_CLANG_VERSION(major,minor) (__clang_major__ > (major) || (__clang_major__ == (major) && __clang_minor__ >= (minor)))
605
+
606
+ #if __clang__ && defined __has_builtin
607
+ #define ECB_CLANG_BUILTIN(x) __has_builtin (x)
608
+ #else
609
+ #define ECB_CLANG_BUILTIN(x) 0
610
+ #endif
611
+
612
+ #if __clang__ && defined __has_extension
613
+ #define ECB_CLANG_EXTENSION(x) __has_extension (x)
614
+ #else
615
+ #define ECB_CLANG_EXTENSION(x) 0
616
+ #endif
617
+
618
+ #define ECB_CPP (__cplusplus+0)
619
+ #define ECB_CPP11 (__cplusplus >= 201103L)
620
+
621
+ #if ECB_CPP
622
+ #define ECB_C 0
623
+ #define ECB_STDC_VERSION 0
624
+ #else
625
+ #define ECB_C 1
626
+ #define ECB_STDC_VERSION __STDC_VERSION__
627
+ #endif
628
+
629
+ #define ECB_C99 (ECB_STDC_VERSION >= 199901L)
630
+ #define ECB_C11 (ECB_STDC_VERSION >= 201112L)
631
+
632
+ #if ECB_CPP
633
+ #define ECB_EXTERN_C extern "C"
634
+ #define ECB_EXTERN_C_BEG ECB_EXTERN_C {
635
+ #define ECB_EXTERN_C_END }
636
+ #else
637
+ #define ECB_EXTERN_C extern
638
+ #define ECB_EXTERN_C_BEG
639
+ #define ECB_EXTERN_C_END
640
+ #endif
641
+
642
+ /*****************************************************************************/
643
+
644
+ /* ECB_NO_THREADS - ecb is not used by multiple threads, ever */
645
+ /* ECB_NO_SMP - ecb might be used in multiple threads, but only on a single cpu */
646
+
647
+ #if ECB_NO_THREADS
648
+ #define ECB_NO_SMP 1
649
+ #endif
650
+
651
+ #if ECB_NO_SMP
652
+ #define ECB_MEMORY_FENCE do { } while (0)
653
+ #endif
654
+
655
+ /* http://www-01.ibm.com/support/knowledgecenter/SSGH3R_13.1.0/com.ibm.xlcpp131.aix.doc/compiler_ref/compiler_builtins.html */
656
+ #if __xlC__ && ECB_CPP
657
+ #include <builtins.h>
658
+ #endif
659
+
660
+ #if 1400 <= _MSC_VER
661
+ #include <intrin.h> /* fence functions _ReadBarrier, also bit search functions _BitScanReverse */
662
+ #endif
663
+
664
+ #ifndef ECB_MEMORY_FENCE
665
+ #if ECB_GCC_VERSION(2,5) || defined __INTEL_COMPILER || (__llvm__ && __GNUC__) || __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
666
+ #if __i386 || __i386__
667
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("lock; orb $0, -1(%%esp)" : : : "memory")
668
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory")
669
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("")
670
+ #elif ECB_GCC_AMD64
671
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mfence" : : : "memory")
672
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory")
673
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("")
674
+ #elif __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__
675
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory")
676
+ #elif defined __ARM_ARCH_2__ \
677
+ || defined __ARM_ARCH_3__ || defined __ARM_ARCH_3M__ \
678
+ || defined __ARM_ARCH_4__ || defined __ARM_ARCH_4T__ \
679
+ || defined __ARM_ARCH_5__ || defined __ARM_ARCH_5E__ \
680
+ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__ \
681
+ || defined __ARM_ARCH_5TEJ__
682
+ /* should not need any, unless running old code on newer cpu - arm doesn't support that */
683
+ #elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ \
684
+ || defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__ \
685
+ || defined __ARM_ARCH_6T2__
686
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,5" : : "r" (0) : "memory")
687
+ #elif defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \
688
+ || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
689
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory")
690
+ #elif __aarch64__
691
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb ish" : : : "memory")
692
+ #elif (__sparc || __sparc__) && !(__sparc_v8__ || defined __sparcv8)
693
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad" : : : "memory")
694
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory")
695
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore")
696
+ #elif defined __s390__ || defined __s390x__
697
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("bcr 15,0" : : : "memory")
698
+ #elif defined __mips__
699
+ /* GNU/Linux emulates sync on mips1 architectures, so we force its use */
700
+ /* anybody else who still uses mips1 is supposed to send in their version, with detection code. */
701
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ (".set mips2; sync; .set mips0" : : : "memory")
702
+ #elif defined __alpha__
703
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mb" : : : "memory")
704
+ #elif defined __hppa__
705
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory")
706
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("")
707
+ #elif defined __ia64__
708
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mf" : : : "memory")
709
+ #elif defined __m68k__
710
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory")
711
+ #elif defined __m88k__
712
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("tb1 0,%%r0,128" : : : "memory")
713
+ #elif defined __sh__
714
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory")
715
+ #endif
716
+ #endif
717
+ #endif
718
+
719
+ #ifndef ECB_MEMORY_FENCE
720
+ #if ECB_GCC_VERSION(4,7)
721
+ /* see comment below (stdatomic.h) about the C11 memory model. */
722
+ #define ECB_MEMORY_FENCE __atomic_thread_fence (__ATOMIC_SEQ_CST)
723
+ #define ECB_MEMORY_FENCE_ACQUIRE __atomic_thread_fence (__ATOMIC_ACQUIRE)
724
+ #define ECB_MEMORY_FENCE_RELEASE __atomic_thread_fence (__ATOMIC_RELEASE)
725
+
726
+ #elif ECB_CLANG_EXTENSION(c_atomic)
727
+ /* see comment below (stdatomic.h) about the C11 memory model. */
728
+ #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST)
729
+ #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE)
730
+ #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE)
731
+
732
+ #elif ECB_GCC_VERSION(4,4) || defined __INTEL_COMPILER || defined __clang__
733
+ #define ECB_MEMORY_FENCE __sync_synchronize ()
734
+ #elif _MSC_VER >= 1500 /* VC++ 2008 */
735
+ /* apparently, microsoft broke all the memory barrier stuff in Visual Studio 2008... */
736
+ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
737
+ #define ECB_MEMORY_FENCE _ReadWriteBarrier (); MemoryBarrier()
738
+ #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier (); MemoryBarrier() /* according to msdn, _ReadBarrier is not a load fence */
739
+ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier (); MemoryBarrier()
740
+ #elif _MSC_VER >= 1400 /* VC++ 2005 */
741
+ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
742
+ #define ECB_MEMORY_FENCE _ReadWriteBarrier ()
743
+ #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier () /* according to msdn, _ReadBarrier is not a load fence */
744
+ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier ()
745
+ #elif defined _WIN32
746
+ #include <WinNT.h>
747
+ #define ECB_MEMORY_FENCE MemoryBarrier () /* actually just xchg on x86... scary */
748
+ #elif __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
749
+ #include <mbarrier.h>
750
+ #define ECB_MEMORY_FENCE __machine_rw_barrier ()
751
+ #define ECB_MEMORY_FENCE_ACQUIRE __machine_r_barrier ()
752
+ #define ECB_MEMORY_FENCE_RELEASE __machine_w_barrier ()
753
+ #elif __xlC__
754
+ #define ECB_MEMORY_FENCE __sync ()
755
+ #endif
756
+ #endif
757
+
758
+ #ifndef ECB_MEMORY_FENCE
759
+ #if ECB_C11 && !defined __STDC_NO_ATOMICS__
760
+ /* we assume that these memory fences work on all variables/all memory accesses, */
761
+ /* not just C11 atomics and atomic accesses */
762
+ #include <stdatomic.h>
763
+ /* Unfortunately, neither gcc 4.7 nor clang 3.1 generate any instructions for */
764
+ /* any fence other than seq_cst, which isn't very efficient for us. */
765
+ /* Why that is, we don't know - either the C11 memory model is quite useless */
766
+ /* for most usages, or gcc and clang have a bug */
767
+ /* I *currently* lean towards the latter, and inefficiently implement */
768
+ /* all three of ecb's fences as a seq_cst fence */
769
+ /* Update, gcc-4.8 generates mfence for all c++ fences, but nothing */
770
+ /* for all __atomic_thread_fence's except seq_cst */
771
+ #define ECB_MEMORY_FENCE atomic_thread_fence (memory_order_seq_cst)
772
+ #endif
773
+ #endif
774
+
775
+ #ifndef ECB_MEMORY_FENCE
776
+ #if !ECB_AVOID_PTHREADS
777
+ /*
778
+ * if you get undefined symbol references to pthread_mutex_lock,
779
+ * or failure to find pthread.h, then you should implement
780
+ * the ECB_MEMORY_FENCE operations for your cpu/compiler
781
+ * OR provide pthread.h and link against the posix thread library
782
+ * of your system.
783
+ */
784
+ #include <pthread.h>
785
+ #define ECB_NEEDS_PTHREADS 1
786
+ #define ECB_MEMORY_FENCE_NEEDS_PTHREADS 1
787
+
788
+ static pthread_mutex_t ecb_mf_lock = PTHREAD_MUTEX_INITIALIZER;
789
+ #define ECB_MEMORY_FENCE do { pthread_mutex_lock (&ecb_mf_lock); pthread_mutex_unlock (&ecb_mf_lock); } while (0)
790
+ #endif
791
+ #endif
792
+
793
+ #if !defined ECB_MEMORY_FENCE_ACQUIRE && defined ECB_MEMORY_FENCE
794
+ #define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
795
+ #endif
796
+
797
+ #if !defined ECB_MEMORY_FENCE_RELEASE && defined ECB_MEMORY_FENCE
798
+ #define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
799
+ #endif
800
+
801
+ /*****************************************************************************/
802
+
803
+ #if ECB_CPP
804
+ #define ecb_inline static inline
805
+ #elif ECB_GCC_VERSION(2,5)
806
+ #define ecb_inline static __inline__
807
+ #elif ECB_C99
808
+ #define ecb_inline static inline
809
+ #else
810
+ #define ecb_inline static
811
+ #endif
812
+
813
+ #if ECB_GCC_VERSION(3,3)
814
+ #define ecb_restrict __restrict__
815
+ #elif ECB_C99
816
+ #define ecb_restrict restrict
817
+ #else
818
+ #define ecb_restrict
819
+ #endif
820
+
821
+ typedef int ecb_bool;
822
+
823
+ #define ECB_CONCAT_(a, b) a ## b
824
+ #define ECB_CONCAT(a, b) ECB_CONCAT_(a, b)
825
+ #define ECB_STRINGIFY_(a) # a
826
+ #define ECB_STRINGIFY(a) ECB_STRINGIFY_(a)
827
+ #define ECB_STRINGIFY_EXPR(expr) ((expr), ECB_STRINGIFY_ (expr))
828
+
829
+ #define ecb_function_ ecb_inline
830
+
831
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_VERSION(2,8)
832
+ #define ecb_attribute(attrlist) __attribute__ (attrlist)
833
+ #else
834
+ #define ecb_attribute(attrlist)
835
+ #endif
836
+
837
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_constant_p)
838
+ #define ecb_is_constant(expr) __builtin_constant_p (expr)
839
+ #else
840
+ /* possible C11 impl for integral types
841
+ typedef struct ecb_is_constant_struct ecb_is_constant_struct;
842
+ #define ecb_is_constant(expr) _Generic ((1 ? (struct ecb_is_constant_struct *)0 : (void *)((expr) - (expr)), ecb_is_constant_struct *: 0, default: 1)) */
843
+
844
+ #define ecb_is_constant(expr) 0
845
+ #endif
846
+
847
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_expect)
848
+ #define ecb_expect(expr,value) __builtin_expect ((expr),(value))
849
+ #else
850
+ #define ecb_expect(expr,value) (expr)
851
+ #endif
852
+
853
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_prefetch)
854
+ #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality)
855
+ #else
856
+ #define ecb_prefetch(addr,rw,locality)
857
+ #endif
858
+
859
+ /* no emulation for ecb_decltype */
860
+ #if ECB_CPP11
861
+ // older implementations might have problems with decltype(x)::type, work around it
862
+ template<class T> struct ecb_decltype_t { typedef T type; };
863
+ #define ecb_decltype(x) ecb_decltype_t<decltype (x)>::type
864
+ #elif ECB_GCC_VERSION(3,0) || ECB_CLANG_VERSION(2,8)
865
+ #define ecb_decltype(x) __typeof__ (x)
866
+ #endif
867
+
868
+ #if _MSC_VER >= 1300
869
+ #define ecb_deprecated __declspec (deprecated)
870
+ #else
871
+ #define ecb_deprecated ecb_attribute ((__deprecated__))
872
+ #endif
873
+
874
+ #if _MSC_VER >= 1500
875
+ #define ecb_deprecated_message(msg) __declspec (deprecated (msg))
876
+ #elif ECB_GCC_VERSION(4,5)
877
+ #define ecb_deprecated_message(msg) ecb_attribute ((__deprecated__ (msg))
878
+ #else
879
+ #define ecb_deprecated_message(msg) ecb_deprecated
880
+ #endif
881
+
882
+ #if _MSC_VER >= 1400
883
+ #define ecb_noinline __declspec (noinline)
884
+ #else
885
+ #define ecb_noinline ecb_attribute ((__noinline__))
886
+ #endif
887
+
888
+ #define ecb_unused ecb_attribute ((__unused__))
889
+ #define ecb_const ecb_attribute ((__const__))
890
+ #define ecb_pure ecb_attribute ((__pure__))
891
+
892
+ #if ECB_C11 || __IBMC_NORETURN
893
+ /* http://www-01.ibm.com/support/knowledgecenter/SSGH3R_13.1.0/com.ibm.xlcpp131.aix.doc/language_ref/noreturn.html */
894
+ #define ecb_noreturn _Noreturn
895
+ #elif ECB_CPP11
896
+ #define ecb_noreturn [[noreturn]]
897
+ #elif _MSC_VER >= 1200
898
+ /* http://msdn.microsoft.com/en-us/library/k6ktzx3s.aspx */
899
+ #define ecb_noreturn __declspec (noreturn)
900
+ #else
901
+ #define ecb_noreturn ecb_attribute ((__noreturn__))
902
+ #endif
903
+
904
+ #if ECB_GCC_VERSION(4,3)
905
+ #define ecb_artificial ecb_attribute ((__artificial__))
906
+ #define ecb_hot ecb_attribute ((__hot__))
907
+ #define ecb_cold ecb_attribute ((__cold__))
908
+ #else
909
+ #define ecb_artificial
910
+ #define ecb_hot
911
+ #define ecb_cold
912
+ #endif
913
+
914
+ /* put around conditional expressions if you are very sure that the */
915
+ /* expression is mostly true or mostly false. note that these return */
916
+ /* booleans, not the expression. */
917
+ #define ecb_expect_false(expr) ecb_expect (!!(expr), 0)
918
+ #define ecb_expect_true(expr) ecb_expect (!!(expr), 1)
919
+ /* for compatibility to the rest of the world */
920
+ #define ecb_likely(expr) ecb_expect_true (expr)
921
+ #define ecb_unlikely(expr) ecb_expect_false (expr)
922
+
923
+ /* count trailing zero bits and count # of one bits */
924
+ #if ECB_GCC_VERSION(3,4) \
925
+ || (ECB_CLANG_BUILTIN(__builtin_clz) && ECB_CLANG_BUILTIN(__builtin_clzll) \
926
+ && ECB_CLANG_BUILTIN(__builtin_ctz) && ECB_CLANG_BUILTIN(__builtin_ctzll) \
927
+ && ECB_CLANG_BUILTIN(__builtin_popcount))
928
+ /* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */
929
+ #define ecb_ld32(x) (__builtin_clz (x) ^ 31)
930
+ #define ecb_ld64(x) (__builtin_clzll (x) ^ 63)
931
+ #define ecb_ctz32(x) __builtin_ctz (x)
932
+ #define ecb_ctz64(x) __builtin_ctzll (x)
933
+ #define ecb_popcount32(x) __builtin_popcount (x)
934
+ /* no popcountll */
935
+ #else
936
+ ecb_function_ ecb_const int ecb_ctz32 (uint32_t x);
937
+ ecb_function_ ecb_const int
938
+ ecb_ctz32 (uint32_t x)
939
+ {
940
+ #if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM)
941
+ unsigned long r;
942
+ _BitScanForward (&r, x);
943
+ return (int)r;
944
+ #else
945
+ int r = 0;
946
+
947
+ x &= ~x + 1; /* this isolates the lowest bit */
948
+
949
+ #if ECB_branchless_on_i386
950
+ r += !!(x & 0xaaaaaaaa) << 0;
951
+ r += !!(x & 0xcccccccc) << 1;
952
+ r += !!(x & 0xf0f0f0f0) << 2;
953
+ r += !!(x & 0xff00ff00) << 3;
954
+ r += !!(x & 0xffff0000) << 4;
955
+ #else
956
+ if (x & 0xaaaaaaaa) r += 1;
957
+ if (x & 0xcccccccc) r += 2;
958
+ if (x & 0xf0f0f0f0) r += 4;
959
+ if (x & 0xff00ff00) r += 8;
960
+ if (x & 0xffff0000) r += 16;
961
+ #endif
962
+
963
+ return r;
964
+ #endif
965
+ }
966
+
967
+ ecb_function_ ecb_const int ecb_ctz64 (uint64_t x);
968
+ ecb_function_ ecb_const int
969
+ ecb_ctz64 (uint64_t x)
970
+ {
971
+ #if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM)
972
+ unsigned long r;
973
+ _BitScanForward64 (&r, x);
974
+ return (int)r;
975
+ #else
976
+ int shift = x & 0xffffffff ? 0 : 32;
977
+ return ecb_ctz32 (x >> shift) + shift;
978
+ #endif
979
+ }
980
+
981
+ ecb_function_ ecb_const int ecb_popcount32 (uint32_t x);
982
+ ecb_function_ ecb_const int
983
+ ecb_popcount32 (uint32_t x)
984
+ {
985
+ x -= (x >> 1) & 0x55555555;
986
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
987
+ x = ((x >> 4) + x) & 0x0f0f0f0f;
988
+ x *= 0x01010101;
989
+
990
+ return x >> 24;
991
+ }
992
+
993
+ ecb_function_ ecb_const int ecb_ld32 (uint32_t x);
994
+ ecb_function_ ecb_const int ecb_ld32 (uint32_t x)
995
+ {
996
+ #if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM)
997
+ unsigned long r;
998
+ _BitScanReverse (&r, x);
999
+ return (int)r;
1000
+ #else
1001
+ int r = 0;
1002
+
1003
+ if (x >> 16) { x >>= 16; r += 16; }
1004
+ if (x >> 8) { x >>= 8; r += 8; }
1005
+ if (x >> 4) { x >>= 4; r += 4; }
1006
+ if (x >> 2) { x >>= 2; r += 2; }
1007
+ if (x >> 1) { r += 1; }
1008
+
1009
+ return r;
1010
+ #endif
1011
+ }
1012
+
1013
+ ecb_function_ ecb_const int ecb_ld64 (uint64_t x);
1014
+ ecb_function_ ecb_const int ecb_ld64 (uint64_t x)
1015
+ {
1016
+ #if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM)
1017
+ unsigned long r;
1018
+ _BitScanReverse64 (&r, x);
1019
+ return (int)r;
1020
+ #else
1021
+ int r = 0;
1022
+
1023
+ if (x >> 32) { x >>= 32; r += 32; }
1024
+
1025
+ return r + ecb_ld32 (x);
1026
+ #endif
1027
+ }
1028
+ #endif
1029
+
1030
+ ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x);
1031
+ ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x) { return !(x & (x - 1)); }
1032
+ ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x);
1033
+ ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x) { return !(x & (x - 1)); }
1034
+
1035
+ ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x);
1036
+ ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x)
1037
+ {
1038
+ return ( (x * 0x0802U & 0x22110U)
1039
+ | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16;
1040
+ }
1041
+
1042
+ ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x);
1043
+ ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x)
1044
+ {
1045
+ x = ((x >> 1) & 0x5555) | ((x & 0x5555) << 1);
1046
+ x = ((x >> 2) & 0x3333) | ((x & 0x3333) << 2);
1047
+ x = ((x >> 4) & 0x0f0f) | ((x & 0x0f0f) << 4);
1048
+ x = ( x >> 8 ) | ( x << 8);
1049
+
1050
+ return x;
1051
+ }
1052
+
1053
+ ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x);
1054
+ ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x)
1055
+ {
1056
+ x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
1057
+ x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
1058
+ x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);
1059
+ x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);
1060
+ x = ( x >> 16 ) | ( x << 16);
1061
+
1062
+ return x;
1063
+ }
1064
+
1065
+ /* popcount64 is only available on 64 bit cpus as gcc builtin */
1066
+ /* so for this version we are lazy */
1067
+ ecb_function_ ecb_const int ecb_popcount64 (uint64_t x);
1068
+ ecb_function_ ecb_const int
1069
+ ecb_popcount64 (uint64_t x)
1070
+ {
1071
+ return ecb_popcount32 (x) + ecb_popcount32 (x >> 32);
1072
+ }
1073
+
1074
+ ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count);
1075
+ ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count);
1076
+ ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count);
1077
+ ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count);
1078
+ ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count);
1079
+ ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count);
1080
+ ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count);
1081
+ ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count);
1082
+
1083
+ ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); }
1084
+ ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); }
1085
+ ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); }
1086
+ ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); }
1087
+ ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); }
1088
+ ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); }
1089
+ ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); }
1090
+ ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); }
1091
+
1092
+ #if ECB_GCC_VERSION(4,3) || (ECB_CLANG_BUILTIN(__builtin_bswap32) && ECB_CLANG_BUILTIN(__builtin_bswap64))
1093
+ #if ECB_GCC_VERSION(4,8) || ECB_CLANG_BUILTIN(__builtin_bswap16)
1094
+ #define ecb_bswap16(x) __builtin_bswap16 (x)
1095
+ #else
1096
+ #define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16)
1097
+ #endif
1098
+ #define ecb_bswap32(x) __builtin_bswap32 (x)
1099
+ #define ecb_bswap64(x) __builtin_bswap64 (x)
1100
+ #elif _MSC_VER
1101
+ #include <stdlib.h>
1102
+ #define ecb_bswap16(x) ((uint16_t)_byteswap_ushort ((uint16_t)(x)))
1103
+ #define ecb_bswap32(x) ((uint32_t)_byteswap_ulong ((uint32_t)(x)))
1104
+ #define ecb_bswap64(x) ((uint64_t)_byteswap_uint64 ((uint64_t)(x)))
1105
+ #else
1106
+ ecb_function_ ecb_const uint16_t ecb_bswap16 (uint16_t x);
1107
+ ecb_function_ ecb_const uint16_t
1108
+ ecb_bswap16 (uint16_t x)
1109
+ {
1110
+ return ecb_rotl16 (x, 8);
1111
+ }
1112
+
1113
+ ecb_function_ ecb_const uint32_t ecb_bswap32 (uint32_t x);
1114
+ ecb_function_ ecb_const uint32_t
1115
+ ecb_bswap32 (uint32_t x)
1116
+ {
1117
+ return (((uint32_t)ecb_bswap16 (x)) << 16) | ecb_bswap16 (x >> 16);
1118
+ }
1119
+
1120
+ ecb_function_ ecb_const uint64_t ecb_bswap64 (uint64_t x);
1121
+ ecb_function_ ecb_const uint64_t
1122
+ ecb_bswap64 (uint64_t x)
1123
+ {
1124
+ return (((uint64_t)ecb_bswap32 (x)) << 32) | ecb_bswap32 (x >> 32);
1125
+ }
1126
+ #endif
1127
+
1128
+ #if ECB_GCC_VERSION(4,5) || ECB_CLANG_BUILTIN(__builtin_unreachable)
1129
+ #define ecb_unreachable() __builtin_unreachable ()
1130
+ #else
1131
+ /* this seems to work fine, but gcc always emits a warning for it :/ */
1132
+ ecb_inline ecb_noreturn void ecb_unreachable (void);
1133
+ ecb_inline ecb_noreturn void ecb_unreachable (void) { }
1134
+ #endif
1135
+
1136
+ /* try to tell the compiler that some condition is definitely true */
1137
+ #define ecb_assume(cond) if (!(cond)) ecb_unreachable (); else 0
1138
+
1139
+ ecb_inline ecb_const uint32_t ecb_byteorder_helper (void);
1140
+ ecb_inline ecb_const uint32_t
1141
+ ecb_byteorder_helper (void)
1142
+ {
1143
+ /* the union code still generates code under pressure in gcc, */
1144
+ /* but less than using pointers, and always seems to */
1145
+ /* successfully return a constant. */
1146
+ /* the reason why we have this horrible preprocessor mess */
1147
+ /* is to avoid it in all cases, at least on common architectures */
1148
+ /* or when using a recent enough gcc version (>= 4.6) */
1149
+ #if (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
1150
+ || ((__i386 || __i386__ || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64) && !__VOS__)
1151
+ #define ECB_LITTLE_ENDIAN 1
1152
+ return 0x44332211;
1153
+ #elif (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) \
1154
+ || ((__AARCH64EB__ || __MIPSEB__ || __ARMEB__) && !__VOS__)
1155
+ #define ECB_BIG_ENDIAN 1
1156
+ return 0x11223344;
1157
+ #else
1158
+ union
1159
+ {
1160
+ uint8_t c[4];
1161
+ uint32_t u;
1162
+ } u = { 0x11, 0x22, 0x33, 0x44 };
1163
+ return u.u;
1164
+ #endif
1165
+ }
1166
+
1167
+ ecb_inline ecb_const ecb_bool ecb_big_endian (void);
1168
+ ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11223344; }
1169
+ ecb_inline ecb_const ecb_bool ecb_little_endian (void);
1170
+ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44332211; }
1171
+
1172
+ #if ECB_GCC_VERSION(3,0) || ECB_C99
1173
+ #define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0))
1174
+ #else
1175
+ #define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n)))
471
1176
  #endif
472
1177
 
473
- #define expect_false(expr) expect ((expr) != 0, 0)
474
- #define expect_true(expr) expect ((expr) != 0, 1)
475
- #define inline_size static inline
1178
+ #if ECB_CPP
1179
+ template<typename T>
1180
+ static inline T ecb_div_rd (T val, T div)
1181
+ {
1182
+ return val < 0 ? - ((-val + div - 1) / div) : (val ) / div;
1183
+ }
1184
+ template<typename T>
1185
+ static inline T ecb_div_ru (T val, T div)
1186
+ {
1187
+ return val < 0 ? - ((-val ) / div) : (val + div - 1) / div;
1188
+ }
1189
+ #else
1190
+ #define ecb_div_rd(val,div) ((val) < 0 ? - ((-(val) + (div) - 1) / (div)) : ((val) ) / (div))
1191
+ #define ecb_div_ru(val,div) ((val) < 0 ? - ((-(val) ) / (div)) : ((val) + (div) - 1) / (div))
1192
+ #endif
1193
+
1194
+ #if ecb_cplusplus_does_not_suck
1195
+ /* does not work for local types (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm) */
1196
+ template<typename T, int N>
1197
+ static inline int ecb_array_length (const T (&arr)[N])
1198
+ {
1199
+ return N;
1200
+ }
1201
+ #else
1202
+ #define ecb_array_length(name) (sizeof (name) / sizeof (name [0]))
1203
+ #endif
1204
+
1205
+ ecb_function_ ecb_const uint32_t ecb_binary16_to_binary32 (uint32_t x);
1206
+ ecb_function_ ecb_const uint32_t
1207
+ ecb_binary16_to_binary32 (uint32_t x)
1208
+ {
1209
+ unsigned int s = (x & 0x8000) << (31 - 15);
1210
+ int e = (x >> 10) & 0x001f;
1211
+ unsigned int m = x & 0x03ff;
1212
+
1213
+ if (ecb_expect_false (e == 31))
1214
+ /* infinity or NaN */
1215
+ e = 255 - (127 - 15);
1216
+ else if (ecb_expect_false (!e))
1217
+ {
1218
+ if (ecb_expect_true (!m))
1219
+ /* zero, handled by code below by forcing e to 0 */
1220
+ e = 0 - (127 - 15);
1221
+ else
1222
+ {
1223
+ /* subnormal, renormalise */
1224
+ unsigned int s = 10 - ecb_ld32 (m);
1225
+
1226
+ m = (m << s) & 0x3ff; /* mask implicit bit */
1227
+ e -= s - 1;
1228
+ }
1229
+ }
1230
+
1231
+ /* e and m now are normalised, or zero, (or inf or nan) */
1232
+ e += 127 - 15;
1233
+
1234
+ return s | (e << 23) | (m << (23 - 10));
1235
+ }
1236
+
1237
+ ecb_function_ ecb_const uint16_t ecb_binary32_to_binary16 (uint32_t x);
1238
+ ecb_function_ ecb_const uint16_t
1239
+ ecb_binary32_to_binary16 (uint32_t x)
1240
+ {
1241
+ unsigned int s = (x >> 16) & 0x00008000; /* sign bit, the easy part */
1242
+ unsigned int e = ((x >> 23) & 0x000000ff) - (127 - 15); /* the desired exponent */
1243
+ unsigned int m = x & 0x007fffff;
1244
+
1245
+ x &= 0x7fffffff;
1246
+
1247
+ /* if it's within range of binary16 normals, use fast path */
1248
+ if (ecb_expect_true (0x38800000 <= x && x <= 0x477fefff))
1249
+ {
1250
+ /* mantissa round-to-even */
1251
+ m += 0x00000fff + ((m >> (23 - 10)) & 1);
1252
+
1253
+ /* handle overflow */
1254
+ if (ecb_expect_false (m >= 0x00800000))
1255
+ {
1256
+ m >>= 1;
1257
+ e += 1;
1258
+ }
1259
+
1260
+ return s | (e << 10) | (m >> (23 - 10));
1261
+ }
1262
+
1263
+ /* handle large numbers and infinity */
1264
+ if (ecb_expect_true (0x477fefff < x && x <= 0x7f800000))
1265
+ return s | 0x7c00;
1266
+
1267
+ /* handle zero, subnormals and small numbers */
1268
+ if (ecb_expect_true (x < 0x38800000))
1269
+ {
1270
+ /* zero */
1271
+ if (ecb_expect_true (!x))
1272
+ return s;
1273
+
1274
+ /* handle subnormals */
1275
+
1276
+ /* too small, will be zero */
1277
+ if (e < (14 - 24)) /* might not be sharp, but is good enough */
1278
+ return s;
1279
+
1280
+ m |= 0x00800000; /* make implicit bit explicit */
1281
+
1282
+ /* very tricky - we need to round to the nearest e (+10) bit value */
1283
+ {
1284
+ unsigned int bits = 14 - e;
1285
+ unsigned int half = (1 << (bits - 1)) - 1;
1286
+ unsigned int even = (m >> bits) & 1;
1287
+
1288
+ /* if this overflows, we will end up with a normalised number */
1289
+ m = (m + half + even) >> bits;
1290
+ }
1291
+
1292
+ return s | m;
1293
+ }
1294
+
1295
+ /* handle NaNs, preserve leftmost nan bits, but make sure we don't turn them into infinities */
1296
+ m >>= 13;
1297
+
1298
+ return s | 0x7c00 | m | !m;
1299
+ }
1300
+
1301
+ /*******************************************************************************/
1302
+ /* floating point stuff, can be disabled by defining ECB_NO_LIBM */
1303
+
1304
+ /* basically, everything uses "ieee pure-endian" floating point numbers */
1305
+ /* the only noteworthy exception is ancient armle, which uses order 43218765 */
1306
+ #if 0 \
1307
+ || __i386 || __i386__ \
1308
+ || ECB_GCC_AMD64 \
1309
+ || __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__ \
1310
+ || defined __s390__ || defined __s390x__ \
1311
+ || defined __mips__ \
1312
+ || defined __alpha__ \
1313
+ || defined __hppa__ \
1314
+ || defined __ia64__ \
1315
+ || defined __m68k__ \
1316
+ || defined __m88k__ \
1317
+ || defined __sh__ \
1318
+ || defined _M_IX86 || defined ECB_MSVC_AMD64 || defined _M_IA64 \
1319
+ || (defined __arm__ && (defined __ARM_EABI__ || defined __EABI__ || defined __VFP_FP__ || defined _WIN32_WCE || defined __ANDROID__)) \
1320
+ || defined __aarch64__
1321
+ #define ECB_STDFP 1
1322
+ #include <string.h> /* for memcpy */
1323
+ #else
1324
+ #define ECB_STDFP 0
1325
+ #endif
1326
+
1327
+ #ifndef ECB_NO_LIBM
1328
+
1329
+ #include <math.h> /* for frexp*, ldexp*, INFINITY, NAN */
1330
+
1331
+ /* only the oldest of old doesn't have this one. solaris. */
1332
+ #ifdef INFINITY
1333
+ #define ECB_INFINITY INFINITY
1334
+ #else
1335
+ #define ECB_INFINITY HUGE_VAL
1336
+ #endif
1337
+
1338
+ #ifdef NAN
1339
+ #define ECB_NAN NAN
1340
+ #else
1341
+ #define ECB_NAN ECB_INFINITY
1342
+ #endif
1343
+
1344
+ #if ECB_C99 || _XOPEN_VERSION >= 600 || _POSIX_VERSION >= 200112L
1345
+ #define ecb_ldexpf(x,e) ldexpf ((x), (e))
1346
+ #define ecb_frexpf(x,e) frexpf ((x), (e))
1347
+ #else
1348
+ #define ecb_ldexpf(x,e) (float) ldexp ((double) (x), (e))
1349
+ #define ecb_frexpf(x,e) (float) frexp ((double) (x), (e))
1350
+ #endif
1351
+
1352
+ /* convert a float to ieee single/binary32 */
1353
+ ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x);
1354
+ ecb_function_ ecb_const uint32_t
1355
+ ecb_float_to_binary32 (float x)
1356
+ {
1357
+ uint32_t r;
1358
+
1359
+ #if ECB_STDFP
1360
+ memcpy (&r, &x, 4);
1361
+ #else
1362
+ /* slow emulation, works for anything but -0 */
1363
+ uint32_t m;
1364
+ int e;
1365
+
1366
+ if (x == 0e0f ) return 0x00000000U;
1367
+ if (x > +3.40282346638528860e+38f) return 0x7f800000U;
1368
+ if (x < -3.40282346638528860e+38f) return 0xff800000U;
1369
+ if (x != x ) return 0x7fbfffffU;
1370
+
1371
+ m = ecb_frexpf (x, &e) * 0x1000000U;
1372
+
1373
+ r = m & 0x80000000U;
1374
+
1375
+ if (r)
1376
+ m = -m;
1377
+
1378
+ if (e <= -126)
1379
+ {
1380
+ m &= 0xffffffU;
1381
+ m >>= (-125 - e);
1382
+ e = -126;
1383
+ }
1384
+
1385
+ r |= (e + 126) << 23;
1386
+ r |= m & 0x7fffffU;
1387
+ #endif
1388
+
1389
+ return r;
1390
+ }
1391
+
1392
+ /* converts an ieee single/binary32 to a float */
1393
+ ecb_function_ ecb_const float ecb_binary32_to_float (uint32_t x);
1394
+ ecb_function_ ecb_const float
1395
+ ecb_binary32_to_float (uint32_t x)
1396
+ {
1397
+ float r;
1398
+
1399
+ #if ECB_STDFP
1400
+ memcpy (&r, &x, 4);
1401
+ #else
1402
+ /* emulation, only works for normals and subnormals and +0 */
1403
+ int neg = x >> 31;
1404
+ int e = (x >> 23) & 0xffU;
1405
+
1406
+ x &= 0x7fffffU;
1407
+
1408
+ if (e)
1409
+ x |= 0x800000U;
1410
+ else
1411
+ e = 1;
1412
+
1413
+ /* we distrust ldexpf a bit and do the 2**-24 scaling by an extra multiply */
1414
+ r = ecb_ldexpf (x * (0.5f / 0x800000U), e - 126);
1415
+
1416
+ r = neg ? -r : r;
1417
+ #endif
1418
+
1419
+ return r;
1420
+ }
1421
+
1422
+ /* convert a double to ieee double/binary64 */
1423
+ ecb_function_ ecb_const uint64_t ecb_double_to_binary64 (double x);
1424
+ ecb_function_ ecb_const uint64_t
1425
+ ecb_double_to_binary64 (double x)
1426
+ {
1427
+ uint64_t r;
1428
+
1429
+ #if ECB_STDFP
1430
+ memcpy (&r, &x, 8);
1431
+ #else
1432
+ /* slow emulation, works for anything but -0 */
1433
+ uint64_t m;
1434
+ int e;
1435
+
1436
+ if (x == 0e0 ) return 0x0000000000000000U;
1437
+ if (x > +1.79769313486231470e+308) return 0x7ff0000000000000U;
1438
+ if (x < -1.79769313486231470e+308) return 0xfff0000000000000U;
1439
+ if (x != x ) return 0X7ff7ffffffffffffU;
1440
+
1441
+ m = frexp (x, &e) * 0x20000000000000U;
1442
+
1443
+ r = m & 0x8000000000000000;;
1444
+
1445
+ if (r)
1446
+ m = -m;
1447
+
1448
+ if (e <= -1022)
1449
+ {
1450
+ m &= 0x1fffffffffffffU;
1451
+ m >>= (-1021 - e);
1452
+ e = -1022;
1453
+ }
1454
+
1455
+ r |= ((uint64_t)(e + 1022)) << 52;
1456
+ r |= m & 0xfffffffffffffU;
1457
+ #endif
1458
+
1459
+ return r;
1460
+ }
1461
+
1462
+ /* converts an ieee double/binary64 to a double */
1463
+ ecb_function_ ecb_const double ecb_binary64_to_double (uint64_t x);
1464
+ ecb_function_ ecb_const double
1465
+ ecb_binary64_to_double (uint64_t x)
1466
+ {
1467
+ double r;
1468
+
1469
+ #if ECB_STDFP
1470
+ memcpy (&r, &x, 8);
1471
+ #else
1472
+ /* emulation, only works for normals and subnormals and +0 */
1473
+ int neg = x >> 63;
1474
+ int e = (x >> 52) & 0x7ffU;
1475
+
1476
+ x &= 0xfffffffffffffU;
1477
+
1478
+ if (e)
1479
+ x |= 0x10000000000000U;
1480
+ else
1481
+ e = 1;
1482
+
1483
+ /* we distrust ldexp a bit and do the 2**-53 scaling by an extra multiply */
1484
+ r = ldexp (x * (0.5 / 0x10000000000000U), e - 1022);
1485
+
1486
+ r = neg ? -r : r;
1487
+ #endif
1488
+
1489
+ return r;
1490
+ }
1491
+
1492
+ /* convert a float to ieee half/binary16 */
1493
+ ecb_function_ ecb_const uint16_t ecb_float_to_binary16 (float x);
1494
+ ecb_function_ ecb_const uint16_t
1495
+ ecb_float_to_binary16 (float x)
1496
+ {
1497
+ return ecb_binary32_to_binary16 (ecb_float_to_binary32 (x));
1498
+ }
1499
+
1500
+ /* convert an ieee half/binary16 to float */
1501
+ ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x);
1502
+ ecb_function_ ecb_const float
1503
+ ecb_binary16_to_float (uint16_t x)
1504
+ {
1505
+ return ecb_binary32_to_float (ecb_binary16_to_binary32 (x));
1506
+ }
1507
+
1508
+ #endif
1509
+
1510
+ #endif
1511
+
1512
+ /* ECB.H END */
1513
+
1514
+ #if ECB_MEMORY_FENCE_NEEDS_PTHREADS
1515
+ /* if your architecture doesn't need memory fences, e.g. because it is
1516
+ * single-cpu/core, or if you use libev in a project that doesn't use libev
1517
+ * from multiple threads, then you can define ECB_AVOID_PTHREADS when compiling
1518
+ * libev, in which cases the memory fences become nops.
1519
+ * alternatively, you can remove this #error and link against libpthread,
1520
+ * which will then provide the memory fences.
1521
+ */
1522
+ # error "memory fences not defined for your architecture, please report"
1523
+ #endif
1524
+
1525
+ #ifndef ECB_MEMORY_FENCE
1526
+ # define ECB_MEMORY_FENCE do { } while (0)
1527
+ # define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
1528
+ # define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
1529
+ #endif
1530
+
1531
+ #define expect_false(cond) ecb_expect_false (cond)
1532
+ #define expect_true(cond) ecb_expect_true (cond)
1533
+ #define noinline ecb_noinline
1534
+
1535
+ #define inline_size ecb_inline
476
1536
 
477
1537
  #if EV_FEATURE_CODE
478
- # define inline_speed static inline
1538
+ # define inline_speed ecb_inline
479
1539
  #else
480
- # define inline_speed static noinline
1540
+ # define inline_speed noinline static
481
1541
  #endif
482
1542
 
483
1543
  #define NUMPRI (EV_MAXPRI - EV_MINPRI + 1)
@@ -508,18 +1568,67 @@ static EV_ATOMIC_T have_realtime; /* did clock_gettime (CLOCK_REALTIME) work? */
508
1568
  static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */
509
1569
  #endif
510
1570
 
511
- #ifndef EV_FD_TO_WIN32_HANDLE
512
- # define EV_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd)
513
- #endif
514
- #ifndef EV_WIN32_HANDLE_TO_FD
515
- # define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0)
516
- #endif
517
- #ifndef EV_WIN32_CLOSE_FD
518
- # define EV_WIN32_CLOSE_FD(fd) close (fd)
519
- #endif
1571
+ #ifndef EV_FD_TO_WIN32_HANDLE
1572
+ # define EV_FD_TO_WIN32_HANDLE(fd) _get_osfhandle (fd)
1573
+ #endif
1574
+ #ifndef EV_WIN32_HANDLE_TO_FD
1575
+ # define EV_WIN32_HANDLE_TO_FD(handle) _open_osfhandle (handle, 0)
1576
+ #endif
1577
+ #ifndef EV_WIN32_CLOSE_FD
1578
+ # define EV_WIN32_CLOSE_FD(fd) close (fd)
1579
+ #endif
1580
+
1581
+ #ifdef _WIN32
1582
+ # include "ev_win32.c"
1583
+ #endif
1584
+
1585
+ /*****************************************************************************/
1586
+
1587
+ /* define a suitable floor function (only used by periodics atm) */
1588
+
1589
+ #if EV_USE_FLOOR
1590
+ # include <math.h>
1591
+ # define ev_floor(v) floor (v)
1592
+ #else
1593
+
1594
+ #include <float.h>
1595
+
1596
+ /* a floor() replacement function, should be independent of ev_tstamp type */
1597
+ noinline
1598
+ static ev_tstamp
1599
+ ev_floor (ev_tstamp v)
1600
+ {
1601
+ /* the choice of shift factor is not terribly important */
1602
+ #if FLT_RADIX != 2 /* assume FLT_RADIX == 10 */
1603
+ const ev_tstamp shift = sizeof (unsigned long) >= 8 ? 10000000000000000000. : 1000000000.;
1604
+ #else
1605
+ const ev_tstamp shift = sizeof (unsigned long) >= 8 ? 18446744073709551616. : 4294967296.;
1606
+ #endif
1607
+
1608
+ /* argument too large for an unsigned long? */
1609
+ if (expect_false (v >= shift))
1610
+ {
1611
+ ev_tstamp f;
1612
+
1613
+ if (v == v - 1.)
1614
+ return v; /* very large number */
1615
+
1616
+ f = shift * ev_floor (v * (1. / shift));
1617
+ return f + ev_floor (v - f);
1618
+ }
1619
+
1620
+ /* special treatment for negative args? */
1621
+ if (expect_false (v < 0.))
1622
+ {
1623
+ ev_tstamp f = -ev_floor (-v);
1624
+
1625
+ return f - (f == v ? 0 : 1);
1626
+ }
1627
+
1628
+ /* fits into an unsigned long */
1629
+ return (unsigned long)v;
1630
+ }
520
1631
 
521
- #ifdef _WIN32
522
- # include "ev_win32.c"
523
1632
  #endif
524
1633
 
525
1634
  /*****************************************************************************/
@@ -528,7 +1637,8 @@ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work?
528
1637
  # include <sys/utsname.h>
529
1638
  #endif
530
1639
 
531
- static unsigned int noinline
1640
+ noinline ecb_cold
1641
+ static unsigned int
532
1642
  ev_linux_version (void)
533
1643
  {
534
1644
  #ifdef __linux
@@ -567,22 +1677,25 @@ ev_linux_version (void)
567
1677
  /*****************************************************************************/
568
1678
 
569
1679
  #if EV_AVOID_STDIO
570
- static void noinline
1680
+ noinline ecb_cold
1681
+ static void
571
1682
  ev_printerr (const char *msg)
572
1683
  {
573
1684
  write (STDERR_FILENO, msg, strlen (msg));
574
1685
  }
575
1686
  #endif
576
1687
 
577
- static void (*syserr_cb)(const char *msg);
1688
+ static void (*syserr_cb)(const char *msg) EV_THROW;
578
1689
 
1690
+ ecb_cold
579
1691
  void
580
- ev_set_syserr_cb (void (*cb)(const char *msg))
1692
+ ev_set_syserr_cb (void (*cb)(const char *msg) EV_THROW) EV_THROW
581
1693
  {
582
1694
  syserr_cb = cb;
583
1695
  }
584
1696
 
585
- static void noinline
1697
+ noinline ecb_cold
1698
+ static void
586
1699
  ev_syserr (const char *msg)
587
1700
  {
588
1701
  if (!msg)
@@ -605,14 +1718,13 @@ ev_syserr (const char *msg)
605
1718
  }
606
1719
 
607
1720
  static void *
608
- ev_realloc_emul (void *ptr, long size)
1721
+ ev_realloc_emul (void *ptr, long size) EV_THROW
609
1722
  {
610
- #if __GLIBC__
611
- return realloc (ptr, size);
612
- #else
613
1723
  /* some systems, notably openbsd and darwin, fail to properly
614
1724
  * implement realloc (x, 0) (as required by both ansi c-89 and
615
1725
  * the single unix specification, so work around them here.
1726
+ * recently, also (at least) fedora and debian started breaking it,
1727
+ * despite documenting it otherwise.
616
1728
  */
617
1729
 
618
1730
  if (size)
@@ -620,13 +1732,13 @@ ev_realloc_emul (void *ptr, long size)
620
1732
 
621
1733
  free (ptr);
622
1734
  return 0;
623
- #endif
624
1735
  }
625
1736
 
626
- static void *(*alloc)(void *ptr, long size) = ev_realloc_emul;
1737
+ static void *(*alloc)(void *ptr, long size) EV_THROW = ev_realloc_emul;
627
1738
 
1739
+ ecb_cold
628
1740
  void
629
- ev_set_allocator (void *(*cb)(void *ptr, long size))
1741
+ ev_set_allocator (void *(*cb)(void *ptr, long size) EV_THROW) EV_THROW
630
1742
  {
631
1743
  alloc = cb;
632
1744
  }
@@ -724,11 +1836,11 @@ typedef struct
724
1836
  #include "ev_wrap.h"
725
1837
 
726
1838
  static struct ev_loop default_loop_struct;
727
- struct ev_loop *ev_default_loop_ptr;
1839
+ EV_API_DECL struct ev_loop *ev_default_loop_ptr = 0; /* needs to be initialised to make it a definition despite extern */
728
1840
 
729
1841
  #else
730
1842
 
731
- ev_tstamp ev_rt_now;
1843
+ EV_API_DECL ev_tstamp ev_rt_now = 0; /* needs to be initialised to make it a definition despite extern */
732
1844
  #define VAR(name,decl) static decl;
733
1845
  #include "ev_vars.h"
734
1846
  #undef VAR
@@ -753,7 +1865,7 @@ typedef struct
753
1865
 
754
1866
  #ifndef EV_HAVE_EV_TIME
755
1867
  ev_tstamp
756
- ev_time (void)
1868
+ ev_time (void) EV_THROW
757
1869
  {
758
1870
  #if EV_USE_REALTIME
759
1871
  if (expect_true (have_realtime))
@@ -787,14 +1899,14 @@ get_clock (void)
787
1899
 
788
1900
  #if EV_MULTIPLICITY
789
1901
  ev_tstamp
790
- ev_now (EV_P)
1902
+ ev_now (EV_P) EV_THROW
791
1903
  {
792
1904
  return ev_rt_now;
793
1905
  }
794
1906
  #endif
795
1907
 
796
1908
  void
797
- ev_sleep (ev_tstamp delay)
1909
+ ev_sleep (ev_tstamp delay) EV_THROW
798
1910
  {
799
1911
  if (delay > 0.)
800
1912
  {
@@ -803,7 +1915,7 @@ ev_sleep (ev_tstamp delay)
803
1915
 
804
1916
  EV_TS_SET (ts, delay);
805
1917
  nanosleep (&ts, 0);
806
- #elif defined(_WIN32)
1918
+ #elif defined _WIN32
807
1919
  Sleep ((unsigned long)(delay * 1e3));
808
1920
  #else
809
1921
  struct timeval tv;
@@ -832,7 +1944,7 @@ array_nextsize (int elem, int cur, int cnt)
832
1944
  ncur <<= 1;
833
1945
  while (cnt > ncur);
834
1946
 
835
- /* if size is large, round to MALLOC_ROUND - 4 * longs to accomodate malloc overhead */
1947
+ /* if size is large, round to MALLOC_ROUND - 4 * longs to accommodate malloc overhead */
836
1948
  if (elem * ncur > MALLOC_ROUND - sizeof (void *) * 4)
837
1949
  {
838
1950
  ncur *= elem;
@@ -844,7 +1956,8 @@ array_nextsize (int elem, int cur, int cnt)
844
1956
  return ncur;
845
1957
  }
846
1958
 
847
- static noinline void *
1959
+ noinline ecb_cold
1960
+ static void *
848
1961
  array_realloc (int elem, void *base, int *cur, int cnt)
849
1962
  {
850
1963
  *cur = array_nextsize (elem, *cur, cnt);
@@ -857,7 +1970,7 @@ array_realloc (int elem, void *base, int *cur, int cnt)
857
1970
  #define array_needsize(type,base,cur,cnt,init) \
858
1971
  if (expect_false ((cnt) > (cur))) \
859
1972
  { \
860
- int ocur_ = (cur); \
1973
+ ecb_unused int ocur_ = (cur); \
861
1974
  (base) = (type *)array_realloc \
862
1975
  (sizeof (type), (base), &(cur), (cnt)); \
863
1976
  init ((base) + (ocur_), (cur) - ocur_); \
@@ -879,13 +1992,15 @@ array_realloc (int elem, void *base, int *cur, int cnt)
879
1992
  /*****************************************************************************/
880
1993
 
881
1994
  /* dummy callback for pending events */
882
- static void noinline
1995
+ noinline
1996
+ static void
883
1997
  pendingcb (EV_P_ ev_prepare *w, int revents)
884
1998
  {
885
1999
  }
886
2000
 
887
- void noinline
888
- ev_feed_event (EV_P_ void *w, int revents)
2001
+ noinline
2002
+ void
2003
+ ev_feed_event (EV_P_ void *w, int revents) EV_THROW
889
2004
  {
890
2005
  W w_ = (W)w;
891
2006
  int pri = ABSPRI (w_);
@@ -899,6 +2014,8 @@ ev_feed_event (EV_P_ void *w, int revents)
899
2014
  pendings [pri][w_->pending - 1].w = w_;
900
2015
  pendings [pri][w_->pending - 1].events = revents;
901
2016
  }
2017
+
2018
+ pendingpri = NUMPRI - 1;
902
2019
  }
903
2020
 
904
2021
  inline_speed void
@@ -954,7 +2071,7 @@ fd_event (EV_P_ int fd, int revents)
954
2071
  }
955
2072
 
956
2073
  void
957
- ev_feed_fd_event (EV_P_ int fd, int revents)
2074
+ ev_feed_fd_event (EV_P_ int fd, int revents) EV_THROW
958
2075
  {
959
2076
  if (fd >= 0 && fd < anfdmax)
960
2077
  fd_event_nocheck (EV_A_ fd, revents);
@@ -967,6 +2084,31 @@ fd_reify (EV_P)
967
2084
  {
968
2085
  int i;
969
2086
 
2087
+ #if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP
2088
+ for (i = 0; i < fdchangecnt; ++i)
2089
+ {
2090
+ int fd = fdchanges [i];
2091
+ ANFD *anfd = anfds + fd;
2092
+
2093
+ if (anfd->reify & EV__IOFDSET && anfd->head)
2094
+ {
2095
+ SOCKET handle = EV_FD_TO_WIN32_HANDLE (fd);
2096
+
2097
+ if (handle != anfd->handle)
2098
+ {
2099
+ unsigned long arg;
2100
+
2101
+ assert (("libev: only socket fds supported in this configuration", ioctlsocket (handle, FIONREAD, &arg) == 0));
2102
+
2103
+ /* handle changed, but fd didn't - we need to do it in two steps */
2104
+ backend_modify (EV_A_ fd, anfd->events, 0);
2105
+ anfd->events = 0;
2106
+ anfd->handle = handle;
2107
+ }
2108
+ }
2109
+ }
2110
+ #endif
2111
+
970
2112
  for (i = 0; i < fdchangecnt; ++i)
971
2113
  {
972
2114
  int fd = fdchanges [i];
@@ -978,16 +2120,6 @@ fd_reify (EV_P)
978
2120
 
979
2121
  anfd->reify = 0;
980
2122
 
981
- #if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP
982
- if (o_reify & EV__IOFDSET)
983
- {
984
- unsigned long arg;
985
- anfd->handle = EV_FD_TO_WIN32_HANDLE (fd);
986
- assert (("libev: only socket fds supported in this configuration", ioctlsocket (anfd->handle, FIONREAD, &arg) == 0));
987
- printf ("oi %d %x\n", fd, anfd->handle);//D
988
- }
989
- #endif
990
-
991
2123
  /*if (expect_true (o_reify & EV_ANFD_REIFY)) probably a deoptimisation */
992
2124
  {
993
2125
  anfd->events = 0;
@@ -1007,7 +2139,8 @@ fd_reify (EV_P)
1007
2139
  }
1008
2140
 
1009
2141
  /* something about the given fd changed */
1010
- inline_size void
2142
+ inline_size
2143
+ void
1011
2144
  fd_change (EV_P_ int fd, int flags)
1012
2145
  {
1013
2146
  unsigned char reify = anfds [fd].reify;
@@ -1022,7 +2155,7 @@ fd_change (EV_P_ int fd, int flags)
1022
2155
  }
1023
2156
 
1024
2157
  /* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */
1025
- inline_speed void
2158
+ inline_speed ecb_cold void
1026
2159
  fd_kill (EV_P_ int fd)
1027
2160
  {
1028
2161
  ev_io *w;
@@ -1035,7 +2168,7 @@ fd_kill (EV_P_ int fd)
1035
2168
  }
1036
2169
 
1037
2170
  /* check whether the given fd is actually valid, for error recovery */
1038
- inline_size int
2171
+ inline_size ecb_cold int
1039
2172
  fd_valid (int fd)
1040
2173
  {
1041
2174
  #ifdef _WIN32
@@ -1046,7 +2179,8 @@ fd_valid (int fd)
1046
2179
  }
1047
2180
 
1048
2181
  /* called on EBADF to verify fds */
1049
- static void noinline
2182
+ noinline ecb_cold
2183
+ static void
1050
2184
  fd_ebadf (EV_P)
1051
2185
  {
1052
2186
  int fd;
@@ -1058,7 +2192,8 @@ fd_ebadf (EV_P)
1058
2192
  }
1059
2193
 
1060
2194
  /* called on ENOMEM in select/poll to kill some fds and retry */
1061
- static void noinline
2195
+ noinline ecb_cold
2196
+ static void
1062
2197
  fd_enomem (EV_P)
1063
2198
  {
1064
2199
  int fd;
@@ -1072,7 +2207,8 @@ fd_enomem (EV_P)
1072
2207
  }
1073
2208
 
1074
2209
  /* usually called after fork if backend needs to re-arm all fds from scratch */
1075
- static void noinline
2210
+ noinline
2211
+ static void
1076
2212
  fd_rearm_all (EV_P)
1077
2213
  {
1078
2214
  int fd;
@@ -1192,7 +2328,7 @@ downheap (ANHE *heap, int N, int k)
1192
2328
 
1193
2329
  heap [k] = heap [c];
1194
2330
  ev_active (ANHE_w (heap [k])) = k;
1195
-
2331
+
1196
2332
  k = c;
1197
2333
  }
1198
2334
 
@@ -1263,62 +2399,95 @@ static ANSIG signals [EV_NSIG - 1];
1263
2399
 
1264
2400
  #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
1265
2401
 
1266
- static void noinline
2402
+ noinline ecb_cold
2403
+ static void
1267
2404
  evpipe_init (EV_P)
1268
2405
  {
1269
2406
  if (!ev_is_active (&pipe_w))
1270
2407
  {
2408
+ int fds [2];
2409
+
1271
2410
  # if EV_USE_EVENTFD
1272
- evfd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
1273
- if (evfd < 0 && errno == EINVAL)
1274
- evfd = eventfd (0, 0);
2411
+ fds [0] = -1;
2412
+ fds [1] = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
2413
+ if (fds [1] < 0 && errno == EINVAL)
2414
+ fds [1] = eventfd (0, 0);
1275
2415
 
1276
- if (evfd >= 0)
2416
+ if (fds [1] < 0)
2417
+ # endif
1277
2418
  {
1278
- evpipe [0] = -1;
1279
- fd_intern (evfd); /* doing it twice doesn't hurt */
1280
- ev_io_set (&pipe_w, evfd, EV_READ);
2419
+ while (pipe (fds))
2420
+ ev_syserr ("(libev) error creating signal/async pipe");
2421
+
2422
+ fd_intern (fds [0]);
1281
2423
  }
2424
+
2425
+ evpipe [0] = fds [0];
2426
+
2427
+ if (evpipe [1] < 0)
2428
+ evpipe [1] = fds [1]; /* first call, set write fd */
1282
2429
  else
1283
- # endif
1284
2430
  {
1285
- while (pipe (evpipe))
1286
- ev_syserr ("(libev) error creating signal/async pipe");
2431
+ /* on subsequent calls, do not change evpipe [1] */
2432
+ /* so that evpipe_write can always rely on its value. */
2433
+ /* this branch does not do anything sensible on windows, */
2434
+ /* so must not be executed on windows */
1287
2435
 
1288
- fd_intern (evpipe [0]);
1289
- fd_intern (evpipe [1]);
1290
- ev_io_set (&pipe_w, evpipe [0], EV_READ);
2436
+ dup2 (fds [1], evpipe [1]);
2437
+ close (fds [1]);
1291
2438
  }
1292
2439
 
2440
+ fd_intern (evpipe [1]);
2441
+
2442
+ ev_io_set (&pipe_w, evpipe [0] < 0 ? evpipe [1] : evpipe [0], EV_READ);
1293
2443
  ev_io_start (EV_A_ &pipe_w);
1294
2444
  ev_unref (EV_A); /* watcher should not keep loop alive */
1295
2445
  }
1296
2446
  }
1297
2447
 
1298
- inline_size void
2448
+ inline_speed void
1299
2449
  evpipe_write (EV_P_ EV_ATOMIC_T *flag)
1300
2450
  {
1301
- if (!*flag)
2451
+ ECB_MEMORY_FENCE; /* push out the write before this function was called, acquire flag */
2452
+
2453
+ if (expect_true (*flag))
2454
+ return;
2455
+
2456
+ *flag = 1;
2457
+ ECB_MEMORY_FENCE_RELEASE; /* make sure flag is visible before the wakeup */
2458
+
2459
+ pipe_write_skipped = 1;
2460
+
2461
+ ECB_MEMORY_FENCE; /* make sure pipe_write_skipped is visible before we check pipe_write_wanted */
2462
+
2463
+ if (pipe_write_wanted)
1302
2464
  {
1303
- int old_errno = errno; /* save errno because write might clobber it */
1304
- char dummy;
2465
+ int old_errno;
2466
+
2467
+ pipe_write_skipped = 0;
2468
+ ECB_MEMORY_FENCE_RELEASE;
1305
2469
 
1306
- *flag = 1;
2470
+ old_errno = errno; /* save errno because write will clobber it */
1307
2471
 
1308
2472
  #if EV_USE_EVENTFD
1309
- if (evfd >= 0)
2473
+ if (evpipe [0] < 0)
1310
2474
  {
1311
2475
  uint64_t counter = 1;
1312
- write (evfd, &counter, sizeof (uint64_t));
2476
+ write (evpipe [1], &counter, sizeof (uint64_t));
1313
2477
  }
1314
2478
  else
1315
2479
  #endif
1316
- /* win32 people keep sending patches that change this write() to send() */
1317
- /* and then run away. but send() is wrong, it wants a socket handle on win32 */
1318
- /* so when you think this write should be a send instead, please find out */
1319
- /* where your send() is from - it's definitely not the microsoft send, and */
1320
- /* tell me. thank you. */
1321
- write (evpipe [1], &dummy, 1);
2480
+ {
2481
+ #ifdef _WIN32
2482
+ WSABUF buf;
2483
+ DWORD sent;
2484
+ buf.buf = (char *)&buf;
2485
+ buf.len = 1;
2486
+ WSASend (EV_FD_TO_WIN32_HANDLE (evpipe [1]), &buf, 1, &sent, 0, 0, 0);
2487
+ #else
2488
+ write (evpipe [1], &(evpipe [1]), 1);
2489
+ #endif
2490
+ }
1322
2491
 
1323
2492
  errno = old_errno;
1324
2493
  }
@@ -1331,38 +2500,60 @@ pipecb (EV_P_ ev_io *iow, int revents)
1331
2500
  {
1332
2501
  int i;
1333
2502
 
1334
- #if EV_USE_EVENTFD
1335
- if (evfd >= 0)
2503
+ if (revents & EV_READ)
1336
2504
  {
1337
- uint64_t counter;
1338
- read (evfd, &counter, sizeof (uint64_t));
1339
- }
1340
- else
2505
+ #if EV_USE_EVENTFD
2506
+ if (evpipe [0] < 0)
2507
+ {
2508
+ uint64_t counter;
2509
+ read (evpipe [1], &counter, sizeof (uint64_t));
2510
+ }
2511
+ else
1341
2512
  #endif
1342
- {
1343
- char dummy;
1344
- /* see discussion in evpipe_write when you think this read should be recv in win32 */
1345
- read (evpipe [0], &dummy, 1);
2513
+ {
2514
+ char dummy[4];
2515
+ #ifdef _WIN32
2516
+ WSABUF buf;
2517
+ DWORD recvd;
2518
+ DWORD flags = 0;
2519
+ buf.buf = dummy;
2520
+ buf.len = sizeof (dummy);
2521
+ WSARecv (EV_FD_TO_WIN32_HANDLE (evpipe [0]), &buf, 1, &recvd, &flags, 0, 0);
2522
+ #else
2523
+ read (evpipe [0], &dummy, sizeof (dummy));
2524
+ #endif
2525
+ }
1346
2526
  }
1347
2527
 
2528
+ pipe_write_skipped = 0;
2529
+
2530
+ ECB_MEMORY_FENCE; /* push out skipped, acquire flags */
2531
+
2532
+ #if EV_SIGNAL_ENABLE
1348
2533
  if (sig_pending)
1349
- {
2534
+ {
1350
2535
  sig_pending = 0;
1351
2536
 
2537
+ ECB_MEMORY_FENCE;
2538
+
1352
2539
  for (i = EV_NSIG - 1; i--; )
1353
2540
  if (expect_false (signals [i].pending))
1354
2541
  ev_feed_signal_event (EV_A_ i + 1);
1355
2542
  }
2543
+ #endif
1356
2544
 
1357
2545
  #if EV_ASYNC_ENABLE
1358
2546
  if (async_pending)
1359
2547
  {
1360
2548
  async_pending = 0;
1361
2549
 
2550
+ ECB_MEMORY_FENCE;
2551
+
1362
2552
  for (i = asynccnt; i--; )
1363
2553
  if (asyncs [i]->sent)
1364
2554
  {
1365
2555
  asyncs [i]->sent = 0;
2556
+ ECB_MEMORY_FENCE_RELEASE;
1366
2557
  ev_feed_event (EV_A_ asyncs [i], EV_ASYNC);
1367
2558
  }
1368
2559
  }
@@ -1371,27 +2562,39 @@ pipecb (EV_P_ ev_io *iow, int revents)
1371
2562
 
1372
2563
  /*****************************************************************************/
1373
2564
 
1374
- static void
1375
- ev_sighandler (int signum)
2565
+ void
2566
+ ev_feed_signal (int signum) EV_THROW
1376
2567
  {
1377
2568
  #if EV_MULTIPLICITY
1378
- EV_P = signals [signum - 1].loop;
2569
+ EV_P;
2570
+ ECB_MEMORY_FENCE_ACQUIRE;
2571
+ EV_A = signals [signum - 1].loop;
2572
+
2573
+ if (!EV_A)
2574
+ return;
1379
2575
  #endif
1380
2576
 
2577
+ signals [signum - 1].pending = 1;
2578
+ evpipe_write (EV_A_ &sig_pending);
2579
+ }
2580
+
2581
+ static void
2582
+ ev_sighandler (int signum)
2583
+ {
1381
2584
  #ifdef _WIN32
1382
2585
  signal (signum, ev_sighandler);
1383
2586
  #endif
1384
2587
 
1385
- signals [signum - 1].pending = 1;
1386
- evpipe_write (EV_A_ &sig_pending);
2588
+ ev_feed_signal (signum);
1387
2589
  }
1388
2590
 
1389
- void noinline
1390
- ev_feed_signal_event (EV_P_ int signum)
2591
+ noinline
2592
+ void
2593
+ ev_feed_signal_event (EV_P_ int signum) EV_THROW
1391
2594
  {
1392
2595
  WL w;
1393
2596
 
1394
- if (expect_false (signum <= 0 || signum > EV_NSIG))
2597
+ if (expect_false (signum <= 0 || signum >= EV_NSIG))
1395
2598
  return;
1396
2599
 
1397
2600
  --signum;
@@ -1405,6 +2608,7 @@ ev_feed_signal_event (EV_P_ int signum)
1405
2608
  #endif
1406
2609
 
1407
2610
  signals [signum].pending = 0;
2611
+ ECB_MEMORY_FENCE_RELEASE;
1408
2612
 
1409
2613
  for (w = signals [signum].head; w; w = w->next)
1410
2614
  ev_feed_event (EV_A_ (W)w, EV_SIGNAL);
@@ -1512,20 +2716,20 @@ childcb (EV_P_ ev_signal *sw, int revents)
1512
2716
  # include "ev_select.c"
1513
2717
  #endif
1514
2718
 
1515
- int
1516
- ev_version_major (void)
2719
+ ecb_cold int
2720
+ ev_version_major (void) EV_THROW
1517
2721
  {
1518
2722
  return EV_VERSION_MAJOR;
1519
2723
  }
1520
2724
 
1521
- int
1522
- ev_version_minor (void)
2725
+ ecb_cold int
2726
+ ev_version_minor (void) EV_THROW
1523
2727
  {
1524
2728
  return EV_VERSION_MINOR;
1525
2729
  }
1526
2730
 
1527
2731
  /* return true if we are running with elevated privileges and should ignore env variables */
1528
- int inline_size
2732
+ inline_size ecb_cold int
1529
2733
  enable_secure (void)
1530
2734
  {
1531
2735
  #ifdef _WIN32
@@ -1536,8 +2740,9 @@ enable_secure (void)
1536
2740
  #endif
1537
2741
  }
1538
2742
 
2743
+ ecb_cold
1539
2744
  unsigned int
1540
- ev_supported_backends (void)
2745
+ ev_supported_backends (void) EV_THROW
1541
2746
  {
1542
2747
  unsigned int flags = 0;
1543
2748
 
@@ -1546,12 +2751,13 @@ ev_supported_backends (void)
1546
2751
  if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL;
1547
2752
  if (EV_USE_POLL ) flags |= EVBACKEND_POLL;
1548
2753
  if (EV_USE_SELECT) flags |= EVBACKEND_SELECT;
1549
-
2754
+
1550
2755
  return flags;
1551
2756
  }
1552
2757
 
2758
+ ecb_cold
1553
2759
  unsigned int
1554
- ev_recommended_backends (void)
2760
+ ev_recommended_backends (void) EV_THROW
1555
2761
  {
1556
2762
  unsigned int flags = ev_supported_backends ();
1557
2763
 
@@ -1572,8 +2778,9 @@ ev_recommended_backends (void)
1572
2778
  return flags;
1573
2779
  }
1574
2780
 
2781
+ ecb_cold
1575
2782
  unsigned int
1576
- ev_embeddable_backends (void)
2783
+ ev_embeddable_backends (void) EV_THROW
1577
2784
  {
1578
2785
  int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT;
1579
2786
 
@@ -1585,54 +2792,56 @@ ev_embeddable_backends (void)
1585
2792
  }
1586
2793
 
1587
2794
  unsigned int
1588
- ev_backend (EV_P)
2795
+ ev_backend (EV_P) EV_THROW
1589
2796
  {
1590
2797
  return backend;
1591
2798
  }
1592
2799
 
1593
2800
  #if EV_FEATURE_API
1594
2801
  unsigned int
1595
- ev_iteration (EV_P)
2802
+ ev_iteration (EV_P) EV_THROW
1596
2803
  {
1597
2804
  return loop_count;
1598
2805
  }
1599
2806
 
1600
2807
  unsigned int
1601
- ev_depth (EV_P)
2808
+ ev_depth (EV_P) EV_THROW
1602
2809
  {
1603
2810
  return loop_depth;
1604
2811
  }
1605
2812
 
1606
2813
  void
1607
- ev_set_io_collect_interval (EV_P_ ev_tstamp interval)
2814
+ ev_set_io_collect_interval (EV_P_ ev_tstamp interval) EV_THROW
1608
2815
  {
1609
2816
  io_blocktime = interval;
1610
2817
  }
1611
2818
 
1612
2819
  void
1613
- ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval)
2820
+ ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) EV_THROW
1614
2821
  {
1615
2822
  timeout_blocktime = interval;
1616
2823
  }
1617
2824
 
1618
2825
  void
1619
- ev_set_userdata (EV_P_ void *data)
2826
+ ev_set_userdata (EV_P_ void *data) EV_THROW
1620
2827
  {
1621
2828
  userdata = data;
1622
2829
  }
1623
2830
 
1624
2831
  void *
1625
- ev_userdata (EV_P)
2832
+ ev_userdata (EV_P) EV_THROW
1626
2833
  {
1627
2834
  return userdata;
1628
2835
  }
1629
2836
 
1630
- void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P))
2837
+ void
2838
+ ev_set_invoke_pending_cb (EV_P_ ev_loop_callback invoke_pending_cb) EV_THROW
1631
2839
  {
1632
2840
  invoke_cb = invoke_pending_cb;
1633
2841
  }
1634
2842
 
1635
- void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P))
2843
+ void
2844
+ ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_THROW, void (*acquire)(EV_P) EV_THROW) EV_THROW
1636
2845
  {
1637
2846
  release_cb = release;
1638
2847
  acquire_cb = acquire;
@@ -1640,11 +2849,14 @@ void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P))
1640
2849
  #endif
1641
2850
 
1642
2851
  /* initialise a loop structure, must be zero-initialised */
1643
- static void noinline
1644
- loop_init (EV_P_ unsigned int flags)
2852
+ noinline ecb_cold
2853
+ static void
2854
+ loop_init (EV_P_ unsigned int flags) EV_THROW
1645
2855
  {
1646
2856
  if (!backend)
1647
2857
  {
2858
+ origflags = flags;
2859
+
1648
2860
  #if EV_USE_REALTIME
1649
2861
  if (!have_realtime)
1650
2862
  {
@@ -1676,30 +2888,34 @@ loop_init (EV_P_ unsigned int flags)
1676
2888
  && getenv ("LIBEV_FLAGS"))
1677
2889
  flags = atoi (getenv ("LIBEV_FLAGS"));
1678
2890
 
1679
- ev_rt_now = ev_time ();
1680
- mn_now = get_clock ();
1681
- now_floor = mn_now;
1682
- rtmn_diff = ev_rt_now - mn_now;
2891
+ ev_rt_now = ev_time ();
2892
+ mn_now = get_clock ();
2893
+ now_floor = mn_now;
2894
+ rtmn_diff = ev_rt_now - mn_now;
1683
2895
  #if EV_FEATURE_API
1684
- invoke_cb = ev_invoke_pending;
2896
+ invoke_cb = ev_invoke_pending;
1685
2897
  #endif
1686
2898
 
1687
- io_blocktime = 0.;
1688
- timeout_blocktime = 0.;
1689
- backend = 0;
1690
- backend_fd = -1;
1691
- sig_pending = 0;
2899
+ io_blocktime = 0.;
2900
+ timeout_blocktime = 0.;
2901
+ backend = 0;
2902
+ backend_fd = -1;
2903
+ sig_pending = 0;
1692
2904
  #if EV_ASYNC_ENABLE
1693
- async_pending = 0;
2905
+ async_pending = 0;
1694
2906
  #endif
2907
+ pipe_write_skipped = 0;
2908
+ pipe_write_wanted = 0;
2909
+ evpipe [0] = -1;
2910
+ evpipe [1] = -1;
1695
2911
  #if EV_USE_INOTIFY
1696
- fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
2912
+ fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
1697
2913
  #endif
1698
2914
  #if EV_USE_SIGNALFD
1699
- sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
2915
+ sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
1700
2916
  #endif
1701
2917
 
1702
- if (!(flags & 0x0000ffffU))
2918
+ if (!(flags & EVBACKEND_MASK))
1703
2919
  flags |= ev_recommended_backends ();
1704
2920
 
1705
2921
  #if EV_USE_IOCP
@@ -1731,6 +2947,7 @@ loop_init (EV_P_ unsigned int flags)
1731
2947
  }
1732
2948
 
1733
2949
  /* free up a loop structure */
2950
+ ecb_cold
1734
2951
  void
1735
2952
  ev_loop_destroy (EV_P)
1736
2953
  {
@@ -1752,7 +2969,7 @@ ev_loop_destroy (EV_P)
1752
2969
  #endif
1753
2970
 
1754
2971
  #if EV_CHILD_ENABLE
1755
- if (ev_is_active (&childev))
2972
+ if (ev_is_default_loop (EV_A) && ev_is_active (&childev))
1756
2973
  {
1757
2974
  ev_ref (EV_A); /* child watcher */
1758
2975
  ev_signal_stop (EV_A_ &childev);
@@ -1764,16 +2981,8 @@ ev_loop_destroy (EV_P)
1764
2981
  /*ev_ref (EV_A);*/
1765
2982
  /*ev_io_stop (EV_A_ &pipe_w);*/
1766
2983
 
1767
- #if EV_USE_EVENTFD
1768
- if (evfd >= 0)
1769
- close (evfd);
1770
- #endif
1771
-
1772
- if (evpipe [0] >= 0)
1773
- {
1774
- EV_WIN32_CLOSE_FD (evpipe [0]);
1775
- EV_WIN32_CLOSE_FD (evpipe [1]);
1776
- }
2984
+ if (evpipe [0] >= 0) EV_WIN32_CLOSE_FD (evpipe [0]);
2985
+ if (evpipe [1] >= 0) EV_WIN32_CLOSE_FD (evpipe [1]);
1777
2986
  }
1778
2987
 
1779
2988
  #if EV_USE_SIGNALFD
@@ -1869,43 +3078,31 @@ loop_fork (EV_P)
1869
3078
  infy_fork (EV_A);
1870
3079
  #endif
1871
3080
 
1872
- if (ev_is_active (&pipe_w))
3081
+ #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
3082
+ if (ev_is_active (&pipe_w) && postfork != 2)
1873
3083
  {
1874
- /* this "locks" the handlers against writing to the pipe */
1875
- /* while we modify the fd vars */
1876
- sig_pending = 1;
1877
- #if EV_ASYNC_ENABLE
1878
- async_pending = 1;
1879
- #endif
3084
+ /* pipe_write_wanted must be false now, so modifying fd vars should be safe */
1880
3085
 
1881
3086
  ev_ref (EV_A);
1882
3087
  ev_io_stop (EV_A_ &pipe_w);
1883
3088
 
1884
- #if EV_USE_EVENTFD
1885
- if (evfd >= 0)
1886
- close (evfd);
1887
- #endif
1888
-
1889
3089
  if (evpipe [0] >= 0)
1890
- {
1891
- EV_WIN32_CLOSE_FD (evpipe [0]);
1892
- EV_WIN32_CLOSE_FD (evpipe [1]);
1893
- }
3090
+ EV_WIN32_CLOSE_FD (evpipe [0]);
1894
3091
 
1895
- #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
1896
3092
  evpipe_init (EV_A);
1897
- /* now iterate over everything, in case we missed something */
1898
- pipecb (EV_A_ &pipe_w, EV_READ);
1899
- #endif
3093
+ /* iterate over everything, in case we missed something before */
3094
+ ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
1900
3095
  }
3096
+ #endif
1901
3097
 
1902
3098
  postfork = 0;
1903
3099
  }
1904
3100
 
1905
3101
  #if EV_MULTIPLICITY
1906
3102
 
3103
+ ecb_cold
1907
3104
  struct ev_loop *
1908
- ev_loop_new (unsigned int flags)
3105
+ ev_loop_new (unsigned int flags) EV_THROW
1909
3106
  {
1910
3107
  EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
1911
3108
 
@@ -1922,7 +3119,8 @@ ev_loop_new (unsigned int flags)
1922
3119
  #endif /* multiplicity */
1923
3120
 
1924
3121
  #if EV_VERIFY
1925
- static void noinline
3122
+ noinline ecb_cold
3123
+ static void
1926
3124
  verify_watcher (EV_P_ W w)
1927
3125
  {
1928
3126
  assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI));
@@ -1931,7 +3129,8 @@ verify_watcher (EV_P_ W w)
1931
3129
  assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w));
1932
3130
  }
1933
3131
 
1934
- static void noinline
3132
+ noinline ecb_cold
3133
+ static void
1935
3134
  verify_heap (EV_P_ ANHE *heap, int N)
1936
3135
  {
1937
3136
  int i;
@@ -1946,7 +3145,8 @@ verify_heap (EV_P_ ANHE *heap, int N)
1946
3145
  }
1947
3146
  }
1948
3147
 
1949
- static void noinline
3148
+ noinline ecb_cold
3149
+ static void
1950
3150
  array_verify (EV_P_ W *ws, int cnt)
1951
3151
  {
1952
3152
  while (cnt--)
@@ -1958,12 +3158,12 @@ array_verify (EV_P_ W *ws, int cnt)
1958
3158
  #endif
1959
3159
 
1960
3160
  #if EV_FEATURE_API
1961
- void
1962
- ev_verify (EV_P)
3161
+ void ecb_cold
3162
+ ev_verify (EV_P) EV_THROW
1963
3163
  {
1964
3164
  #if EV_VERIFY
1965
3165
  int i;
1966
- WL w;
3166
+ WL w, w2;
1967
3167
 
1968
3168
  assert (activecnt >= -1);
1969
3169
 
@@ -1973,12 +3173,23 @@ ev_verify (EV_P)
1973
3173
 
1974
3174
  assert (anfdmax >= 0);
1975
3175
  for (i = 0; i < anfdmax; ++i)
1976
- for (w = anfds [i].head; w; w = w->next)
1977
- {
1978
- verify_watcher (EV_A_ (W)w);
1979
- assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1));
1980
- assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i));
1981
- }
3176
+ {
3177
+ int j = 0;
3178
+
3179
+ for (w = w2 = anfds [i].head; w; w = w->next)
3180
+ {
3181
+ verify_watcher (EV_A_ (W)w);
3182
+
3183
+ if (j++ & 1)
3184
+ {
3185
+ assert (("libev: io watcher list contains a loop", w != w2));
3186
+ w2 = w2->next;
3187
+ }
3188
+
3189
+ assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1));
3190
+ assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i));
3191
+ }
3192
+ }
1982
3193
 
1983
3194
  assert (timermax >= timercnt);
1984
3195
  verify_heap (EV_A_ timers, timercnt);
@@ -2034,11 +3245,12 @@ ev_verify (EV_P)
2034
3245
  #endif
2035
3246
 
2036
3247
  #if EV_MULTIPLICITY
3248
+ ecb_cold
2037
3249
  struct ev_loop *
2038
3250
  #else
2039
3251
  int
2040
3252
  #endif
2041
- ev_default_loop (unsigned int flags)
3253
+ ev_default_loop (unsigned int flags) EV_THROW
2042
3254
  {
2043
3255
  if (!ev_default_loop_ptr)
2044
3256
  {
@@ -2067,9 +3279,9 @@ ev_default_loop (unsigned int flags)
2067
3279
  }
2068
3280
 
2069
3281
  void
2070
- ev_loop_fork (EV_P)
3282
+ ev_loop_fork (EV_P) EV_THROW
2071
3283
  {
2072
- postfork = 1; /* must be in line with ev_default_fork */
3284
+ postfork = 1;
2073
3285
  }
2074
3286
 
2075
3287
  /*****************************************************************************/
@@ -2081,7 +3293,7 @@ ev_invoke (EV_P_ void *w, int revents)
2081
3293
  }
2082
3294
 
2083
3295
  unsigned int
2084
- ev_pending_count (EV_P)
3296
+ ev_pending_count (EV_P) EV_THROW
2085
3297
  {
2086
3298
  int pri;
2087
3299
  unsigned int count = 0;
@@ -2092,23 +3304,25 @@ ev_pending_count (EV_P)
2092
3304
  return count;
2093
3305
  }
2094
3306
 
2095
- void noinline
3307
+ noinline
3308
+ void
2096
3309
  ev_invoke_pending (EV_P)
2097
3310
  {
2098
- int pri;
3311
+ pendingpri = NUMPRI;
2099
3312
 
2100
- for (pri = NUMPRI; pri--; )
2101
- while (pendingcnt [pri])
2102
- {
2103
- ANPENDING *p = pendings [pri] + --pendingcnt [pri];
3313
+ while (pendingpri) /* pendingpri possibly gets modified in the inner loop */
3314
+ {
3315
+ --pendingpri;
2104
3316
 
2105
- /*assert (("libev: non-pending watcher on pending list", p->w->pending));*/
2106
- /* ^ this is no longer true, as pending_w could be here */
3317
+ while (pendingcnt [pendingpri])
3318
+ {
3319
+ ANPENDING *p = pendings [pendingpri] + --pendingcnt [pendingpri];
2107
3320
 
2108
- p->w->pending = 0;
2109
- EV_CB_INVOKE (p->w, p->events);
2110
- EV_FREQUENT_CHECK;
2111
- }
3321
+ p->w->pending = 0;
3322
+ EV_CB_INVOKE (p->w, p->events);
3323
+ EV_FREQUENT_CHECK;
3324
+ }
3325
+ }
2112
3326
  }
2113
3327
 
2114
3328
  #if EV_IDLE_ENABLE
@@ -2175,6 +3389,32 @@ timers_reify (EV_P)
2175
3389
  }
2176
3390
 
2177
3391
  #if EV_PERIODIC_ENABLE
3392
+
3393
+ noinline
3394
+ static void
3395
+ periodic_recalc (EV_P_ ev_periodic *w)
3396
+ {
3397
+ ev_tstamp interval = w->interval > MIN_INTERVAL ? w->interval : MIN_INTERVAL;
3398
+ ev_tstamp at = w->offset + interval * ev_floor ((ev_rt_now - w->offset) / interval);
3399
+
3400
+ /* the above almost always errs on the low side */
3401
+ while (at <= ev_rt_now)
3402
+ {
3403
+ ev_tstamp nat = at + w->interval;
3404
+
3405
+ /* when resolution fails us, we use ev_rt_now */
3406
+ if (expect_false (nat == at))
3407
+ {
3408
+ at = ev_rt_now;
3409
+ break;
3410
+ }
3411
+
3412
+ at = nat;
3413
+ }
3414
+
3415
+ ev_at (w) = at;
3416
+ }
3417
+
2178
3418
  /* make periodics pending */
2179
3419
  inline_size void
2180
3420
  periodics_reify (EV_P)
@@ -2183,8 +3423,6 @@ periodics_reify (EV_P)
2183
3423
 
2184
3424
  while (periodiccnt && ANHE_at (periodics [HEAP0]) < ev_rt_now)
2185
3425
  {
2186
- int feed_count = 0;
2187
-
2188
3426
  do
2189
3427
  {
2190
3428
  ev_periodic *w = (ev_periodic *)ANHE_w (periodics [HEAP0]);
@@ -2203,20 +3441,7 @@ periodics_reify (EV_P)
2203
3441
  }
2204
3442
  else if (w->interval)
2205
3443
  {
2206
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
2207
- /* if next trigger time is not sufficiently in the future, put it there */
2208
- /* this might happen because of floating point inexactness */
2209
- if (ev_at (w) - ev_rt_now < TIME_EPSILON)
2210
- {
2211
- ev_at (w) += w->interval;
2212
-
2213
- /* if interval is unreasonably low we might still have a time in the past */
2214
- /* so correct this. this will make the periodic very inexact, but the user */
2215
- /* has effectively asked to get triggered more often than possible */
2216
- if (ev_at (w) < ev_rt_now)
2217
- ev_at (w) = ev_rt_now;
2218
- }
2219
-
3444
+ periodic_recalc (EV_A_ w);
2220
3445
  ANHE_at_cache (periodics [HEAP0]);
2221
3446
  downheap (periodics, periodiccnt, HEAP0);
2222
3447
  }
@@ -2234,7 +3459,8 @@ periodics_reify (EV_P)
2234
3459
 
2235
3460
  /* simply recalculate all periodics */
2236
3461
  /* TODO: maybe ensure that at least one event happens when jumping forward? */
2237
- static void noinline
3462
+ noinline ecb_cold
3463
+ static void
2238
3464
  periodics_reschedule (EV_P)
2239
3465
  {
2240
3466
  int i;
@@ -2247,7 +3473,7 @@ periodics_reschedule (EV_P)
2247
3473
  if (w->reschedule_cb)
2248
3474
  ev_at (w) = w->reschedule_cb (w, ev_rt_now);
2249
3475
  else if (w->interval)
2250
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
3476
+ periodic_recalc (EV_A_ w);
2251
3477
 
2252
3478
  ANHE_at_cache (periodics [i]);
2253
3479
  }
@@ -2257,7 +3483,8 @@ periodics_reschedule (EV_P)
2257
3483
  #endif
2258
3484
 
2259
3485
  /* adjust all timers by a given offset */
2260
- static void noinline
3486
+ noinline ecb_cold
3487
+ static void
2261
3488
  timers_reschedule (EV_P_ ev_tstamp adjust)
2262
3489
  {
2263
3490
  int i;
@@ -2304,9 +3531,12 @@ time_update (EV_P_ ev_tstamp max_block)
2304
3531
  */
2305
3532
  for (i = 4; --i; )
2306
3533
  {
3534
+ ev_tstamp diff;
2307
3535
  rtmn_diff = ev_rt_now - mn_now;
2308
3536
 
2309
- if (expect_true (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP))
3537
+ diff = odiff - rtmn_diff;
3538
+
3539
+ if (expect_true ((diff < 0. ? -diff : diff) < MIN_TIMEJUMP))
2310
3540
  return; /* all is well */
2311
3541
 
2312
3542
  ev_rt_now = ev_time ();
@@ -2338,9 +3568,33 @@ time_update (EV_P_ ev_tstamp max_block)
2338
3568
  }
2339
3569
  }
2340
3570
 
2341
- void
3571
+ /* ########## COOLIO PATCHERY HO! ########## */
3572
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
3573
+ struct ev_poll_args {
3574
+ struct ev_loop *loop;
3575
+ ev_tstamp waittime;
3576
+ };
3577
+
3578
+ static
3579
+ VALUE ev_backend_poll(void *ptr)
3580
+ {
3581
+ struct ev_poll_args *args = (struct ev_poll_args *)ptr;
3582
+ struct ev_loop *loop = args->loop;
3583
+ backend_poll (EV_A_ args->waittime);
3584
+ return Qnil;
3585
+ }
3586
+ #endif
3587
+ /* ######################################## */
3588
+
3589
+ int
2342
3590
  ev_run (EV_P_ int flags)
2343
3591
  {
3592
+ /* ########## COOLIO PATCHERY HO! ########## */
3593
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
3594
+ struct ev_poll_args poll_args;
3595
+ #endif
3596
+ /* ######################################## */
3597
+
2344
3598
  #if EV_FEATURE_API
2345
3599
  ++loop_depth;
2346
3600
  #endif
@@ -2406,20 +3660,25 @@ ev_run (EV_P_ int flags)
2406
3660
  /* update time to cancel out callback processing overhead */
2407
3661
  time_update (EV_A_ 1e100);
2408
3662
 
2409
- if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt)))
3663
+ /* from now on, we want a pipe-wake-up */
3664
+ pipe_write_wanted = 1;
3665
+
3666
+ ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */
3667
+
3668
+ if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
2410
3669
  {
2411
3670
  waittime = MAX_BLOCKTIME;
2412
3671
 
2413
3672
  if (timercnt)
2414
3673
  {
2415
- ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge;
3674
+ ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
2416
3675
  if (waittime > to) waittime = to;
2417
3676
  }
2418
3677
 
2419
3678
  #if EV_PERIODIC_ENABLE
2420
3679
  if (periodiccnt)
2421
3680
  {
2422
- ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge;
3681
+ ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;
2423
3682
  if (waittime > to) waittime = to;
2424
3683
  }
2425
3684
  #endif
@@ -2428,13 +3687,18 @@ ev_run (EV_P_ int flags)
2428
3687
  if (expect_false (waittime < timeout_blocktime))
2429
3688
  waittime = timeout_blocktime;
2430
3689
 
3690
+ /* at this point, we NEED to wait, so we have to ensure */
3691
+ /* to pass a minimum nonzero value to the backend */
3692
+ if (expect_false (waittime < backend_mintime))
3693
+ waittime = backend_mintime;
3694
+
2431
3695
  /* extra check because io_blocktime is commonly 0 */
2432
3696
  if (expect_false (io_blocktime))
2433
3697
  {
2434
3698
  sleeptime = io_blocktime - (mn_now - prev_mn_now);
2435
3699
 
2436
- if (sleeptime > waittime - backend_fudge)
2437
- sleeptime = waittime - backend_fudge;
3700
+ if (sleeptime > waittime - backend_mintime)
3701
+ sleeptime = waittime - backend_mintime;
2438
3702
 
2439
3703
  if (expect_true (sleeptime > 0.))
2440
3704
  {
@@ -2448,9 +3712,82 @@ ev_run (EV_P_ int flags)
2448
3712
  ++loop_count;
2449
3713
  #endif
2450
3714
  assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
2451
- backend_poll (EV_A_ waittime);
3715
+
3716
+ /*
3717
+ ########################## COOLIO PATCHERY HO! ##########################
3718
+
3719
+ According to the grandwizards of Ruby, locking and unlocking of the global
3720
+ interpreter lock are apparently too powerful a concept for a mere mortal to
3721
+ wield (although redefining what + and - do to numbers is totally cool).
3722
+ And so it came to pass that the only acceptable way to release the global
3723
+ interpreter lock is through a convoluted callback system that thakes a
3724
+ function pointer. While the grandwizard of libev foresaw this sort of scenario,
3725
+ he too attempted to place an API with callbacks on it, one that runs before
3726
+ the system call, and one that runs immediately after.
3727
+
3728
+ And so it came to pass that trying to wrap everything up in callbacks created
3729
+ two incompatible APIs, Ruby's which releases the global interpreter lock and
3730
+ reacquires it when the callback returns, and libev's, which wants two
3731
+ callbacks, one which runs before the polling operation starts, and one which
3732
+ runs after it finishes.
3733
+
3734
+ These two systems are incompatible as they both want to use callbacks to
3735
+ solve the same problem, however libev wants to use before/after callbacks,
3736
+ and Ruby wants to use an "around" callback. This presents a significant
3737
+ problem as these two patterns of callbacks are diametrical opposites of each
3738
+ other and thus cannot be composed.
3739
+
3740
+ And thus we are left with no choice but to patch the internals of libev in
3741
+ order to release a mutex at just the precise moment.
3742
+
3743
+ This is a great example of a situation where granular locking and unlocking
3744
+ of the GVL is practically required. The goal is to get as close to the
3745
+ system call as possible, and to keep the GVL unlocked for the shortest
3746
+ amount of time possible.
3747
+
3748
+ Perhaps Ruby could benefit from such an API, e.g:
3749
+
3750
+ rb_thread_unsafe_dangerous_crazy_blocking_region_begin(...);
3751
+ rb_thread_unsafe_dangerous_crazy_blocking_region_end(...);
3752
+
3753
+ #######################################################################
3754
+ */
3755
+
3756
+ /*
3757
+ simulate to rb_thread_call_without_gvl using rb_theread_blocking_region.
3758
+ https://github.com/brianmario/mysql2/blob/master/ext/mysql2/client.h#L8
3759
+ */
3760
+
3761
+ #ifndef HAVE_RB_THREAD_CALL_WITHOUT_GVL
3762
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
3763
+ #define rb_thread_call_without_gvl(func, data1, ubf, data2) \
3764
+ rb_thread_blocking_region((rb_blocking_function_t *)func, data1, ubf, data2)
3765
+ #endif
3766
+ #endif
3767
+
3768
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
3769
+ poll_args.loop = loop;
3770
+ poll_args.waittime = waittime;
3771
+ rb_thread_call_without_gvl((void *)ev_backend_poll, (void *)&poll_args, RUBY_UBF_IO, 0);
3772
+ #else
3773
+ backend_poll (EV_A_ waittime);
3774
+ #endif
3775
+ /*
3776
+ ############################# END PATCHERY ############################
3777
+ */
3778
+
2452
3779
  assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
2453
3780
 
3781
+ pipe_write_wanted = 0; /* just an optimisation, no fence needed */
3782
+
3783
+ ECB_MEMORY_FENCE_ACQUIRE;
3784
+ if (pipe_write_skipped)
3785
+ {
3786
+ assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
3787
+ ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
3788
+ }
3789
+
3790
+
2454
3791
  /* update ev_rt_now, do magic */
2455
3792
  time_update (EV_A_ waittime + sleeptime);
2456
3793
  }
@@ -2486,40 +3823,42 @@ ev_run (EV_P_ int flags)
2486
3823
  #if EV_FEATURE_API
2487
3824
  --loop_depth;
2488
3825
  #endif
3826
+
3827
+ return activecnt;
2489
3828
  }
2490
3829
 
2491
3830
  void
2492
- ev_break (EV_P_ int how)
3831
+ ev_break (EV_P_ int how) EV_THROW
2493
3832
  {
2494
3833
  loop_done = how;
2495
3834
  }
2496
3835
 
2497
3836
  void
2498
- ev_ref (EV_P)
3837
+ ev_ref (EV_P) EV_THROW
2499
3838
  {
2500
3839
  ++activecnt;
2501
3840
  }
2502
3841
 
2503
3842
  void
2504
- ev_unref (EV_P)
3843
+ ev_unref (EV_P) EV_THROW
2505
3844
  {
2506
3845
  --activecnt;
2507
3846
  }
2508
3847
 
2509
3848
  void
2510
- ev_now_update (EV_P)
3849
+ ev_now_update (EV_P) EV_THROW
2511
3850
  {
2512
3851
  time_update (EV_A_ 1e100);
2513
3852
  }
2514
3853
 
2515
3854
  void
2516
- ev_suspend (EV_P)
3855
+ ev_suspend (EV_P) EV_THROW
2517
3856
  {
2518
3857
  ev_now_update (EV_A);
2519
3858
  }
2520
3859
 
2521
3860
  void
2522
- ev_resume (EV_P)
3861
+ ev_resume (EV_P) EV_THROW
2523
3862
  {
2524
3863
  ev_tstamp mn_prev = mn_now;
2525
3864
 
@@ -2568,7 +3907,7 @@ clear_pending (EV_P_ W w)
2568
3907
  }
2569
3908
 
2570
3909
  int
2571
- ev_clear_pending (EV_P_ void *w)
3910
+ ev_clear_pending (EV_P_ void *w) EV_THROW
2572
3911
  {
2573
3912
  W w_ = (W)w;
2574
3913
  int pending = w_->pending;
@@ -2610,8 +3949,9 @@ ev_stop (EV_P_ W w)
2610
3949
 
2611
3950
  /*****************************************************************************/
2612
3951
 
2613
- void noinline
2614
- ev_io_start (EV_P_ ev_io *w)
3952
+ noinline
3953
+ void
3954
+ ev_io_start (EV_P_ ev_io *w) EV_THROW
2615
3955
  {
2616
3956
  int fd = w->fd;
2617
3957
 
@@ -2627,14 +3967,18 @@ ev_io_start (EV_P_ ev_io *w)
2627
3967
  array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero);
2628
3968
  wlist_add (&anfds[fd].head, (WL)w);
2629
3969
 
3970
+ /* common bug, apparently */
3971
+ assert (("libev: ev_io_start called with corrupted watcher", ((WL)w)->next != (WL)w));
3972
+
2630
3973
  fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY);
2631
3974
  w->events &= ~EV__IOFDSET;
2632
3975
 
2633
3976
  EV_FREQUENT_CHECK;
2634
3977
  }
2635
3978
 
2636
- void noinline
2637
- ev_io_stop (EV_P_ ev_io *w)
3979
+ noinline
3980
+ void
3981
+ ev_io_stop (EV_P_ ev_io *w) EV_THROW
2638
3982
  {
2639
3983
  clear_pending (EV_A_ (W)w);
2640
3984
  if (expect_false (!ev_is_active (w)))
@@ -2652,8 +3996,9 @@ ev_io_stop (EV_P_ ev_io *w)
2652
3996
  EV_FREQUENT_CHECK;
2653
3997
  }
2654
3998
 
2655
- void noinline
2656
- ev_timer_start (EV_P_ ev_timer *w)
3999
+ noinline
4000
+ void
4001
+ ev_timer_start (EV_P_ ev_timer *w) EV_THROW
2657
4002
  {
2658
4003
  if (expect_false (ev_is_active (w)))
2659
4004
  return;
@@ -2676,8 +4021,9 @@ ev_timer_start (EV_P_ ev_timer *w)
2676
4021
  /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/
2677
4022
  }
2678
4023
 
2679
- void noinline
2680
- ev_timer_stop (EV_P_ ev_timer *w)
4024
+ noinline
4025
+ void
4026
+ ev_timer_stop (EV_P_ ev_timer *w) EV_THROW
2681
4027
  {
2682
4028
  clear_pending (EV_A_ (W)w);
2683
4029
  if (expect_false (!ev_is_active (w)))
@@ -2706,11 +4052,14 @@ ev_timer_stop (EV_P_ ev_timer *w)
2706
4052
  EV_FREQUENT_CHECK;
2707
4053
  }
2708
4054
 
2709
- void noinline
2710
- ev_timer_again (EV_P_ ev_timer *w)
4055
+ noinline
4056
+ void
4057
+ ev_timer_again (EV_P_ ev_timer *w) EV_THROW
2711
4058
  {
2712
4059
  EV_FREQUENT_CHECK;
2713
4060
 
4061
+ clear_pending (EV_A_ (W)w);
4062
+
2714
4063
  if (ev_is_active (w))
2715
4064
  {
2716
4065
  if (w->repeat)
@@ -2732,14 +4081,15 @@ ev_timer_again (EV_P_ ev_timer *w)
2732
4081
  }
2733
4082
 
2734
4083
  ev_tstamp
2735
- ev_timer_remaining (EV_P_ ev_timer *w)
4084
+ ev_timer_remaining (EV_P_ ev_timer *w) EV_THROW
2736
4085
  {
2737
4086
  return ev_at (w) - (ev_is_active (w) ? mn_now : 0.);
2738
4087
  }
2739
4088
 
2740
4089
  #if EV_PERIODIC_ENABLE
2741
- void noinline
2742
- ev_periodic_start (EV_P_ ev_periodic *w)
4090
+ noinline
4091
+ void
4092
+ ev_periodic_start (EV_P_ ev_periodic *w) EV_THROW
2743
4093
  {
2744
4094
  if (expect_false (ev_is_active (w)))
2745
4095
  return;
@@ -2749,8 +4099,7 @@ ev_periodic_start (EV_P_ ev_periodic *w)
2749
4099
  else if (w->interval)
2750
4100
  {
2751
4101
  assert (("libev: ev_periodic_start called with negative interval value", w->interval >= 0.));
2752
- /* this formula differs from the one in periodic_reify because we do not always round up */
2753
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
4102
+ periodic_recalc (EV_A_ w);
2754
4103
  }
2755
4104
  else
2756
4105
  ev_at (w) = w->offset;
@@ -2769,8 +4118,9 @@ ev_periodic_start (EV_P_ ev_periodic *w)
2769
4118
  /*assert (("libev: internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/
2770
4119
  }
2771
4120
 
2772
- void noinline
2773
- ev_periodic_stop (EV_P_ ev_periodic *w)
4121
+ noinline
4122
+ void
4123
+ ev_periodic_stop (EV_P_ ev_periodic *w) EV_THROW
2774
4124
  {
2775
4125
  clear_pending (EV_A_ (W)w);
2776
4126
  if (expect_false (!ev_is_active (w)))
@@ -2797,8 +4147,9 @@ ev_periodic_stop (EV_P_ ev_periodic *w)
2797
4147
  EV_FREQUENT_CHECK;
2798
4148
  }
2799
4149
 
2800
- void noinline
2801
- ev_periodic_again (EV_P_ ev_periodic *w)
4150
+ noinline
4151
+ void
4152
+ ev_periodic_again (EV_P_ ev_periodic *w) EV_THROW
2802
4153
  {
2803
4154
  /* TODO: use adjustheap and recalculation */
2804
4155
  ev_periodic_stop (EV_A_ w);
@@ -2812,8 +4163,9 @@ ev_periodic_again (EV_P_ ev_periodic *w)
2812
4163
 
2813
4164
  #if EV_SIGNAL_ENABLE
2814
4165
 
2815
- void noinline
2816
- ev_signal_start (EV_P_ ev_signal *w)
4166
+ noinline
4167
+ void
4168
+ ev_signal_start (EV_P_ ev_signal *w) EV_THROW
2817
4169
  {
2818
4170
  if (expect_false (ev_is_active (w)))
2819
4171
  return;
@@ -2825,6 +4177,7 @@ ev_signal_start (EV_P_ ev_signal *w)
2825
4177
  !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop));
2826
4178
 
2827
4179
  signals [w->signum - 1].loop = EV_A;
4180
+ ECB_MEMORY_FENCE_RELEASE;
2828
4181
  #endif
2829
4182
 
2830
4183
  EV_FREQUENT_CHECK;
@@ -2881,17 +4234,21 @@ ev_signal_start (EV_P_ ev_signal *w)
2881
4234
  sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
2882
4235
  sigaction (w->signum, &sa, 0);
2883
4236
 
2884
- sigemptyset (&sa.sa_mask);
2885
- sigaddset (&sa.sa_mask, w->signum);
2886
- sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0);
4237
+ if (origflags & EVFLAG_NOSIGMASK)
4238
+ {
4239
+ sigemptyset (&sa.sa_mask);
4240
+ sigaddset (&sa.sa_mask, w->signum);
4241
+ sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0);
4242
+ }
2887
4243
  #endif
2888
4244
  }
2889
4245
 
2890
4246
  EV_FREQUENT_CHECK;
2891
4247
  }
2892
4248
 
2893
- void noinline
2894
- ev_signal_stop (EV_P_ ev_signal *w)
4249
+ noinline
4250
+ void
4251
+ ev_signal_stop (EV_P_ ev_signal *w) EV_THROW
2895
4252
  {
2896
4253
  clear_pending (EV_A_ (W)w);
2897
4254
  if (expect_false (!ev_is_active (w)))
@@ -2932,7 +4289,7 @@ ev_signal_stop (EV_P_ ev_signal *w)
2932
4289
  #if EV_CHILD_ENABLE
2933
4290
 
2934
4291
  void
2935
- ev_child_start (EV_P_ ev_child *w)
4292
+ ev_child_start (EV_P_ ev_child *w) EV_THROW
2936
4293
  {
2937
4294
  #if EV_MULTIPLICITY
2938
4295
  assert (("libev: child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
@@ -2949,7 +4306,7 @@ ev_child_start (EV_P_ ev_child *w)
2949
4306
  }
2950
4307
 
2951
4308
  void
2952
- ev_child_stop (EV_P_ ev_child *w)
4309
+ ev_child_stop (EV_P_ ev_child *w) EV_THROW
2953
4310
  {
2954
4311
  clear_pending (EV_A_ (W)w);
2955
4312
  if (expect_false (!ev_is_active (w)))
@@ -2976,17 +4333,21 @@ ev_child_stop (EV_P_ ev_child *w)
2976
4333
  #define NFS_STAT_INTERVAL 30.1074891 /* for filesystems potentially failing inotify */
2977
4334
  #define MIN_STAT_INTERVAL 0.1074891
2978
4335
 
2979
- static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents);
4336
+ noinline static void stat_timer_cb (EV_P_ ev_timer *w_, int revents);
2980
4337
 
2981
4338
  #if EV_USE_INOTIFY
2982
4339
 
2983
4340
  /* the * 2 is to allow for alignment padding, which for some reason is >> 8 */
2984
4341
  # define EV_INOTIFY_BUFSIZE (sizeof (struct inotify_event) * 2 + NAME_MAX)
2985
4342
 
2986
- static void noinline
4343
+ noinline
4344
+ static void
2987
4345
  infy_add (EV_P_ ev_stat *w)
2988
4346
  {
2989
- 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);
4347
+ w->wd = inotify_add_watch (fs_fd, w->path,
4348
+ IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY
4349
+ | IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO
4350
+ | IN_DONT_FOLLOW | IN_MASK_ADD);
2990
4351
 
2991
4352
  if (w->wd >= 0)
2992
4353
  {
@@ -3000,10 +4361,16 @@ infy_add (EV_P_ ev_stat *w)
3000
4361
  w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL;
3001
4362
  else if (!statfs (w->path, &sfs)
3002
4363
  && (sfs.f_type == 0x1373 /* devfs */
4364
+ || sfs.f_type == 0x4006 /* fat */
4365
+ || sfs.f_type == 0x4d44 /* msdos */
3003
4366
  || sfs.f_type == 0xEF53 /* ext2/3 */
4367
+ || sfs.f_type == 0x72b6 /* jffs2 */
4368
+ || sfs.f_type == 0x858458f6 /* ramfs */
4369
+ || sfs.f_type == 0x5346544e /* ntfs */
3004
4370
  || sfs.f_type == 0x3153464a /* jfs */
4371
+ || sfs.f_type == 0x9123683e /* btrfs */
3005
4372
  || sfs.f_type == 0x52654973 /* reiser3 */
3006
- || sfs.f_type == 0x01021994 /* tempfs */
4373
+ || sfs.f_type == 0x01021994 /* tmpfs */
3007
4374
  || sfs.f_type == 0x58465342 /* xfs */))
3008
4375
  w->timer.repeat = 0.; /* filesystem is local, kernel new enough */
3009
4376
  else
@@ -3034,7 +4401,7 @@ infy_add (EV_P_ ev_stat *w)
3034
4401
 
3035
4402
  *pend = 0;
3036
4403
  w->wd = inotify_add_watch (fs_fd, path, mask);
3037
- }
4404
+ }
3038
4405
  while (w->wd < 0 && (errno == ENOENT || errno == EACCES));
3039
4406
  }
3040
4407
  }
@@ -3048,7 +4415,8 @@ infy_add (EV_P_ ev_stat *w)
3048
4415
  if (ev_is_active (&w->timer)) ev_unref (EV_A);
3049
4416
  }
3050
4417
 
3051
- static void noinline
4418
+ noinline
4419
+ static void
3052
4420
  infy_del (EV_P_ ev_stat *w)
3053
4421
  {
3054
4422
  int slot;
@@ -3065,7 +4433,8 @@ infy_del (EV_P_ ev_stat *w)
3065
4433
  inotify_rm_watch (fs_fd, wd);
3066
4434
  }
3067
4435
 
3068
- static void noinline
4436
+ noinline
4437
+ static void
3069
4438
  infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev)
3070
4439
  {
3071
4440
  if (slot < 0)
@@ -3111,7 +4480,8 @@ infy_cb (EV_P_ ev_io *w, int revents)
3111
4480
  }
3112
4481
  }
3113
4482
 
3114
- inline_size void
4483
+ inline_size ecb_cold
4484
+ void
3115
4485
  ev_check_2625 (EV_P)
3116
4486
  {
3117
4487
  /* kernels < 2.6.25 are borked
@@ -3126,7 +4496,7 @@ ev_check_2625 (EV_P)
3126
4496
  inline_size int
3127
4497
  infy_newfd (void)
3128
4498
  {
3129
- #if defined (IN_CLOEXEC) && defined (IN_NONBLOCK)
4499
+ #if defined IN_CLOEXEC && defined IN_NONBLOCK
3130
4500
  int fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK);
3131
4501
  if (fd >= 0)
3132
4502
  return fd;
@@ -3211,7 +4581,7 @@ infy_fork (EV_P)
3211
4581
  #endif
3212
4582
 
3213
4583
  void
3214
- ev_stat_stat (EV_P_ ev_stat *w)
4584
+ ev_stat_stat (EV_P_ ev_stat *w) EV_THROW
3215
4585
  {
3216
4586
  if (lstat (w->path, &w->attr) < 0)
3217
4587
  w->attr.st_nlink = 0;
@@ -3219,7 +4589,8 @@ ev_stat_stat (EV_P_ ev_stat *w)
3219
4589
  w->attr.st_nlink = 1;
3220
4590
  }
3221
4591
 
3222
- static void noinline
4592
+ noinline
4593
+ static void
3223
4594
  stat_timer_cb (EV_P_ ev_timer *w_, int revents)
3224
4595
  {
3225
4596
  ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
@@ -3260,7 +4631,7 @@ stat_timer_cb (EV_P_ ev_timer *w_, int revents)
3260
4631
  }
3261
4632
 
3262
4633
  void
3263
- ev_stat_start (EV_P_ ev_stat *w)
4634
+ ev_stat_start (EV_P_ ev_stat *w) EV_THROW
3264
4635
  {
3265
4636
  if (expect_false (ev_is_active (w)))
3266
4637
  return;
@@ -3291,7 +4662,7 @@ ev_stat_start (EV_P_ ev_stat *w)
3291
4662
  }
3292
4663
 
3293
4664
  void
3294
- ev_stat_stop (EV_P_ ev_stat *w)
4665
+ ev_stat_stop (EV_P_ ev_stat *w) EV_THROW
3295
4666
  {
3296
4667
  clear_pending (EV_A_ (W)w);
3297
4668
  if (expect_false (!ev_is_active (w)))
@@ -3317,7 +4688,7 @@ ev_stat_stop (EV_P_ ev_stat *w)
3317
4688
 
3318
4689
  #if EV_IDLE_ENABLE
3319
4690
  void
3320
- ev_idle_start (EV_P_ ev_idle *w)
4691
+ ev_idle_start (EV_P_ ev_idle *w) EV_THROW
3321
4692
  {
3322
4693
  if (expect_false (ev_is_active (w)))
3323
4694
  return;
@@ -3340,7 +4711,7 @@ ev_idle_start (EV_P_ ev_idle *w)
3340
4711
  }
3341
4712
 
3342
4713
  void
3343
- ev_idle_stop (EV_P_ ev_idle *w)
4714
+ ev_idle_stop (EV_P_ ev_idle *w) EV_THROW
3344
4715
  {
3345
4716
  clear_pending (EV_A_ (W)w);
3346
4717
  if (expect_false (!ev_is_active (w)))
@@ -3364,7 +4735,7 @@ ev_idle_stop (EV_P_ ev_idle *w)
3364
4735
 
3365
4736
  #if EV_PREPARE_ENABLE
3366
4737
  void
3367
- ev_prepare_start (EV_P_ ev_prepare *w)
4738
+ ev_prepare_start (EV_P_ ev_prepare *w) EV_THROW
3368
4739
  {
3369
4740
  if (expect_false (ev_is_active (w)))
3370
4741
  return;
@@ -3379,7 +4750,7 @@ ev_prepare_start (EV_P_ ev_prepare *w)
3379
4750
  }
3380
4751
 
3381
4752
  void
3382
- ev_prepare_stop (EV_P_ ev_prepare *w)
4753
+ ev_prepare_stop (EV_P_ ev_prepare *w) EV_THROW
3383
4754
  {
3384
4755
  clear_pending (EV_A_ (W)w);
3385
4756
  if (expect_false (!ev_is_active (w)))
@@ -3402,7 +4773,7 @@ ev_prepare_stop (EV_P_ ev_prepare *w)
3402
4773
 
3403
4774
  #if EV_CHECK_ENABLE
3404
4775
  void
3405
- ev_check_start (EV_P_ ev_check *w)
4776
+ ev_check_start (EV_P_ ev_check *w) EV_THROW
3406
4777
  {
3407
4778
  if (expect_false (ev_is_active (w)))
3408
4779
  return;
@@ -3417,7 +4788,7 @@ ev_check_start (EV_P_ ev_check *w)
3417
4788
  }
3418
4789
 
3419
4790
  void
3420
- ev_check_stop (EV_P_ ev_check *w)
4791
+ ev_check_stop (EV_P_ ev_check *w) EV_THROW
3421
4792
  {
3422
4793
  clear_pending (EV_A_ (W)w);
3423
4794
  if (expect_false (!ev_is_active (w)))
@@ -3439,8 +4810,9 @@ ev_check_stop (EV_P_ ev_check *w)
3439
4810
  #endif
3440
4811
 
3441
4812
  #if EV_EMBED_ENABLE
3442
- void noinline
3443
- ev_embed_sweep (EV_P_ ev_embed *w)
4813
+ noinline
4814
+ void
4815
+ ev_embed_sweep (EV_P_ ev_embed *w) EV_THROW
3444
4816
  {
3445
4817
  ev_run (w->other, EVRUN_NOWAIT);
3446
4818
  }
@@ -3498,7 +4870,7 @@ embed_idle_cb (EV_P_ ev_idle *idle, int revents)
3498
4870
  #endif
3499
4871
 
3500
4872
  void
3501
- ev_embed_start (EV_P_ ev_embed *w)
4873
+ ev_embed_start (EV_P_ ev_embed *w) EV_THROW
3502
4874
  {
3503
4875
  if (expect_false (ev_is_active (w)))
3504
4876
  return;
@@ -3529,7 +4901,7 @@ ev_embed_start (EV_P_ ev_embed *w)
3529
4901
  }
3530
4902
 
3531
4903
  void
3532
- ev_embed_stop (EV_P_ ev_embed *w)
4904
+ ev_embed_stop (EV_P_ ev_embed *w) EV_THROW
3533
4905
  {
3534
4906
  clear_pending (EV_A_ (W)w);
3535
4907
  if (expect_false (!ev_is_active (w)))
@@ -3549,7 +4921,7 @@ ev_embed_stop (EV_P_ ev_embed *w)
3549
4921
 
3550
4922
  #if EV_FORK_ENABLE
3551
4923
  void
3552
- ev_fork_start (EV_P_ ev_fork *w)
4924
+ ev_fork_start (EV_P_ ev_fork *w) EV_THROW
3553
4925
  {
3554
4926
  if (expect_false (ev_is_active (w)))
3555
4927
  return;
@@ -3564,7 +4936,7 @@ ev_fork_start (EV_P_ ev_fork *w)
3564
4936
  }
3565
4937
 
3566
4938
  void
3567
- ev_fork_stop (EV_P_ ev_fork *w)
4939
+ ev_fork_stop (EV_P_ ev_fork *w) EV_THROW
3568
4940
  {
3569
4941
  clear_pending (EV_A_ (W)w);
3570
4942
  if (expect_false (!ev_is_active (w)))
@@ -3587,7 +4959,7 @@ ev_fork_stop (EV_P_ ev_fork *w)
3587
4959
 
3588
4960
  #if EV_CLEANUP_ENABLE
3589
4961
  void
3590
- ev_cleanup_start (EV_P_ ev_cleanup *w)
4962
+ ev_cleanup_start (EV_P_ ev_cleanup *w) EV_THROW
3591
4963
  {
3592
4964
  if (expect_false (ev_is_active (w)))
3593
4965
  return;
@@ -3604,7 +4976,7 @@ ev_cleanup_start (EV_P_ ev_cleanup *w)
3604
4976
  }
3605
4977
 
3606
4978
  void
3607
- ev_cleanup_stop (EV_P_ ev_cleanup *w)
4979
+ ev_cleanup_stop (EV_P_ ev_cleanup *w) EV_THROW
3608
4980
  {
3609
4981
  clear_pending (EV_A_ (W)w);
3610
4982
  if (expect_false (!ev_is_active (w)))
@@ -3628,7 +5000,7 @@ ev_cleanup_stop (EV_P_ ev_cleanup *w)
3628
5000
 
3629
5001
  #if EV_ASYNC_ENABLE
3630
5002
  void
3631
- ev_async_start (EV_P_ ev_async *w)
5003
+ ev_async_start (EV_P_ ev_async *w) EV_THROW
3632
5004
  {
3633
5005
  if (expect_false (ev_is_active (w)))
3634
5006
  return;
@@ -3647,7 +5019,7 @@ ev_async_start (EV_P_ ev_async *w)
3647
5019
  }
3648
5020
 
3649
5021
  void
3650
- ev_async_stop (EV_P_ ev_async *w)
5022
+ ev_async_stop (EV_P_ ev_async *w) EV_THROW
3651
5023
  {
3652
5024
  clear_pending (EV_A_ (W)w);
3653
5025
  if (expect_false (!ev_is_active (w)))
@@ -3668,7 +5040,7 @@ ev_async_stop (EV_P_ ev_async *w)
3668
5040
  }
3669
5041
 
3670
5042
  void
3671
- ev_async_send (EV_P_ ev_async *w)
5043
+ ev_async_send (EV_P_ ev_async *w) EV_THROW
3672
5044
  {
3673
5045
  w->sent = 1;
3674
5046
  evpipe_write (EV_A_ &async_pending);
@@ -3715,7 +5087,7 @@ once_cb_to (EV_P_ ev_timer *w, int revents)
3715
5087
  }
3716
5088
 
3717
5089
  void
3718
- ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg)
5090
+ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg) EV_THROW
3719
5091
  {
3720
5092
  struct ev_once *once = (struct ev_once *)ev_malloc (sizeof (struct ev_once));
3721
5093
 
@@ -3746,8 +5118,9 @@ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, vo
3746
5118
  /*****************************************************************************/
3747
5119
 
3748
5120
  #if EV_WALK_ENABLE
5121
+ ecb_cold
3749
5122
  void
3750
- ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
5123
+ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) EV_THROW
3751
5124
  {
3752
5125
  int i, j;
3753
5126
  ev_watcher_list *wl, *wn;
@@ -3800,7 +5173,7 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
3800
5173
 
3801
5174
  #if EV_IDLE_ENABLE
3802
5175
  if (types & EV_IDLE)
3803
- for (j = NUMPRI; i--; )
5176
+ for (j = NUMPRI; j--; )
3804
5177
  for (i = idlecnt [j]; i--; )
3805
5178
  cb (EV_A_ EV_IDLE, idles [j][i]);
3806
5179
  #endif
@@ -3863,5 +5236,3 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
3863
5236
  #include "ev_wrap.h"
3864
5237
  #endif
3865
5238
 
3866
- EV_CPP(})
3867
-