nio4r 0.2.0 → 2.7.5

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 (60) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/ext/libev/Changes +232 -3
  4. data/ext/libev/LICENSE +2 -1
  5. data/ext/libev/README +11 -10
  6. data/ext/libev/ev.c +2249 -473
  7. data/ext/libev/ev.h +165 -135
  8. data/ext/libev/ev_epoll.c +68 -36
  9. data/ext/libev/ev_iouring.c +694 -0
  10. data/ext/libev/ev_kqueue.c +44 -18
  11. data/ext/libev/ev_linuxaio.c +620 -0
  12. data/ext/libev/ev_poll.c +28 -20
  13. data/ext/libev/ev_port.c +23 -10
  14. data/ext/libev/ev_select.c +18 -12
  15. data/ext/libev/ev_vars.h +65 -19
  16. data/ext/libev/ev_win32.c +16 -7
  17. data/ext/libev/ev_wrap.h +236 -160
  18. data/ext/nio4r/.clang-format +16 -0
  19. data/ext/nio4r/bytebuffer.c +465 -0
  20. data/ext/nio4r/extconf.rb +44 -35
  21. data/ext/nio4r/libev.h +3 -4
  22. data/ext/nio4r/monitor.c +186 -54
  23. data/ext/nio4r/nio4r.h +17 -23
  24. data/ext/nio4r/nio4r_ext.c +11 -3
  25. data/ext/nio4r/org/nio4r/ByteBuffer.java +295 -0
  26. data/ext/nio4r/org/nio4r/Monitor.java +176 -0
  27. data/ext/nio4r/org/nio4r/Nio4r.java +104 -0
  28. data/ext/nio4r/org/nio4r/Selector.java +297 -0
  29. data/ext/nio4r/selector.c +350 -182
  30. data/lib/nio/bytebuffer.rb +235 -0
  31. data/lib/nio/monitor.rb +100 -8
  32. data/lib/nio/selector.rb +110 -44
  33. data/lib/nio/version.rb +8 -1
  34. data/lib/nio.rb +47 -16
  35. data/lib/nio4r.rb +7 -0
  36. data/license.md +80 -0
  37. data/readme.md +91 -0
  38. data/releases.md +343 -0
  39. data.tar.gz.sig +2 -0
  40. metadata +114 -79
  41. metadata.gz.sig +0 -0
  42. data/.gitignore +0 -20
  43. data/.rspec +0 -4
  44. data/.travis.yml +0 -7
  45. data/CHANGES.md +0 -10
  46. data/Gemfile +0 -4
  47. data/LICENSE.txt +0 -20
  48. data/README.md +0 -171
  49. data/Rakefile +0 -9
  50. data/examples/echo_server.rb +0 -38
  51. data/ext/libev/README.embed +0 -3
  52. data/ext/libev/test_libev_win32.c +0 -123
  53. data/lib/nio/jruby/monitor.rb +0 -42
  54. data/lib/nio/jruby/selector.rb +0 -135
  55. data/nio4r.gemspec +0 -22
  56. data/spec/nio/monitor_spec.rb +0 -46
  57. data/spec/nio/selector_spec.rb +0 -269
  58. data/spec/spec_helper.rb +0 -3
  59. data/tasks/extension.rake +0 -10
  60. data/tasks/rspec.rake +0 -7
data/ext/libev/ev.c CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * libev event processing core, watcher management
3
3
  *
4
- * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007-2019 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-
@@ -37,6 +37,15 @@
37
37
  * either the BSD or the GPL.
38
38
  */
39
39
 
40
+ /* ########## NIO4R PATCHERY HO! ########## */
41
+ #include "ruby.h"
42
+ #include "ruby/thread.h"
43
+
44
+ #ifdef __APPLE__
45
+ #include <AvailabilityMacros.h>
46
+ #endif
47
+ /* ######################################## */
48
+
40
49
  /* this big block deduces configuration from config.h */
41
50
  #ifndef EV_STANDALONE
42
51
  # ifdef EV_CONFIG_H
@@ -45,6 +54,12 @@
45
54
  # include "config.h"
46
55
  # endif
47
56
 
57
+ # if HAVE_FLOOR
58
+ # ifndef EV_USE_FLOOR
59
+ # define EV_USE_FLOOR 1
60
+ # endif
61
+ # endif
62
+
48
63
  # if HAVE_CLOCK_SYSCALL
49
64
  # ifndef EV_USE_CLOCK_SYSCALL
50
65
  # define EV_USE_CLOCK_SYSCALL 1
@@ -55,7 +70,7 @@
55
70
  # define EV_USE_MONOTONIC 1
56
71
  # endif
57
72
  # endif
58
- # elif !defined(EV_USE_CLOCK_SYSCALL)
73
+ # elif !defined EV_USE_CLOCK_SYSCALL
59
74
  # define EV_USE_CLOCK_SYSCALL 0
60
75
  # endif
61
76
 
@@ -111,6 +126,24 @@
111
126
  # define EV_USE_EPOLL 0
112
127
  # endif
113
128
 
129
+ # if HAVE_LINUX_AIO_ABI_H
130
+ # ifndef EV_USE_LINUXAIO
131
+ # define EV_USE_LINUXAIO 0 /* was: EV_FEATURE_BACKENDS, always off by default */
132
+ # endif
133
+ # else
134
+ # undef EV_USE_LINUXAIO
135
+ # define EV_USE_LINUXAIO 0
136
+ # endif
137
+
138
+ # if HAVE_LINUX_FS_H && HAVE_SYS_TIMERFD_H && HAVE_KERNEL_RWF_T
139
+ # ifndef EV_USE_IOURING
140
+ # define EV_USE_IOURING EV_FEATURE_BACKENDS
141
+ # endif
142
+ # else
143
+ # undef EV_USE_IOURING
144
+ # define EV_USE_IOURING 0
145
+ # endif
146
+
114
147
  # if HAVE_KQUEUE && HAVE_SYS_EVENT_H
115
148
  # ifndef EV_USE_KQUEUE
116
149
  # define EV_USE_KQUEUE EV_FEATURE_BACKENDS
@@ -156,9 +189,27 @@
156
189
  # define EV_USE_EVENTFD 0
157
190
  # endif
158
191
 
192
+ # if HAVE_SYS_TIMERFD_H
193
+ # ifndef EV_USE_TIMERFD
194
+ # define EV_USE_TIMERFD EV_FEATURE_OS
195
+ # endif
196
+ # else
197
+ # undef EV_USE_TIMERFD
198
+ # define EV_USE_TIMERFD 0
199
+ # endif
200
+
159
201
  #endif
160
202
 
161
- #include <math.h>
203
+ /* OS X, in its infinite idiocy, actually HARDCODES
204
+ * a limit of 1024 into their select. Where people have brains,
205
+ * OS X engineers apparently have a vacuum. Or maybe they were
206
+ * ordered to have a vacuum, or they do anything for money.
207
+ * This might help. Or not.
208
+ * Note that this must be defined early, as other include files
209
+ * will rely on this define as well.
210
+ */
211
+ #define _DARWIN_UNLIMITED_SELECT 1
212
+
162
213
  #include <stdlib.h>
163
214
  #include <string.h>
164
215
  #include <fcntl.h>
@@ -180,7 +231,16 @@
180
231
  # include "ev.h"
181
232
  #endif
182
233
 
183
- EV_CPP(extern "C" {)
234
+ #if EV_NO_THREADS
235
+ # undef EV_NO_SMP
236
+ # define EV_NO_SMP 1
237
+ # undef ECB_NO_THREADS
238
+ # define ECB_NO_THREADS 1
239
+ #endif
240
+ #if EV_NO_SMP
241
+ # undef EV_NO_SMP
242
+ # define ECB_NO_SMP 1
243
+ #endif
184
244
 
185
245
  #ifndef _WIN32
186
246
  # include <sys/time.h>
@@ -189,6 +249,7 @@ EV_CPP(extern "C" {)
189
249
  #else
190
250
  # include <io.h>
191
251
  # define WIN32_LEAN_AND_MEAN
252
+ # include <winsock2.h>
192
253
  # include <windows.h>
193
254
  # ifndef EV_SELECT_IS_WINSOCKET
194
255
  # define EV_SELECT_IS_WINSOCKET 1
@@ -196,54 +257,56 @@ EV_CPP(extern "C" {)
196
257
  # undef EV_AVOID_STDIO
197
258
  #endif
198
259
 
199
- /* OS X, in its infinite idiocy, actually HARDCODES
200
- * a limit of 1024 into their select. Where people have brains,
201
- * OS X engineers apparently have a vacuum. Or maybe they were
202
- * ordered to have a vacuum, or they do anything for money.
203
- * This might help. Or not.
204
- */
205
- #define _DARWIN_UNLIMITED_SELECT 1
206
-
207
260
  /* this block tries to deduce configuration from header-defined symbols and defaults */
208
261
 
209
262
  /* try to deduce the maximum number of signals on this platform */
210
- #if defined (EV_NSIG)
263
+ #if defined EV_NSIG
211
264
  /* use what's provided */
212
- #elif defined (NSIG)
265
+ #elif defined NSIG
213
266
  # define EV_NSIG (NSIG)
214
- #elif defined(_NSIG)
267
+ #elif defined _NSIG
215
268
  # define EV_NSIG (_NSIG)
216
- #elif defined (SIGMAX)
269
+ #elif defined SIGMAX
217
270
  # define EV_NSIG (SIGMAX+1)
218
- #elif defined (SIG_MAX)
271
+ #elif defined SIG_MAX
219
272
  # define EV_NSIG (SIG_MAX+1)
220
- #elif defined (_SIG_MAX)
273
+ #elif defined _SIG_MAX
221
274
  # define EV_NSIG (_SIG_MAX+1)
222
- #elif defined (MAXSIG)
275
+ #elif defined MAXSIG
223
276
  # define EV_NSIG (MAXSIG+1)
224
- #elif defined (MAX_SIG)
277
+ #elif defined MAX_SIG
225
278
  # define EV_NSIG (MAX_SIG+1)
226
- #elif defined (SIGARRAYSIZE)
279
+ #elif defined SIGARRAYSIZE
227
280
  # define EV_NSIG (SIGARRAYSIZE) /* Assume ary[SIGARRAYSIZE] */
228
- #elif defined (_sys_nsig)
281
+ #elif defined _sys_nsig
229
282
  # define EV_NSIG (_sys_nsig) /* Solaris 2.5 */
230
283
  #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
284
+ # define EV_NSIG (8 * sizeof (sigset_t) + 1)
285
+ #endif
286
+
287
+ #ifndef EV_USE_FLOOR
288
+ # define EV_USE_FLOOR 0
235
289
  #endif
236
290
 
237
291
  #ifndef EV_USE_CLOCK_SYSCALL
238
- # if __linux && __GLIBC__ >= 2
292
+ # if __linux && __GLIBC__ == 2 && __GLIBC_MINOR__ < 17
239
293
  # define EV_USE_CLOCK_SYSCALL EV_FEATURE_OS
240
294
  # else
241
295
  # define EV_USE_CLOCK_SYSCALL 0
242
296
  # endif
243
297
  #endif
244
298
 
299
+ #if !(_POSIX_TIMERS > 0)
300
+ # ifndef EV_USE_MONOTONIC
301
+ # define EV_USE_MONOTONIC 0
302
+ # endif
303
+ # ifndef EV_USE_REALTIME
304
+ # define EV_USE_REALTIME 0
305
+ # endif
306
+ #endif
307
+
245
308
  #ifndef EV_USE_MONOTONIC
246
- # if defined (_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
309
+ # if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
247
310
  # define EV_USE_MONOTONIC EV_FEATURE_OS
248
311
  # else
249
312
  # define EV_USE_MONOTONIC 0
@@ -290,6 +353,14 @@ EV_CPP(extern "C" {)
290
353
  # define EV_USE_PORT 0
291
354
  #endif
292
355
 
356
+ #ifndef EV_USE_LINUXAIO
357
+ # define EV_USE_LINUXAIO 0
358
+ #endif
359
+
360
+ #ifndef EV_USE_IOURING
361
+ # define EV_USE_IOURING 0
362
+ #endif
363
+
293
364
  #ifndef EV_USE_INOTIFY
294
365
  # if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 4))
295
366
  # define EV_USE_INOTIFY EV_FEATURE_OS
@@ -322,6 +393,14 @@ EV_CPP(extern "C" {)
322
393
  # endif
323
394
  #endif
324
395
 
396
+ #ifndef EV_USE_TIMERFD
397
+ # if __linux && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8))
398
+ # define EV_USE_TIMERFD EV_FEATURE_OS
399
+ # else
400
+ # define EV_USE_TIMERFD 0
401
+ # endif
402
+ #endif
403
+
325
404
  #if 0 /* debugging */
326
405
  # define EV_VERIFY 3
327
406
  # define EV_USE_4HEAP 1
@@ -340,14 +419,31 @@ EV_CPP(extern "C" {)
340
419
  # define EV_HEAP_CACHE_AT EV_FEATURE_DATA
341
420
  #endif
342
421
 
422
+ #ifdef __ANDROID__
423
+ /* supposedly, android doesn't typedef fd_mask */
424
+ # undef EV_USE_SELECT
425
+ # define EV_USE_SELECT 0
426
+ /* supposedly, we need to include syscall.h, not sys/syscall.h, so just disable */
427
+ # undef EV_USE_CLOCK_SYSCALL
428
+ # define EV_USE_CLOCK_SYSCALL 0
429
+ #endif
430
+
431
+ /* aix's poll.h seems to cause lots of trouble */
432
+ #ifdef _AIX
433
+ /* AIX has a completely broken poll.h header */
434
+ # undef EV_USE_POLL
435
+ # define EV_USE_POLL 0
436
+ #endif
437
+
343
438
  /* on linux, we can use a (slow) syscall to avoid a dependency on pthread, */
344
439
  /* which makes programs even slower. might work on other unices, too. */
345
440
  #if EV_USE_CLOCK_SYSCALL
346
- # include <syscall.h>
441
+ # include <sys/syscall.h>
347
442
  # ifdef SYS_clock_gettime
348
443
  # define clock_gettime(id, ts) syscall (SYS_clock_gettime, (id), (ts))
349
444
  # undef EV_USE_MONOTONIC
350
445
  # define EV_USE_MONOTONIC 1
446
+ # define EV_NEED_SYSCALL 1
351
447
  # else
352
448
  # undef EV_USE_CLOCK_SYSCALL
353
449
  # define EV_USE_CLOCK_SYSCALL 0
@@ -356,12 +452,6 @@ EV_CPP(extern "C" {)
356
452
 
357
453
  /* this block fixes any misconfiguration where we know we run into trouble otherwise */
358
454
 
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
455
  #ifndef CLOCK_MONOTONIC
366
456
  # undef EV_USE_MONOTONIC
367
457
  # define EV_USE_MONOTONIC 0
@@ -379,11 +469,36 @@ EV_CPP(extern "C" {)
379
469
 
380
470
  #if !EV_USE_NANOSLEEP
381
471
  /* hp-ux has it in sys/time.h, which we unconditionally include above */
382
- # if !defined(_WIN32) && !defined(__hpux)
472
+ # if !defined _WIN32 && !defined __hpux
383
473
  # include <sys/select.h>
384
474
  # endif
385
475
  #endif
386
476
 
477
+ #if EV_USE_LINUXAIO
478
+ # include <sys/syscall.h>
479
+ # if SYS_io_getevents && EV_USE_EPOLL /* linuxaio backend requires epoll backend */
480
+ # define EV_NEED_SYSCALL 1
481
+ # else
482
+ # undef EV_USE_LINUXAIO
483
+ # define EV_USE_LINUXAIO 0
484
+ # endif
485
+ #endif
486
+
487
+ #if EV_USE_IOURING
488
+ # include <sys/syscall.h>
489
+ # if !SYS_io_uring_setup && __linux && !__alpha
490
+ # define SYS_io_uring_setup 425
491
+ # define SYS_io_uring_enter 426
492
+ # define SYS_io_uring_wregister 427
493
+ # endif
494
+ # if SYS_io_uring_setup && EV_USE_EPOLL /* iouring backend requires epoll backend */
495
+ # define EV_NEED_SYSCALL 1
496
+ # else
497
+ # undef EV_USE_IOURING
498
+ # define EV_USE_IOURING 0
499
+ # endif
500
+ #endif
501
+
387
502
  #if EV_USE_INOTIFY
388
503
  # include <sys/statfs.h>
389
504
  # include <sys/inotify.h>
@@ -394,12 +509,8 @@ EV_CPP(extern "C" {)
394
509
  # endif
395
510
  #endif
396
511
 
397
- #if EV_SELECT_IS_WINSOCKET
398
- # include <winsock.h>
399
- #endif
400
-
401
512
  #if EV_USE_EVENTFD
402
- /* our minimum requirement is glibc 2.7 which has the stub, but not the header */
513
+ /* our minimum requirement is glibc 2.7 which has the stub, but not the full header */
403
514
  # include <stdint.h>
404
515
  # ifndef EFD_NONBLOCK
405
516
  # define EFD_NONBLOCK O_NONBLOCK
@@ -415,7 +526,7 @@ EV_CPP(extern "C") int (eventfd) (unsigned int initval, int flags);
415
526
  #endif
416
527
 
417
528
  #if EV_USE_SIGNALFD
418
- /* our minimum requirement is glibc 2.7 which has the stub, but not the header */
529
+ /* our minimum requirement is glibc 2.7 which has the stub, but not the full header */
419
530
  # include <stdint.h>
420
531
  # ifndef SFD_NONBLOCK
421
532
  # define SFD_NONBLOCK O_NONBLOCK
@@ -427,7 +538,7 @@ EV_CPP(extern "C") int (eventfd) (unsigned int initval, int flags);
427
538
  # define SFD_CLOEXEC 02000000
428
539
  # endif
429
540
  # endif
430
- EV_CPP (extern "C") int signalfd (int fd, const sigset_t *mask, int flags);
541
+ EV_CPP (extern "C") int (signalfd) (int fd, const sigset_t *mask, int flags);
431
542
 
432
543
  struct signalfd_siginfo
433
544
  {
@@ -436,7 +547,17 @@ struct signalfd_siginfo
436
547
  };
437
548
  #endif
438
549
 
439
- /**/
550
+ /* for timerfd, libev core requires TFD_TIMER_CANCEL_ON_SET &c */
551
+ #if EV_USE_TIMERFD
552
+ # include <sys/timerfd.h>
553
+ /* timerfd is only used for periodics */
554
+ # if !(defined (TFD_TIMER_CANCEL_ON_SET) && defined (TFD_CLOEXEC) && defined (TFD_NONBLOCK)) || !EV_PERIODIC_ENABLE
555
+ # undef EV_USE_TIMERFD
556
+ # define EV_USE_TIMERFD 0
557
+ # endif
558
+ #endif
559
+
560
+ /*****************************************************************************/
440
561
 
441
562
  #if EV_VERIFY >= 3
442
563
  # define EV_FREQUENT_CHECK ev_verify (EV_A)
@@ -445,42 +566,1274 @@ struct signalfd_siginfo
445
566
  #endif
446
567
 
447
568
  /*
448
- * This is used to avoid floating point rounding problems.
449
- * It is added to ev_rt_now when scheduling periodics
450
- * to ensure progress, time-wise, even when rounding
451
- * errors are against us.
569
+ * This is used to work around floating point rounding problems.
452
570
  * This value is good at least till the year 4000.
453
- * Better solutions welcome.
454
571
  */
455
- #define TIME_EPSILON 0.0001220703125 /* 1/8192 */
572
+ #define MIN_INTERVAL 0.0001220703125 /* 1/2**13, good till 4000 */
573
+ /*#define MIN_INTERVAL 0.00000095367431640625 /* 1/2**20, good till 2200 */
574
+
575
+ #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
576
+ #define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */
577
+ #define MAX_BLOCKTIME2 1500001.07 /* same, but when timerfd is used to detect jumps, also safe delay to not overflow */
578
+
579
+ /* find a portable timestamp that is "always" in the future but fits into time_t.
580
+ * this is quite hard, and we are mostly guessing - we handle 32 bit signed/unsigned time_t,
581
+ * and sizes larger than 32 bit, and maybe the unlikely floating point time_t */
582
+ #define EV_TSTAMP_HUGE \
583
+ (sizeof (time_t) >= 8 ? 10000000000000. \
584
+ : 0 < (time_t)4294967295 ? 4294967295. \
585
+ : 2147483647.) \
586
+
587
+ #ifndef EV_TS_CONST
588
+ # define EV_TS_CONST(nv) nv
589
+ # define EV_TS_TO_MSEC(a) a * 1e3 + 0.9999
590
+ # define EV_TS_FROM_USEC(us) us * 1e-6
591
+ # define EV_TV_SET(tv,t) do { tv.tv_sec = (long)t; tv.tv_usec = (long)((t - tv.tv_sec) * 1e6); } while (0)
592
+ # define EV_TS_SET(ts,t) do { ts.tv_sec = (long)t; ts.tv_nsec = (long)((t - ts.tv_sec) * 1e9); } while (0)
593
+ # define EV_TV_GET(tv) ((tv).tv_sec + (tv).tv_usec * 1e-6)
594
+ # define EV_TS_GET(ts) ((ts).tv_sec + (ts).tv_nsec * 1e-9)
595
+ #endif
596
+
597
+ /* the following is ecb.h embedded into libev - use update_ev_c to update from an external copy */
598
+ /* ECB.H BEGIN */
599
+ /*
600
+ * libecb - http://software.schmorp.de/pkg/libecb
601
+ *
602
+ * Copyright (©) 2009-2015,2018-2020 Marc Alexander Lehmann <libecb@schmorp.de>
603
+ * Copyright (©) 2011 Emanuele Giaquinta
604
+ * All rights reserved.
605
+ *
606
+ * Redistribution and use in source and binary forms, with or without modifica-
607
+ * tion, are permitted provided that the following conditions are met:
608
+ *
609
+ * 1. Redistributions of source code must retain the above copyright notice,
610
+ * this list of conditions and the following disclaimer.
611
+ *
612
+ * 2. Redistributions in binary form must reproduce the above copyright
613
+ * notice, this list of conditions and the following disclaimer in the
614
+ * documentation and/or other materials provided with the distribution.
615
+ *
616
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
617
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
618
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
619
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
620
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
621
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
622
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
623
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
624
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
625
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
626
+ *
627
+ * Alternatively, the contents of this file may be used under the terms of
628
+ * the GNU General Public License ("GPL") version 2 or any later version,
629
+ * in which case the provisions of the GPL are applicable instead of
630
+ * the above. If you wish to allow the use of your version of this file
631
+ * only under the terms of the GPL and not to allow others to use your
632
+ * version of this file under the BSD license, indicate your decision
633
+ * by deleting the provisions above and replace them with the notice
634
+ * and other provisions required by the GPL. If you do not delete the
635
+ * provisions above, a recipient may use your version of this file under
636
+ * either the BSD or the GPL.
637
+ */
456
638
 
457
- #define MIN_TIMEJUMP 1. /* minimum timejump that gets detected (if monotonic clock available) */
458
- #define MAX_BLOCKTIME 59.743 /* never wait longer than this time (to detect time jumps) */
639
+ #ifndef ECB_H
640
+ #define ECB_H
641
+
642
+ /* 16 bits major, 16 bits minor */
643
+ #define ECB_VERSION 0x00010008
644
+
645
+ #include <string.h> /* for memcpy */
646
+
647
+ #if defined (_WIN32) && !defined (__MINGW32__)
648
+ typedef signed char int8_t;
649
+ typedef unsigned char uint8_t;
650
+ typedef signed char int_fast8_t;
651
+ typedef unsigned char uint_fast8_t;
652
+ typedef signed short int16_t;
653
+ typedef unsigned short uint16_t;
654
+ typedef signed int int_fast16_t;
655
+ typedef unsigned int uint_fast16_t;
656
+ typedef signed int int32_t;
657
+ typedef unsigned int uint32_t;
658
+ typedef signed int int_fast32_t;
659
+ typedef unsigned int uint_fast32_t;
660
+ #if __GNUC__
661
+ typedef signed long long int64_t;
662
+ typedef unsigned long long uint64_t;
663
+ #else /* _MSC_VER || __BORLANDC__ */
664
+ typedef signed __int64 int64_t;
665
+ typedef unsigned __int64 uint64_t;
666
+ #endif
667
+ typedef int64_t int_fast64_t;
668
+ typedef uint64_t uint_fast64_t;
669
+ #ifdef _WIN64
670
+ #define ECB_PTRSIZE 8
671
+ typedef uint64_t uintptr_t;
672
+ typedef int64_t intptr_t;
673
+ #else
674
+ #define ECB_PTRSIZE 4
675
+ typedef uint32_t uintptr_t;
676
+ typedef int32_t intptr_t;
677
+ #endif
678
+ #else
679
+ #include <inttypes.h>
680
+ #if (defined INTPTR_MAX ? INTPTR_MAX : ULONG_MAX) > 0xffffffffU
681
+ #define ECB_PTRSIZE 8
682
+ #else
683
+ #define ECB_PTRSIZE 4
684
+ #endif
685
+ #endif
686
+
687
+ #define ECB_GCC_AMD64 (__amd64 || __amd64__ || __x86_64 || __x86_64__)
688
+ #define ECB_MSVC_AMD64 (_M_AMD64 || _M_X64)
689
+
690
+ #ifndef ECB_OPTIMIZE_SIZE
691
+ #if __OPTIMIZE_SIZE__
692
+ #define ECB_OPTIMIZE_SIZE 1
693
+ #else
694
+ #define ECB_OPTIMIZE_SIZE 0
695
+ #endif
696
+ #endif
697
+
698
+ /* work around x32 idiocy by defining proper macros */
699
+ #if ECB_GCC_AMD64 || ECB_MSVC_AMD64
700
+ #if _ILP32
701
+ #define ECB_AMD64_X32 1
702
+ #else
703
+ #define ECB_AMD64 1
704
+ #endif
705
+ #endif
706
+
707
+ /* many compilers define _GNUC_ to some versions but then only implement
708
+ * what their idiot authors think are the "more important" extensions,
709
+ * causing enormous grief in return for some better fake benchmark numbers.
710
+ * or so.
711
+ * we try to detect these and simply assume they are not gcc - if they have
712
+ * an issue with that they should have done it right in the first place.
713
+ */
714
+ #if !defined __GNUC_MINOR__ || defined __INTEL_COMPILER || defined __SUNPRO_C || defined __SUNPRO_CC || defined __llvm__ || defined __clang__
715
+ #define ECB_GCC_VERSION(major,minor) 0
716
+ #else
717
+ #define ECB_GCC_VERSION(major,minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
718
+ #endif
459
719
 
460
- #define EV_TV_SET(tv,t) do { tv.tv_sec = (long)t; tv.tv_usec = (long)((t - tv.tv_sec) * 1e6); } while (0)
461
- #define EV_TS_SET(ts,t) do { ts.tv_sec = (long)t; ts.tv_nsec = (long)((t - ts.tv_sec) * 1e9); } while (0)
720
+ #define ECB_CLANG_VERSION(major,minor) (__clang_major__ > (major) || (__clang_major__ == (major) && __clang_minor__ >= (minor)))
462
721
 
463
- #if __GNUC__ >= 4
464
- # define expect(expr,value) __builtin_expect ((expr),(value))
465
- # define noinline __attribute__ ((noinline))
722
+ #if __clang__ && defined __has_builtin
723
+ #define ECB_CLANG_BUILTIN(x) __has_builtin (x)
466
724
  #else
467
- # define expect(expr,value) (expr)
468
- # define noinline
469
- # if __STDC_VERSION__ < 199901L && __GNUC__ < 2
470
- # define inline
471
- # endif
725
+ #define ECB_CLANG_BUILTIN(x) 0
726
+ #endif
727
+
728
+ #if __clang__ && defined __has_extension
729
+ #define ECB_CLANG_EXTENSION(x) __has_extension (x)
730
+ #else
731
+ #define ECB_CLANG_EXTENSION(x) 0
732
+ #endif
733
+
734
+ #define ECB_CPP (__cplusplus+0)
735
+ #define ECB_CPP11 (__cplusplus >= 201103L)
736
+ #define ECB_CPP14 (__cplusplus >= 201402L)
737
+ #define ECB_CPP17 (__cplusplus >= 201703L)
738
+
739
+ #if ECB_CPP
740
+ #define ECB_C 0
741
+ #define ECB_STDC_VERSION 0
742
+ #else
743
+ #define ECB_C 1
744
+ #define ECB_STDC_VERSION __STDC_VERSION__
745
+ #endif
746
+
747
+ #define ECB_C99 (ECB_STDC_VERSION >= 199901L)
748
+ #define ECB_C11 (ECB_STDC_VERSION >= 201112L)
749
+ #define ECB_C17 (ECB_STDC_VERSION >= 201710L)
750
+
751
+ #if ECB_CPP
752
+ #define ECB_EXTERN_C extern "C"
753
+ #define ECB_EXTERN_C_BEG ECB_EXTERN_C {
754
+ #define ECB_EXTERN_C_END }
755
+ #else
756
+ #define ECB_EXTERN_C extern
757
+ #define ECB_EXTERN_C_BEG
758
+ #define ECB_EXTERN_C_END
759
+ #endif
760
+
761
+ /*****************************************************************************/
762
+
763
+ /* ECB_NO_THREADS - ecb is not used by multiple threads, ever */
764
+ /* ECB_NO_SMP - ecb might be used in multiple threads, but only on a single cpu */
765
+
766
+ #if ECB_NO_THREADS
767
+ #define ECB_NO_SMP 1
768
+ #endif
769
+
770
+ #if ECB_NO_SMP
771
+ #define ECB_MEMORY_FENCE do { } while (0)
772
+ #endif
773
+
774
+ /* http://www-01.ibm.com/support/knowledgecenter/SSGH3R_13.1.0/com.ibm.xlcpp131.aix.doc/compiler_ref/compiler_builtins.html */
775
+ #if __xlC__ && ECB_CPP
776
+ #include <builtins.h>
777
+ #endif
778
+
779
+ #if 1400 <= _MSC_VER
780
+ #include <intrin.h> /* fence functions _ReadBarrier, also bit search functions _BitScanReverse */
781
+ #endif
782
+
783
+ #ifndef ECB_MEMORY_FENCE
784
+ #if ECB_GCC_VERSION(2,5) || defined __INTEL_COMPILER || (__llvm__ && __GNUC__) || __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
785
+ #define ECB_MEMORY_FENCE_RELAXED __asm__ __volatile__ ("" : : : "memory")
786
+ #if __i386 || __i386__
787
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("lock; orb $0, -1(%%esp)" : : : "memory")
788
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory")
789
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("" : : : "memory")
790
+ #elif ECB_GCC_AMD64
791
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mfence" : : : "memory")
792
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("" : : : "memory")
793
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("" : : : "memory")
794
+ #elif __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__
795
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory")
796
+ #elif defined __ARM_ARCH_2__ \
797
+ || defined __ARM_ARCH_3__ || defined __ARM_ARCH_3M__ \
798
+ || defined __ARM_ARCH_4__ || defined __ARM_ARCH_4T__ \
799
+ || defined __ARM_ARCH_5__ || defined __ARM_ARCH_5E__ \
800
+ || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__ \
801
+ || defined __ARM_ARCH_5TEJ__
802
+ /* should not need any, unless running old code on newer cpu - arm doesn't support that */
803
+ #elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ \
804
+ || defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__ \
805
+ || defined __ARM_ARCH_6T2__
806
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,5" : : "r" (0) : "memory")
807
+ #elif defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \
808
+ || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
809
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory")
810
+ #elif __aarch64__
811
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb ish" : : : "memory")
812
+ #elif (__sparc || __sparc__) && !(__sparc_v8__ || defined __sparcv8)
813
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad" : : : "memory")
814
+ #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory")
815
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore")
816
+ #elif defined __s390__ || defined __s390x__
817
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("bcr 15,0" : : : "memory")
818
+ #elif defined __mips__
819
+ /* GNU/Linux emulates sync on mips1 architectures, so we force its use */
820
+ /* anybody else who still uses mips1 is supposed to send in their version, with detection code. */
821
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ (".set mips2; sync; .set mips0" : : : "memory")
822
+ #elif defined __alpha__
823
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mb" : : : "memory")
824
+ #elif defined __hppa__
825
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory")
826
+ #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("")
827
+ #elif defined __ia64__
828
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mf" : : : "memory")
829
+ #elif defined __m68k__
830
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory")
831
+ #elif defined __m88k__
832
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("tb1 0,%%r0,128" : : : "memory")
833
+ #elif defined __sh__
834
+ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("" : : : "memory")
835
+ #endif
836
+ #endif
837
+ #endif
838
+
839
+ #ifndef ECB_MEMORY_FENCE
840
+ #if ECB_GCC_VERSION(4,7)
841
+ /* see comment below (stdatomic.h) about the C11 memory model. */
842
+ #define ECB_MEMORY_FENCE __atomic_thread_fence (__ATOMIC_SEQ_CST)
843
+ #define ECB_MEMORY_FENCE_ACQUIRE __atomic_thread_fence (__ATOMIC_ACQUIRE)
844
+ #define ECB_MEMORY_FENCE_RELEASE __atomic_thread_fence (__ATOMIC_RELEASE)
845
+ #define ECB_MEMORY_FENCE_RELAXED __atomic_thread_fence (__ATOMIC_RELAXED)
846
+
847
+ #elif ECB_CLANG_EXTENSION(c_atomic)
848
+ /* see comment below (stdatomic.h) about the C11 memory model. */
849
+ #define ECB_MEMORY_FENCE __c11_atomic_thread_fence (__ATOMIC_SEQ_CST)
850
+ #define ECB_MEMORY_FENCE_ACQUIRE __c11_atomic_thread_fence (__ATOMIC_ACQUIRE)
851
+ #define ECB_MEMORY_FENCE_RELEASE __c11_atomic_thread_fence (__ATOMIC_RELEASE)
852
+ #define ECB_MEMORY_FENCE_RELAXED __c11_atomic_thread_fence (__ATOMIC_RELAXED)
853
+
854
+ #elif ECB_GCC_VERSION(4,4) || defined __INTEL_COMPILER || defined __clang__
855
+ #define ECB_MEMORY_FENCE __sync_synchronize ()
856
+ #elif _MSC_VER >= 1500 /* VC++ 2008 */
857
+ /* apparently, microsoft broke all the memory barrier stuff in Visual Studio 2008... */
858
+ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
859
+ #define ECB_MEMORY_FENCE _ReadWriteBarrier (); MemoryBarrier()
860
+ #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier (); MemoryBarrier() /* according to msdn, _ReadBarrier is not a load fence */
861
+ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier (); MemoryBarrier()
862
+ #elif _MSC_VER >= 1400 /* VC++ 2005 */
863
+ #pragma intrinsic(_ReadBarrier,_WriteBarrier,_ReadWriteBarrier)
864
+ #define ECB_MEMORY_FENCE _ReadWriteBarrier ()
865
+ #define ECB_MEMORY_FENCE_ACQUIRE _ReadWriteBarrier () /* according to msdn, _ReadBarrier is not a load fence */
866
+ #define ECB_MEMORY_FENCE_RELEASE _WriteBarrier ()
867
+ #elif defined _WIN32
868
+ #include <WinNT.h>
869
+ #define ECB_MEMORY_FENCE MemoryBarrier () /* actually just xchg on x86... scary */
870
+ #elif __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
871
+ #include <mbarrier.h>
872
+ #define ECB_MEMORY_FENCE __machine_rw_barrier ()
873
+ #define ECB_MEMORY_FENCE_ACQUIRE __machine_acq_barrier ()
874
+ #define ECB_MEMORY_FENCE_RELEASE __machine_rel_barrier ()
875
+ #define ECB_MEMORY_FENCE_RELAXED __compiler_barrier ()
876
+ #elif __xlC__
877
+ #define ECB_MEMORY_FENCE __sync ()
878
+ #endif
879
+ #endif
880
+
881
+ #ifndef ECB_MEMORY_FENCE
882
+ #if ECB_C11 && !defined __STDC_NO_ATOMICS__
883
+ /* we assume that these memory fences work on all variables/all memory accesses, */
884
+ /* not just C11 atomics and atomic accesses */
885
+ #include <stdatomic.h>
886
+ #define ECB_MEMORY_FENCE atomic_thread_fence (memory_order_seq_cst)
887
+ #define ECB_MEMORY_FENCE_ACQUIRE atomic_thread_fence (memory_order_acquire)
888
+ #define ECB_MEMORY_FENCE_RELEASE atomic_thread_fence (memory_order_release)
889
+ #endif
890
+ #endif
891
+
892
+ #ifndef ECB_MEMORY_FENCE
893
+ #if !ECB_AVOID_PTHREADS
894
+ /*
895
+ * if you get undefined symbol references to pthread_mutex_lock,
896
+ * or failure to find pthread.h, then you should implement
897
+ * the ECB_MEMORY_FENCE operations for your cpu/compiler
898
+ * OR provide pthread.h and link against the posix thread library
899
+ * of your system.
900
+ */
901
+ #include <pthread.h>
902
+ #define ECB_NEEDS_PTHREADS 1
903
+ #define ECB_MEMORY_FENCE_NEEDS_PTHREADS 1
904
+
905
+ static pthread_mutex_t ecb_mf_lock = PTHREAD_MUTEX_INITIALIZER;
906
+ #define ECB_MEMORY_FENCE do { pthread_mutex_lock (&ecb_mf_lock); pthread_mutex_unlock (&ecb_mf_lock); } while (0)
907
+ #endif
908
+ #endif
909
+
910
+ #if !defined ECB_MEMORY_FENCE_ACQUIRE && defined ECB_MEMORY_FENCE
911
+ #define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
912
+ #endif
913
+
914
+ #if !defined ECB_MEMORY_FENCE_RELEASE && defined ECB_MEMORY_FENCE
915
+ #define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
916
+ #endif
917
+
918
+ #if !defined ECB_MEMORY_FENCE_RELAXED && defined ECB_MEMORY_FENCE
919
+ #define ECB_MEMORY_FENCE_RELAXED ECB_MEMORY_FENCE /* very heavy-handed */
920
+ #endif
921
+
922
+ /*****************************************************************************/
923
+
924
+ #if ECB_CPP
925
+ #define ecb_inline static inline
926
+ #elif ECB_GCC_VERSION(2,5)
927
+ #define ecb_inline static __inline__
928
+ #elif ECB_C99
929
+ #define ecb_inline static inline
930
+ #else
931
+ #define ecb_inline static
932
+ #endif
933
+
934
+ #if ECB_GCC_VERSION(3,3)
935
+ #define ecb_restrict __restrict__
936
+ #elif ECB_C99
937
+ #define ecb_restrict restrict
938
+ #else
939
+ #define ecb_restrict
940
+ #endif
941
+
942
+ typedef int ecb_bool;
943
+
944
+ #define ECB_CONCAT_(a, b) a ## b
945
+ #define ECB_CONCAT(a, b) ECB_CONCAT_(a, b)
946
+ #define ECB_STRINGIFY_(a) # a
947
+ #define ECB_STRINGIFY(a) ECB_STRINGIFY_(a)
948
+ #define ECB_STRINGIFY_EXPR(expr) ((expr), ECB_STRINGIFY_ (expr))
949
+
950
+ #define ecb_function_ ecb_inline
951
+
952
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_VERSION(2,8)
953
+ #define ecb_attribute(attrlist) __attribute__ (attrlist)
954
+ #else
955
+ #define ecb_attribute(attrlist)
956
+ #endif
957
+
958
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_constant_p)
959
+ #define ecb_is_constant(expr) __builtin_constant_p (expr)
960
+ #else
961
+ /* possible C11 impl for integral types
962
+ typedef struct ecb_is_constant_struct ecb_is_constant_struct;
963
+ #define ecb_is_constant(expr) _Generic ((1 ? (struct ecb_is_constant_struct *)0 : (void *)((expr) - (expr)), ecb_is_constant_struct *: 0, default: 1)) */
964
+
965
+ #define ecb_is_constant(expr) 0
966
+ #endif
967
+
968
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_expect)
969
+ #define ecb_expect(expr,value) __builtin_expect ((expr),(value))
970
+ #else
971
+ #define ecb_expect(expr,value) (expr)
972
+ #endif
973
+
974
+ #if ECB_GCC_VERSION(3,1) || ECB_CLANG_BUILTIN(__builtin_prefetch)
975
+ #define ecb_prefetch(addr,rw,locality) __builtin_prefetch (addr, rw, locality)
976
+ #else
977
+ #define ecb_prefetch(addr,rw,locality)
978
+ #endif
979
+
980
+ /* no emulation for ecb_decltype */
981
+ #if ECB_CPP11
982
+ // older implementations might have problems with decltype(x)::type, work around it
983
+ template<class T> struct ecb_decltype_t { typedef T type; };
984
+ #define ecb_decltype(x) ecb_decltype_t<decltype (x)>::type
985
+ #elif ECB_GCC_VERSION(3,0) || ECB_CLANG_VERSION(2,8)
986
+ #define ecb_decltype(x) __typeof__ (x)
987
+ #endif
988
+
989
+ #if _MSC_VER >= 1300
990
+ #define ecb_deprecated __declspec (deprecated)
991
+ #else
992
+ #define ecb_deprecated ecb_attribute ((__deprecated__))
993
+ #endif
994
+
995
+ #if _MSC_VER >= 1500
996
+ #define ecb_deprecated_message(msg) __declspec (deprecated (msg))
997
+ #elif ECB_GCC_VERSION(4,5)
998
+ #define ecb_deprecated_message(msg) ecb_attribute ((__deprecated__ (msg))
999
+ #else
1000
+ #define ecb_deprecated_message(msg) ecb_deprecated
1001
+ #endif
1002
+
1003
+ #if _MSC_VER >= 1400
1004
+ #define ecb_noinline __declspec (noinline)
1005
+ #else
1006
+ #define ecb_noinline ecb_attribute ((__noinline__))
1007
+ #endif
1008
+
1009
+ #define ecb_unused ecb_attribute ((__unused__))
1010
+ #define ecb_const ecb_attribute ((__const__))
1011
+ #define ecb_pure ecb_attribute ((__pure__))
1012
+
1013
+ #if ECB_C11 || __IBMC_NORETURN
1014
+ /* http://www-01.ibm.com/support/knowledgecenter/SSGH3R_13.1.0/com.ibm.xlcpp131.aix.doc/language_ref/noreturn.html */
1015
+ #define ecb_noreturn _Noreturn
1016
+ #elif ECB_CPP11
1017
+ #define ecb_noreturn [[noreturn]]
1018
+ #elif _MSC_VER >= 1200
1019
+ /* http://msdn.microsoft.com/en-us/library/k6ktzx3s.aspx */
1020
+ #define ecb_noreturn __declspec (noreturn)
1021
+ #else
1022
+ #define ecb_noreturn ecb_attribute ((__noreturn__))
1023
+ #endif
1024
+
1025
+ #if ECB_GCC_VERSION(4,3)
1026
+ #define ecb_artificial ecb_attribute ((__artificial__))
1027
+ #define ecb_hot ecb_attribute ((__hot__))
1028
+ #define ecb_cold ecb_attribute ((__cold__))
1029
+ #else
1030
+ #define ecb_artificial
1031
+ #define ecb_hot
1032
+ #define ecb_cold
1033
+ #endif
1034
+
1035
+ /* put around conditional expressions if you are very sure that the */
1036
+ /* expression is mostly true or mostly false. note that these return */
1037
+ /* booleans, not the expression. */
1038
+ #define ecb_expect_false(expr) ecb_expect (!!(expr), 0)
1039
+ #define ecb_expect_true(expr) ecb_expect (!!(expr), 1)
1040
+ /* for compatibility to the rest of the world */
1041
+ #define ecb_likely(expr) ecb_expect_true (expr)
1042
+ #define ecb_unlikely(expr) ecb_expect_false (expr)
1043
+
1044
+ /* count trailing zero bits and count # of one bits */
1045
+ #if ECB_GCC_VERSION(3,4) \
1046
+ || (ECB_CLANG_BUILTIN(__builtin_clz) && ECB_CLANG_BUILTIN(__builtin_clzll) \
1047
+ && ECB_CLANG_BUILTIN(__builtin_ctz) && ECB_CLANG_BUILTIN(__builtin_ctzll) \
1048
+ && ECB_CLANG_BUILTIN(__builtin_popcount))
1049
+ /* we assume int == 32 bit, long == 32 or 64 bit and long long == 64 bit */
1050
+ #define ecb_ld32(x) (__builtin_clz (x) ^ 31)
1051
+ #define ecb_ld64(x) (__builtin_clzll (x) ^ 63)
1052
+ #define ecb_ctz32(x) __builtin_ctz (x)
1053
+ #define ecb_ctz64(x) __builtin_ctzll (x)
1054
+ #define ecb_popcount32(x) __builtin_popcount (x)
1055
+ /* no popcountll */
1056
+ #else
1057
+ ecb_function_ ecb_const int ecb_ctz32 (uint32_t x);
1058
+ ecb_function_ ecb_const int
1059
+ ecb_ctz32 (uint32_t x)
1060
+ {
1061
+ #if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM)
1062
+ unsigned long r;
1063
+ _BitScanForward (&r, x);
1064
+ return (int)r;
1065
+ #else
1066
+ int r = 0;
1067
+
1068
+ x &= ~x + 1; /* this isolates the lowest bit */
1069
+
1070
+ #if ECB_branchless_on_i386
1071
+ r += !!(x & 0xaaaaaaaa) << 0;
1072
+ r += !!(x & 0xcccccccc) << 1;
1073
+ r += !!(x & 0xf0f0f0f0) << 2;
1074
+ r += !!(x & 0xff00ff00) << 3;
1075
+ r += !!(x & 0xffff0000) << 4;
1076
+ #else
1077
+ if (x & 0xaaaaaaaa) r += 1;
1078
+ if (x & 0xcccccccc) r += 2;
1079
+ if (x & 0xf0f0f0f0) r += 4;
1080
+ if (x & 0xff00ff00) r += 8;
1081
+ if (x & 0xffff0000) r += 16;
1082
+ #endif
1083
+
1084
+ return r;
1085
+ #endif
1086
+ }
1087
+
1088
+ ecb_function_ ecb_const int ecb_ctz64 (uint64_t x);
1089
+ ecb_function_ ecb_const int
1090
+ ecb_ctz64 (uint64_t x)
1091
+ {
1092
+ #if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM)
1093
+ unsigned long r;
1094
+ _BitScanForward64 (&r, x);
1095
+ return (int)r;
1096
+ #else
1097
+ int shift = x & 0xffffffff ? 0 : 32;
1098
+ return ecb_ctz32 (x >> shift) + shift;
1099
+ #endif
1100
+ }
1101
+
1102
+ ecb_function_ ecb_const int ecb_popcount32 (uint32_t x);
1103
+ ecb_function_ ecb_const int
1104
+ ecb_popcount32 (uint32_t x)
1105
+ {
1106
+ x -= (x >> 1) & 0x55555555;
1107
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
1108
+ x = ((x >> 4) + x) & 0x0f0f0f0f;
1109
+ x *= 0x01010101;
1110
+
1111
+ return x >> 24;
1112
+ }
1113
+
1114
+ ecb_function_ ecb_const int ecb_ld32 (uint32_t x);
1115
+ ecb_function_ ecb_const int ecb_ld32 (uint32_t x)
1116
+ {
1117
+ #if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM)
1118
+ unsigned long r;
1119
+ _BitScanReverse (&r, x);
1120
+ return (int)r;
1121
+ #else
1122
+ int r = 0;
1123
+
1124
+ if (x >> 16) { x >>= 16; r += 16; }
1125
+ if (x >> 8) { x >>= 8; r += 8; }
1126
+ if (x >> 4) { x >>= 4; r += 4; }
1127
+ if (x >> 2) { x >>= 2; r += 2; }
1128
+ if (x >> 1) { r += 1; }
1129
+
1130
+ return r;
1131
+ #endif
1132
+ }
1133
+
1134
+ ecb_function_ ecb_const int ecb_ld64 (uint64_t x);
1135
+ ecb_function_ ecb_const int ecb_ld64 (uint64_t x)
1136
+ {
1137
+ #if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM)
1138
+ unsigned long r;
1139
+ _BitScanReverse64 (&r, x);
1140
+ return (int)r;
1141
+ #else
1142
+ int r = 0;
1143
+
1144
+ if (x >> 32) { x >>= 32; r += 32; }
1145
+
1146
+ return r + ecb_ld32 (x);
1147
+ #endif
1148
+ }
1149
+ #endif
1150
+
1151
+ ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x);
1152
+ ecb_function_ ecb_const ecb_bool ecb_is_pot32 (uint32_t x) { return !(x & (x - 1)); }
1153
+ ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x);
1154
+ ecb_function_ ecb_const ecb_bool ecb_is_pot64 (uint64_t x) { return !(x & (x - 1)); }
1155
+
1156
+ ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x);
1157
+ ecb_function_ ecb_const uint8_t ecb_bitrev8 (uint8_t x)
1158
+ {
1159
+ return ( (x * 0x0802U & 0x22110U)
1160
+ | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16;
1161
+ }
1162
+
1163
+ ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x);
1164
+ ecb_function_ ecb_const uint16_t ecb_bitrev16 (uint16_t x)
1165
+ {
1166
+ x = ((x >> 1) & 0x5555) | ((x & 0x5555) << 1);
1167
+ x = ((x >> 2) & 0x3333) | ((x & 0x3333) << 2);
1168
+ x = ((x >> 4) & 0x0f0f) | ((x & 0x0f0f) << 4);
1169
+ x = ( x >> 8 ) | ( x << 8);
1170
+
1171
+ return x;
1172
+ }
1173
+
1174
+ ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x);
1175
+ ecb_function_ ecb_const uint32_t ecb_bitrev32 (uint32_t x)
1176
+ {
1177
+ x = ((x >> 1) & 0x55555555) | ((x & 0x55555555) << 1);
1178
+ x = ((x >> 2) & 0x33333333) | ((x & 0x33333333) << 2);
1179
+ x = ((x >> 4) & 0x0f0f0f0f) | ((x & 0x0f0f0f0f) << 4);
1180
+ x = ((x >> 8) & 0x00ff00ff) | ((x & 0x00ff00ff) << 8);
1181
+ x = ( x >> 16 ) | ( x << 16);
1182
+
1183
+ return x;
1184
+ }
1185
+
1186
+ /* popcount64 is only available on 64 bit cpus as gcc builtin */
1187
+ /* so for this version we are lazy */
1188
+ ecb_function_ ecb_const int ecb_popcount64 (uint64_t x);
1189
+ ecb_function_ ecb_const int
1190
+ ecb_popcount64 (uint64_t x)
1191
+ {
1192
+ return ecb_popcount32 (x) + ecb_popcount32 (x >> 32);
1193
+ }
1194
+
1195
+ ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count);
1196
+ ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count);
1197
+ ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count);
1198
+ ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count);
1199
+ ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count);
1200
+ ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count);
1201
+ ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count);
1202
+ ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count);
1203
+
1204
+ ecb_inline ecb_const uint8_t ecb_rotl8 (uint8_t x, unsigned int count) { return (x >> ( 8 - count)) | (x << count); }
1205
+ ecb_inline ecb_const uint8_t ecb_rotr8 (uint8_t x, unsigned int count) { return (x << ( 8 - count)) | (x >> count); }
1206
+ ecb_inline ecb_const uint16_t ecb_rotl16 (uint16_t x, unsigned int count) { return (x >> (16 - count)) | (x << count); }
1207
+ ecb_inline ecb_const uint16_t ecb_rotr16 (uint16_t x, unsigned int count) { return (x << (16 - count)) | (x >> count); }
1208
+ ecb_inline ecb_const uint32_t ecb_rotl32 (uint32_t x, unsigned int count) { return (x >> (32 - count)) | (x << count); }
1209
+ ecb_inline ecb_const uint32_t ecb_rotr32 (uint32_t x, unsigned int count) { return (x << (32 - count)) | (x >> count); }
1210
+ ecb_inline ecb_const uint64_t ecb_rotl64 (uint64_t x, unsigned int count) { return (x >> (64 - count)) | (x << count); }
1211
+ ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { return (x << (64 - count)) | (x >> count); }
1212
+
1213
+ #if ECB_CPP
1214
+
1215
+ inline uint8_t ecb_ctz (uint8_t v) { return ecb_ctz32 (v); }
1216
+ inline uint16_t ecb_ctz (uint16_t v) { return ecb_ctz32 (v); }
1217
+ inline uint32_t ecb_ctz (uint32_t v) { return ecb_ctz32 (v); }
1218
+ inline uint64_t ecb_ctz (uint64_t v) { return ecb_ctz64 (v); }
1219
+
1220
+ inline bool ecb_is_pot (uint8_t v) { return ecb_is_pot32 (v); }
1221
+ inline bool ecb_is_pot (uint16_t v) { return ecb_is_pot32 (v); }
1222
+ inline bool ecb_is_pot (uint32_t v) { return ecb_is_pot32 (v); }
1223
+ inline bool ecb_is_pot (uint64_t v) { return ecb_is_pot64 (v); }
1224
+
1225
+ inline int ecb_ld (uint8_t v) { return ecb_ld32 (v); }
1226
+ inline int ecb_ld (uint16_t v) { return ecb_ld32 (v); }
1227
+ inline int ecb_ld (uint32_t v) { return ecb_ld32 (v); }
1228
+ inline int ecb_ld (uint64_t v) { return ecb_ld64 (v); }
1229
+
1230
+ inline int ecb_popcount (uint8_t v) { return ecb_popcount32 (v); }
1231
+ inline int ecb_popcount (uint16_t v) { return ecb_popcount32 (v); }
1232
+ inline int ecb_popcount (uint32_t v) { return ecb_popcount32 (v); }
1233
+ inline int ecb_popcount (uint64_t v) { return ecb_popcount64 (v); }
1234
+
1235
+ inline uint8_t ecb_bitrev (uint8_t v) { return ecb_bitrev8 (v); }
1236
+ inline uint16_t ecb_bitrev (uint16_t v) { return ecb_bitrev16 (v); }
1237
+ inline uint32_t ecb_bitrev (uint32_t v) { return ecb_bitrev32 (v); }
1238
+
1239
+ inline uint8_t ecb_rotl (uint8_t v, unsigned int count) { return ecb_rotl8 (v, count); }
1240
+ inline uint16_t ecb_rotl (uint16_t v, unsigned int count) { return ecb_rotl16 (v, count); }
1241
+ inline uint32_t ecb_rotl (uint32_t v, unsigned int count) { return ecb_rotl32 (v, count); }
1242
+ inline uint64_t ecb_rotl (uint64_t v, unsigned int count) { return ecb_rotl64 (v, count); }
1243
+
1244
+ inline uint8_t ecb_rotr (uint8_t v, unsigned int count) { return ecb_rotr8 (v, count); }
1245
+ inline uint16_t ecb_rotr (uint16_t v, unsigned int count) { return ecb_rotr16 (v, count); }
1246
+ inline uint32_t ecb_rotr (uint32_t v, unsigned int count) { return ecb_rotr32 (v, count); }
1247
+ inline uint64_t ecb_rotr (uint64_t v, unsigned int count) { return ecb_rotr64 (v, count); }
1248
+
472
1249
  #endif
473
1250
 
474
- #define expect_false(expr) expect ((expr) != 0, 0)
475
- #define expect_true(expr) expect ((expr) != 0, 1)
476
- #define inline_size static inline
1251
+ #if ECB_GCC_VERSION(4,3) || (ECB_CLANG_BUILTIN(__builtin_bswap32) && ECB_CLANG_BUILTIN(__builtin_bswap64))
1252
+ #if ECB_GCC_VERSION(4,8) || ECB_CLANG_BUILTIN(__builtin_bswap16)
1253
+ #define ecb_bswap16(x) __builtin_bswap16 (x)
1254
+ #else
1255
+ #define ecb_bswap16(x) (__builtin_bswap32 (x) >> 16)
1256
+ #endif
1257
+ #define ecb_bswap32(x) __builtin_bswap32 (x)
1258
+ #define ecb_bswap64(x) __builtin_bswap64 (x)
1259
+ #elif _MSC_VER
1260
+ #include <stdlib.h>
1261
+ #define ecb_bswap16(x) ((uint16_t)_byteswap_ushort ((uint16_t)(x)))
1262
+ #define ecb_bswap32(x) ((uint32_t)_byteswap_ulong ((uint32_t)(x)))
1263
+ #define ecb_bswap64(x) ((uint64_t)_byteswap_uint64 ((uint64_t)(x)))
1264
+ #else
1265
+ ecb_function_ ecb_const uint16_t ecb_bswap16 (uint16_t x);
1266
+ ecb_function_ ecb_const uint16_t
1267
+ ecb_bswap16 (uint16_t x)
1268
+ {
1269
+ return ecb_rotl16 (x, 8);
1270
+ }
1271
+
1272
+ ecb_function_ ecb_const uint32_t ecb_bswap32 (uint32_t x);
1273
+ ecb_function_ ecb_const uint32_t
1274
+ ecb_bswap32 (uint32_t x)
1275
+ {
1276
+ return (((uint32_t)ecb_bswap16 (x)) << 16) | ecb_bswap16 (x >> 16);
1277
+ }
1278
+
1279
+ ecb_function_ ecb_const uint64_t ecb_bswap64 (uint64_t x);
1280
+ ecb_function_ ecb_const uint64_t
1281
+ ecb_bswap64 (uint64_t x)
1282
+ {
1283
+ return (((uint64_t)ecb_bswap32 (x)) << 32) | ecb_bswap32 (x >> 32);
1284
+ }
1285
+ #endif
1286
+
1287
+ #if ECB_GCC_VERSION(4,5) || ECB_CLANG_BUILTIN(__builtin_unreachable)
1288
+ #define ecb_unreachable() __builtin_unreachable ()
1289
+ #else
1290
+ /* this seems to work fine, but gcc always emits a warning for it :/ */
1291
+ ecb_inline ecb_noreturn void ecb_unreachable (void);
1292
+ ecb_inline ecb_noreturn void ecb_unreachable (void) { }
1293
+ #endif
1294
+
1295
+ /* try to tell the compiler that some condition is definitely true */
1296
+ #define ecb_assume(cond) if (!(cond)) ecb_unreachable (); else 0
1297
+
1298
+ ecb_inline ecb_const uint32_t ecb_byteorder_helper (void);
1299
+ ecb_inline ecb_const uint32_t
1300
+ ecb_byteorder_helper (void)
1301
+ {
1302
+ /* the union code still generates code under pressure in gcc, */
1303
+ /* but less than using pointers, and always seems to */
1304
+ /* successfully return a constant. */
1305
+ /* the reason why we have this horrible preprocessor mess */
1306
+ /* is to avoid it in all cases, at least on common architectures */
1307
+ /* or when using a recent enough gcc version (>= 4.6) */
1308
+ #if (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
1309
+ || ((__i386 || __i386__ || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64) && !__VOS__)
1310
+ #define ECB_LITTLE_ENDIAN 1
1311
+ return 0x44332211;
1312
+ #elif (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) \
1313
+ || ((__AARCH64EB__ || __MIPSEB__ || __ARMEB__) && !__VOS__)
1314
+ #define ECB_BIG_ENDIAN 1
1315
+ return 0x11223344;
1316
+ #else
1317
+ union
1318
+ {
1319
+ uint8_t c[4];
1320
+ uint32_t u;
1321
+ } u = { 0x11, 0x22, 0x33, 0x44 };
1322
+ return u.u;
1323
+ #endif
1324
+ }
1325
+
1326
+ ecb_inline ecb_const ecb_bool ecb_big_endian (void);
1327
+ ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11223344; }
1328
+ ecb_inline ecb_const ecb_bool ecb_little_endian (void);
1329
+ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44332211; }
1330
+
1331
+ /*****************************************************************************/
1332
+ /* unaligned load/store */
1333
+
1334
+ ecb_inline uint_fast16_t ecb_be_u16_to_host (uint_fast16_t v) { return ecb_little_endian () ? ecb_bswap16 (v) : v; }
1335
+ ecb_inline uint_fast32_t ecb_be_u32_to_host (uint_fast32_t v) { return ecb_little_endian () ? ecb_bswap32 (v) : v; }
1336
+ ecb_inline uint_fast64_t ecb_be_u64_to_host (uint_fast64_t v) { return ecb_little_endian () ? ecb_bswap64 (v) : v; }
1337
+
1338
+ ecb_inline uint_fast16_t ecb_le_u16_to_host (uint_fast16_t v) { return ecb_big_endian () ? ecb_bswap16 (v) : v; }
1339
+ ecb_inline uint_fast32_t ecb_le_u32_to_host (uint_fast32_t v) { return ecb_big_endian () ? ecb_bswap32 (v) : v; }
1340
+ ecb_inline uint_fast64_t ecb_le_u64_to_host (uint_fast64_t v) { return ecb_big_endian () ? ecb_bswap64 (v) : v; }
1341
+
1342
+ ecb_inline uint_fast16_t ecb_peek_u16_u (const void *ptr) { uint16_t v; memcpy (&v, ptr, sizeof (v)); return v; }
1343
+ ecb_inline uint_fast32_t ecb_peek_u32_u (const void *ptr) { uint32_t v; memcpy (&v, ptr, sizeof (v)); return v; }
1344
+ ecb_inline uint_fast64_t ecb_peek_u64_u (const void *ptr) { uint64_t v; memcpy (&v, ptr, sizeof (v)); return v; }
1345
+
1346
+ ecb_inline uint_fast16_t ecb_peek_be_u16_u (const void *ptr) { return ecb_be_u16_to_host (ecb_peek_u16_u (ptr)); }
1347
+ ecb_inline uint_fast32_t ecb_peek_be_u32_u (const void *ptr) { return ecb_be_u32_to_host (ecb_peek_u32_u (ptr)); }
1348
+ ecb_inline uint_fast64_t ecb_peek_be_u64_u (const void *ptr) { return ecb_be_u64_to_host (ecb_peek_u64_u (ptr)); }
1349
+
1350
+ ecb_inline uint_fast16_t ecb_peek_le_u16_u (const void *ptr) { return ecb_le_u16_to_host (ecb_peek_u16_u (ptr)); }
1351
+ ecb_inline uint_fast32_t ecb_peek_le_u32_u (const void *ptr) { return ecb_le_u32_to_host (ecb_peek_u32_u (ptr)); }
1352
+ ecb_inline uint_fast64_t ecb_peek_le_u64_u (const void *ptr) { return ecb_le_u64_to_host (ecb_peek_u64_u (ptr)); }
1353
+
1354
+ ecb_inline uint_fast16_t ecb_host_to_be_u16 (uint_fast16_t v) { return ecb_little_endian () ? ecb_bswap16 (v) : v; }
1355
+ ecb_inline uint_fast32_t ecb_host_to_be_u32 (uint_fast32_t v) { return ecb_little_endian () ? ecb_bswap32 (v) : v; }
1356
+ ecb_inline uint_fast64_t ecb_host_to_be_u64 (uint_fast64_t v) { return ecb_little_endian () ? ecb_bswap64 (v) : v; }
1357
+
1358
+ ecb_inline uint_fast16_t ecb_host_to_le_u16 (uint_fast16_t v) { return ecb_big_endian () ? ecb_bswap16 (v) : v; }
1359
+ ecb_inline uint_fast32_t ecb_host_to_le_u32 (uint_fast32_t v) { return ecb_big_endian () ? ecb_bswap32 (v) : v; }
1360
+ ecb_inline uint_fast64_t ecb_host_to_le_u64 (uint_fast64_t v) { return ecb_big_endian () ? ecb_bswap64 (v) : v; }
1361
+
1362
+ ecb_inline void ecb_poke_u16_u (void *ptr, uint16_t v) { memcpy (ptr, &v, sizeof (v)); }
1363
+ ecb_inline void ecb_poke_u32_u (void *ptr, uint32_t v) { memcpy (ptr, &v, sizeof (v)); }
1364
+ ecb_inline void ecb_poke_u64_u (void *ptr, uint64_t v) { memcpy (ptr, &v, sizeof (v)); }
1365
+
1366
+ ecb_inline void ecb_poke_be_u16_u (void *ptr, uint_fast16_t v) { ecb_poke_u16_u (ptr, ecb_host_to_be_u16 (v)); }
1367
+ ecb_inline void ecb_poke_be_u32_u (void *ptr, uint_fast32_t v) { ecb_poke_u32_u (ptr, ecb_host_to_be_u32 (v)); }
1368
+ ecb_inline void ecb_poke_be_u64_u (void *ptr, uint_fast64_t v) { ecb_poke_u64_u (ptr, ecb_host_to_be_u64 (v)); }
1369
+
1370
+ ecb_inline void ecb_poke_le_u16_u (void *ptr, uint_fast16_t v) { ecb_poke_u16_u (ptr, ecb_host_to_le_u16 (v)); }
1371
+ ecb_inline void ecb_poke_le_u32_u (void *ptr, uint_fast32_t v) { ecb_poke_u32_u (ptr, ecb_host_to_le_u32 (v)); }
1372
+ ecb_inline void ecb_poke_le_u64_u (void *ptr, uint_fast64_t v) { ecb_poke_u64_u (ptr, ecb_host_to_le_u64 (v)); }
1373
+
1374
+ #if ECB_CPP
1375
+
1376
+ inline uint8_t ecb_bswap (uint8_t v) { return v; }
1377
+ inline uint16_t ecb_bswap (uint16_t v) { return ecb_bswap16 (v); }
1378
+ inline uint32_t ecb_bswap (uint32_t v) { return ecb_bswap32 (v); }
1379
+ inline uint64_t ecb_bswap (uint64_t v) { return ecb_bswap64 (v); }
1380
+
1381
+ template<typename T> inline T ecb_be_to_host (T v) { return ecb_little_endian () ? ecb_bswap (v) : v; }
1382
+ template<typename T> inline T ecb_le_to_host (T v) { return ecb_big_endian () ? ecb_bswap (v) : v; }
1383
+ template<typename T> inline T ecb_peek (const void *ptr) { return *(const T *)ptr; }
1384
+ template<typename T> inline T ecb_peek_be (const void *ptr) { return ecb_be_to_host (ecb_peek <T> (ptr)); }
1385
+ template<typename T> inline T ecb_peek_le (const void *ptr) { return ecb_le_to_host (ecb_peek <T> (ptr)); }
1386
+ template<typename T> inline T ecb_peek_u (const void *ptr) { T v; memcpy (&v, ptr, sizeof (v)); return v; }
1387
+ template<typename T> inline T ecb_peek_be_u (const void *ptr) { return ecb_be_to_host (ecb_peek_u<T> (ptr)); }
1388
+ template<typename T> inline T ecb_peek_le_u (const void *ptr) { return ecb_le_to_host (ecb_peek_u<T> (ptr)); }
1389
+
1390
+ template<typename T> inline T ecb_host_to_be (T v) { return ecb_little_endian () ? ecb_bswap (v) : v; }
1391
+ template<typename T> inline T ecb_host_to_le (T v) { return ecb_big_endian () ? ecb_bswap (v) : v; }
1392
+ template<typename T> inline void ecb_poke (void *ptr, T v) { *(T *)ptr = v; }
1393
+ template<typename T> inline void ecb_poke_be (void *ptr, T v) { return ecb_poke <T> (ptr, ecb_host_to_be (v)); }
1394
+ template<typename T> inline void ecb_poke_le (void *ptr, T v) { return ecb_poke <T> (ptr, ecb_host_to_le (v)); }
1395
+ template<typename T> inline void ecb_poke_u (void *ptr, T v) { memcpy (ptr, &v, sizeof (v)); }
1396
+ template<typename T> inline void ecb_poke_be_u (void *ptr, T v) { return ecb_poke_u<T> (ptr, ecb_host_to_be (v)); }
1397
+ template<typename T> inline void ecb_poke_le_u (void *ptr, T v) { return ecb_poke_u<T> (ptr, ecb_host_to_le (v)); }
1398
+
1399
+ #endif
1400
+
1401
+ /*****************************************************************************/
1402
+
1403
+ #if ECB_GCC_VERSION(3,0) || ECB_C99
1404
+ #define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0))
1405
+ #else
1406
+ #define ecb_mod(m,n) ((m) < 0 ? ((n) - 1 - ((-1 - (m)) % (n))) : ((m) % (n)))
1407
+ #endif
1408
+
1409
+ #if ECB_CPP
1410
+ template<typename T>
1411
+ static inline T ecb_div_rd (T val, T div)
1412
+ {
1413
+ return val < 0 ? - ((-val + div - 1) / div) : (val ) / div;
1414
+ }
1415
+ template<typename T>
1416
+ static inline T ecb_div_ru (T val, T div)
1417
+ {
1418
+ return val < 0 ? - ((-val ) / div) : (val + div - 1) / div;
1419
+ }
1420
+ #else
1421
+ #define ecb_div_rd(val,div) ((val) < 0 ? - ((-(val) + (div) - 1) / (div)) : ((val) ) / (div))
1422
+ #define ecb_div_ru(val,div) ((val) < 0 ? - ((-(val) ) / (div)) : ((val) + (div) - 1) / (div))
1423
+ #endif
1424
+
1425
+ #if ecb_cplusplus_does_not_suck
1426
+ /* does not work for local types (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm) */
1427
+ template<typename T, int N>
1428
+ static inline int ecb_array_length (const T (&arr)[N])
1429
+ {
1430
+ return N;
1431
+ }
1432
+ #else
1433
+ #define ecb_array_length(name) (sizeof (name) / sizeof (name [0]))
1434
+ #endif
1435
+
1436
+ /*****************************************************************************/
1437
+
1438
+ ecb_function_ ecb_const uint32_t ecb_binary16_to_binary32 (uint32_t x);
1439
+ ecb_function_ ecb_const uint32_t
1440
+ ecb_binary16_to_binary32 (uint32_t x)
1441
+ {
1442
+ unsigned int s = (x & 0x8000) << (31 - 15);
1443
+ int e = (x >> 10) & 0x001f;
1444
+ unsigned int m = x & 0x03ff;
1445
+
1446
+ if (ecb_expect_false (e == 31))
1447
+ /* infinity or NaN */
1448
+ e = 255 - (127 - 15);
1449
+ else if (ecb_expect_false (!e))
1450
+ {
1451
+ if (ecb_expect_true (!m))
1452
+ /* zero, handled by code below by forcing e to 0 */
1453
+ e = 0 - (127 - 15);
1454
+ else
1455
+ {
1456
+ /* subnormal, renormalise */
1457
+ unsigned int s = 10 - ecb_ld32 (m);
1458
+
1459
+ m = (m << s) & 0x3ff; /* mask implicit bit */
1460
+ e -= s - 1;
1461
+ }
1462
+ }
1463
+
1464
+ /* e and m now are normalised, or zero, (or inf or nan) */
1465
+ e += 127 - 15;
1466
+
1467
+ return s | (e << 23) | (m << (23 - 10));
1468
+ }
1469
+
1470
+ ecb_function_ ecb_const uint16_t ecb_binary32_to_binary16 (uint32_t x);
1471
+ ecb_function_ ecb_const uint16_t
1472
+ ecb_binary32_to_binary16 (uint32_t x)
1473
+ {
1474
+ unsigned int s = (x >> 16) & 0x00008000; /* sign bit, the easy part */
1475
+ unsigned int e = ((x >> 23) & 0x000000ff) - (127 - 15); /* the desired exponent */
1476
+ unsigned int m = x & 0x007fffff;
1477
+
1478
+ x &= 0x7fffffff;
1479
+
1480
+ /* if it's within range of binary16 normals, use fast path */
1481
+ if (ecb_expect_true (0x38800000 <= x && x <= 0x477fefff))
1482
+ {
1483
+ /* mantissa round-to-even */
1484
+ m += 0x00000fff + ((m >> (23 - 10)) & 1);
1485
+
1486
+ /* handle overflow */
1487
+ if (ecb_expect_false (m >= 0x00800000))
1488
+ {
1489
+ m >>= 1;
1490
+ e += 1;
1491
+ }
1492
+
1493
+ return s | (e << 10) | (m >> (23 - 10));
1494
+ }
1495
+
1496
+ /* handle large numbers and infinity */
1497
+ if (ecb_expect_true (0x477fefff < x && x <= 0x7f800000))
1498
+ return s | 0x7c00;
1499
+
1500
+ /* handle zero, subnormals and small numbers */
1501
+ if (ecb_expect_true (x < 0x38800000))
1502
+ {
1503
+ /* zero */
1504
+ if (ecb_expect_true (!x))
1505
+ return s;
1506
+
1507
+ /* handle subnormals */
1508
+
1509
+ /* too small, will be zero */
1510
+ if (e < (14 - 24)) /* might not be sharp, but is good enough */
1511
+ return s;
1512
+
1513
+ m |= 0x00800000; /* make implicit bit explicit */
1514
+
1515
+ /* very tricky - we need to round to the nearest e (+10) bit value */
1516
+ {
1517
+ unsigned int bits = 14 - e;
1518
+ unsigned int half = (1 << (bits - 1)) - 1;
1519
+ unsigned int even = (m >> bits) & 1;
1520
+
1521
+ /* if this overflows, we will end up with a normalised number */
1522
+ m = (m + half + even) >> bits;
1523
+ }
1524
+
1525
+ return s | m;
1526
+ }
1527
+
1528
+ /* handle NaNs, preserve leftmost nan bits, but make sure we don't turn them into infinities */
1529
+ m >>= 13;
1530
+
1531
+ return s | 0x7c00 | m | !m;
1532
+ }
1533
+
1534
+ /*******************************************************************************/
1535
+ /* floating point stuff, can be disabled by defining ECB_NO_LIBM */
1536
+
1537
+ /* basically, everything uses "ieee pure-endian" floating point numbers */
1538
+ /* the only noteworthy exception is ancient armle, which uses order 43218765 */
1539
+ #if 0 \
1540
+ || __i386 || __i386__ \
1541
+ || ECB_GCC_AMD64 \
1542
+ || __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__ \
1543
+ || defined __s390__ || defined __s390x__ \
1544
+ || defined __mips__ \
1545
+ || defined __alpha__ \
1546
+ || defined __hppa__ \
1547
+ || defined __ia64__ \
1548
+ || defined __m68k__ \
1549
+ || defined __m88k__ \
1550
+ || defined __sh__ \
1551
+ || defined _M_IX86 || defined ECB_MSVC_AMD64 || defined _M_IA64 \
1552
+ || (defined __arm__ && (defined __ARM_EABI__ || defined __EABI__ || defined __VFP_FP__ || defined _WIN32_WCE || defined __ANDROID__)) \
1553
+ || defined __aarch64__
1554
+ #define ECB_STDFP 1
1555
+ #else
1556
+ #define ECB_STDFP 0
1557
+ #endif
1558
+
1559
+ #ifndef ECB_NO_LIBM
1560
+
1561
+ #include <math.h> /* for frexp*, ldexp*, INFINITY, NAN */
1562
+
1563
+ /* only the oldest of old doesn't have this one. solaris. */
1564
+ #ifdef INFINITY
1565
+ #define ECB_INFINITY INFINITY
1566
+ #else
1567
+ #define ECB_INFINITY HUGE_VAL
1568
+ #endif
1569
+
1570
+ #ifdef NAN
1571
+ #define ECB_NAN NAN
1572
+ #else
1573
+ #define ECB_NAN ECB_INFINITY
1574
+ #endif
1575
+
1576
+ #if ECB_C99 || _XOPEN_VERSION >= 600 || _POSIX_VERSION >= 200112L
1577
+ #define ecb_ldexpf(x,e) ldexpf ((x), (e))
1578
+ #define ecb_frexpf(x,e) frexpf ((x), (e))
1579
+ #else
1580
+ #define ecb_ldexpf(x,e) (float) ldexp ((double) (x), (e))
1581
+ #define ecb_frexpf(x,e) (float) frexp ((double) (x), (e))
1582
+ #endif
1583
+
1584
+ /* convert a float to ieee single/binary32 */
1585
+ ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x);
1586
+ ecb_function_ ecb_const uint32_t
1587
+ ecb_float_to_binary32 (float x)
1588
+ {
1589
+ uint32_t r;
1590
+
1591
+ #if ECB_STDFP
1592
+ memcpy (&r, &x, 4);
1593
+ #else
1594
+ /* slow emulation, works for anything but -0 */
1595
+ uint32_t m;
1596
+ int e;
1597
+
1598
+ if (x == 0e0f ) return 0x00000000U;
1599
+ if (x > +3.40282346638528860e+38f) return 0x7f800000U;
1600
+ if (x < -3.40282346638528860e+38f) return 0xff800000U;
1601
+ if (x != x ) return 0x7fbfffffU;
1602
+
1603
+ m = ecb_frexpf (x, &e) * 0x1000000U;
1604
+
1605
+ r = m & 0x80000000U;
1606
+
1607
+ if (r)
1608
+ m = -m;
1609
+
1610
+ if (e <= -126)
1611
+ {
1612
+ m &= 0xffffffU;
1613
+ m >>= (-125 - e);
1614
+ e = -126;
1615
+ }
1616
+
1617
+ r |= (e + 126) << 23;
1618
+ r |= m & 0x7fffffU;
1619
+ #endif
1620
+
1621
+ return r;
1622
+ }
1623
+
1624
+ /* converts an ieee single/binary32 to a float */
1625
+ ecb_function_ ecb_const float ecb_binary32_to_float (uint32_t x);
1626
+ ecb_function_ ecb_const float
1627
+ ecb_binary32_to_float (uint32_t x)
1628
+ {
1629
+ float r;
1630
+
1631
+ #if ECB_STDFP
1632
+ memcpy (&r, &x, 4);
1633
+ #else
1634
+ /* emulation, only works for normals and subnormals and +0 */
1635
+ int neg = x >> 31;
1636
+ int e = (x >> 23) & 0xffU;
1637
+
1638
+ x &= 0x7fffffU;
1639
+
1640
+ if (e)
1641
+ x |= 0x800000U;
1642
+ else
1643
+ e = 1;
1644
+
1645
+ /* we distrust ldexpf a bit and do the 2**-24 scaling by an extra multiply */
1646
+ r = ecb_ldexpf (x * (0.5f / 0x800000U), e - 126);
1647
+
1648
+ r = neg ? -r : r;
1649
+ #endif
1650
+
1651
+ return r;
1652
+ }
1653
+
1654
+ /* convert a double to ieee double/binary64 */
1655
+ ecb_function_ ecb_const uint64_t ecb_double_to_binary64 (double x);
1656
+ ecb_function_ ecb_const uint64_t
1657
+ ecb_double_to_binary64 (double x)
1658
+ {
1659
+ uint64_t r;
1660
+
1661
+ #if ECB_STDFP
1662
+ memcpy (&r, &x, 8);
1663
+ #else
1664
+ /* slow emulation, works for anything but -0 */
1665
+ uint64_t m;
1666
+ int e;
1667
+
1668
+ if (x == 0e0 ) return 0x0000000000000000U;
1669
+ if (x > +1.79769313486231470e+308) return 0x7ff0000000000000U;
1670
+ if (x < -1.79769313486231470e+308) return 0xfff0000000000000U;
1671
+ if (x != x ) return 0X7ff7ffffffffffffU;
1672
+
1673
+ m = frexp (x, &e) * 0x20000000000000U;
1674
+
1675
+ r = m & 0x8000000000000000;;
1676
+
1677
+ if (r)
1678
+ m = -m;
1679
+
1680
+ if (e <= -1022)
1681
+ {
1682
+ m &= 0x1fffffffffffffU;
1683
+ m >>= (-1021 - e);
1684
+ e = -1022;
1685
+ }
1686
+
1687
+ r |= ((uint64_t)(e + 1022)) << 52;
1688
+ r |= m & 0xfffffffffffffU;
1689
+ #endif
1690
+
1691
+ return r;
1692
+ }
1693
+
1694
+ /* converts an ieee double/binary64 to a double */
1695
+ ecb_function_ ecb_const double ecb_binary64_to_double (uint64_t x);
1696
+ ecb_function_ ecb_const double
1697
+ ecb_binary64_to_double (uint64_t x)
1698
+ {
1699
+ double r;
1700
+
1701
+ #if ECB_STDFP
1702
+ memcpy (&r, &x, 8);
1703
+ #else
1704
+ /* emulation, only works for normals and subnormals and +0 */
1705
+ int neg = x >> 63;
1706
+ int e = (x >> 52) & 0x7ffU;
1707
+
1708
+ x &= 0xfffffffffffffU;
1709
+
1710
+ if (e)
1711
+ x |= 0x10000000000000U;
1712
+ else
1713
+ e = 1;
1714
+
1715
+ /* we distrust ldexp a bit and do the 2**-53 scaling by an extra multiply */
1716
+ r = ldexp (x * (0.5 / 0x10000000000000U), e - 1022);
1717
+
1718
+ r = neg ? -r : r;
1719
+ #endif
1720
+
1721
+ return r;
1722
+ }
1723
+
1724
+ /* convert a float to ieee half/binary16 */
1725
+ ecb_function_ ecb_const uint16_t ecb_float_to_binary16 (float x);
1726
+ ecb_function_ ecb_const uint16_t
1727
+ ecb_float_to_binary16 (float x)
1728
+ {
1729
+ return ecb_binary32_to_binary16 (ecb_float_to_binary32 (x));
1730
+ }
1731
+
1732
+ /* convert an ieee half/binary16 to float */
1733
+ ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x);
1734
+ ecb_function_ ecb_const float
1735
+ ecb_binary16_to_float (uint16_t x)
1736
+ {
1737
+ return ecb_binary32_to_float (ecb_binary16_to_binary32 (x));
1738
+ }
1739
+
1740
+ #endif
1741
+
1742
+ #endif
1743
+
1744
+ /* ECB.H END */
1745
+
1746
+ #if ECB_MEMORY_FENCE_NEEDS_PTHREADS
1747
+ /* if your architecture doesn't need memory fences, e.g. because it is
1748
+ * single-cpu/core, or if you use libev in a project that doesn't use libev
1749
+ * from multiple threads, then you can define ECB_NO_THREADS when compiling
1750
+ * libev, in which cases the memory fences become nops.
1751
+ * alternatively, you can remove this #error and link against libpthread,
1752
+ * which will then provide the memory fences.
1753
+ */
1754
+ # error "memory fences not defined for your architecture, please report"
1755
+ #endif
1756
+
1757
+ #ifndef ECB_MEMORY_FENCE
1758
+ # define ECB_MEMORY_FENCE do { } while (0)
1759
+ # define ECB_MEMORY_FENCE_ACQUIRE ECB_MEMORY_FENCE
1760
+ # define ECB_MEMORY_FENCE_RELEASE ECB_MEMORY_FENCE
1761
+ #endif
1762
+
1763
+ #define inline_size ecb_inline
477
1764
 
478
1765
  #if EV_FEATURE_CODE
479
- # define inline_speed static inline
1766
+ # define inline_speed ecb_inline
480
1767
  #else
481
- # define inline_speed static noinline
1768
+ # define inline_speed ecb_noinline static
482
1769
  #endif
483
1770
 
1771
+ /*****************************************************************************/
1772
+ /* raw syscall wrappers */
1773
+
1774
+ #if EV_NEED_SYSCALL
1775
+
1776
+ #include <sys/syscall.h>
1777
+
1778
+ /*
1779
+ * define some syscall wrappers for common architectures
1780
+ * this is mostly for nice looks during debugging, not performance.
1781
+ * our syscalls return < 0, not == -1, on error. which is good
1782
+ * enough for linux aio.
1783
+ * TODO: arm is also common nowadays, maybe even mips and x86
1784
+ * TODO: after implementing this, it suddenly looks like overkill, but its hard to remove...
1785
+ */
1786
+ #if __GNUC__ && __linux && ECB_AMD64 && !EV_FEATURE_CODE
1787
+ /* the costly errno access probably kills this for size optimisation */
1788
+
1789
+ #define ev_syscall(nr,narg,arg1,arg2,arg3,arg4,arg5,arg6) \
1790
+ ({ \
1791
+ long res; \
1792
+ register unsigned long r6 __asm__ ("r9" ); \
1793
+ register unsigned long r5 __asm__ ("r8" ); \
1794
+ register unsigned long r4 __asm__ ("r10"); \
1795
+ register unsigned long r3 __asm__ ("rdx"); \
1796
+ register unsigned long r2 __asm__ ("rsi"); \
1797
+ register unsigned long r1 __asm__ ("rdi"); \
1798
+ if (narg >= 6) r6 = (unsigned long)(arg6); \
1799
+ if (narg >= 5) r5 = (unsigned long)(arg5); \
1800
+ if (narg >= 4) r4 = (unsigned long)(arg4); \
1801
+ if (narg >= 3) r3 = (unsigned long)(arg3); \
1802
+ if (narg >= 2) r2 = (unsigned long)(arg2); \
1803
+ if (narg >= 1) r1 = (unsigned long)(arg1); \
1804
+ __asm__ __volatile__ ( \
1805
+ "syscall\n\t" \
1806
+ : "=a" (res) \
1807
+ : "0" (nr), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5) \
1808
+ : "cc", "r11", "cx", "memory"); \
1809
+ errno = -res; \
1810
+ res; \
1811
+ })
1812
+
1813
+ #endif
1814
+
1815
+ #ifdef ev_syscall
1816
+ #define ev_syscall0(nr) ev_syscall (nr, 0, 0, 0, 0, 0, 0, 0)
1817
+ #define ev_syscall1(nr,arg1) ev_syscall (nr, 1, arg1, 0, 0, 0, 0, 0)
1818
+ #define ev_syscall2(nr,arg1,arg2) ev_syscall (nr, 2, arg1, arg2, 0, 0, 0, 0)
1819
+ #define ev_syscall3(nr,arg1,arg2,arg3) ev_syscall (nr, 3, arg1, arg2, arg3, 0, 0, 0)
1820
+ #define ev_syscall4(nr,arg1,arg2,arg3,arg4) ev_syscall (nr, 3, arg1, arg2, arg3, arg4, 0, 0)
1821
+ #define ev_syscall5(nr,arg1,arg2,arg3,arg4,arg5) ev_syscall (nr, 5, arg1, arg2, arg3, arg4, arg5, 0)
1822
+ #define ev_syscall6(nr,arg1,arg2,arg3,arg4,arg5,arg6) ev_syscall (nr, 6, arg1, arg2, arg3, arg4, arg5,arg6)
1823
+ #else
1824
+ #define ev_syscall0(nr) syscall (nr)
1825
+ #define ev_syscall1(nr,arg1) syscall (nr, arg1)
1826
+ #define ev_syscall2(nr,arg1,arg2) syscall (nr, arg1, arg2)
1827
+ #define ev_syscall3(nr,arg1,arg2,arg3) syscall (nr, arg1, arg2, arg3)
1828
+ #define ev_syscall4(nr,arg1,arg2,arg3,arg4) syscall (nr, arg1, arg2, arg3, arg4)
1829
+ #define ev_syscall5(nr,arg1,arg2,arg3,arg4,arg5) syscall (nr, arg1, arg2, arg3, arg4, arg5)
1830
+ #define ev_syscall6(nr,arg1,arg2,arg3,arg4,arg5,arg6) syscall (nr, arg1, arg2, arg3, arg4, arg5,arg6)
1831
+ #endif
1832
+
1833
+ #endif
1834
+
1835
+ /*****************************************************************************/
1836
+
484
1837
  #define NUMPRI (EV_MAXPRI - EV_MINPRI + 1)
485
1838
 
486
1839
  #if EV_MINPRI == EV_MAXPRI
@@ -489,8 +1842,7 @@ struct signalfd_siginfo
489
1842
  # define ABSPRI(w) (((W)w)->priority - EV_MINPRI)
490
1843
  #endif
491
1844
 
492
- #define EMPTY /* required for microsofts broken pseudo-c compiler */
493
- #define EMPTY2(a,b) /* used to suppress some warnings */
1845
+ #define EMPTY /* required for microsofts broken pseudo-c compiler */
494
1846
 
495
1847
  typedef ev_watcher *W;
496
1848
  typedef ev_watcher_list *WL;
@@ -525,11 +1877,65 @@ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work?
525
1877
 
526
1878
  /*****************************************************************************/
527
1879
 
1880
+ #if EV_USE_LINUXAIO
1881
+ # include <linux/aio_abi.h> /* probably only needed for aio_context_t */
1882
+ #endif
1883
+
1884
+ /* define a suitable floor function (only used by periodics atm) */
1885
+
1886
+ #if EV_USE_FLOOR
1887
+ # include <math.h>
1888
+ # define ev_floor(v) floor (v)
1889
+ #else
1890
+
1891
+ #include <float.h>
1892
+
1893
+ /* a floor() replacement function, should be independent of ev_tstamp type */
1894
+ ecb_noinline
1895
+ static ev_tstamp
1896
+ ev_floor (ev_tstamp v)
1897
+ {
1898
+ /* the choice of shift factor is not terribly important */
1899
+ #if FLT_RADIX != 2 /* assume FLT_RADIX == 10 */
1900
+ const ev_tstamp shift = sizeof (unsigned long) >= 8 ? 10000000000000000000. : 1000000000.;
1901
+ #else
1902
+ const ev_tstamp shift = sizeof (unsigned long) >= 8 ? 18446744073709551616. : 4294967296.;
1903
+ #endif
1904
+
1905
+ /* special treatment for negative arguments */
1906
+ if (ecb_expect_false (v < 0.))
1907
+ {
1908
+ ev_tstamp f = -ev_floor (-v);
1909
+
1910
+ return f - (f == v ? 0 : 1);
1911
+ }
1912
+
1913
+ /* argument too large for an unsigned long? then reduce it */
1914
+ if (ecb_expect_false (v >= shift))
1915
+ {
1916
+ ev_tstamp f;
1917
+
1918
+ if (v == v - 1.)
1919
+ return v; /* very large numbers are assumed to be integer */
1920
+
1921
+ f = shift * ev_floor (v * (1. / shift));
1922
+ return f + ev_floor (v - f);
1923
+ }
1924
+
1925
+ /* fits into an unsigned long */
1926
+ return (unsigned long)v;
1927
+ }
1928
+
1929
+ #endif
1930
+
1931
+ /*****************************************************************************/
1932
+
528
1933
  #ifdef __linux
529
1934
  # include <sys/utsname.h>
530
1935
  #endif
531
1936
 
532
- static unsigned int noinline
1937
+ ecb_noinline ecb_cold
1938
+ static unsigned int
533
1939
  ev_linux_version (void)
534
1940
  {
535
1941
  #ifdef __linux
@@ -568,22 +1974,25 @@ ev_linux_version (void)
568
1974
  /*****************************************************************************/
569
1975
 
570
1976
  #if EV_AVOID_STDIO
571
- static void noinline
1977
+ ecb_noinline ecb_cold
1978
+ static void
572
1979
  ev_printerr (const char *msg)
573
1980
  {
574
1981
  write (STDERR_FILENO, msg, strlen (msg));
575
1982
  }
576
1983
  #endif
577
1984
 
578
- static void (*syserr_cb)(const char *msg);
1985
+ static void (*syserr_cb)(const char *msg) EV_NOEXCEPT;
579
1986
 
1987
+ ecb_cold
580
1988
  void
581
- ev_set_syserr_cb (void (*cb)(const char *msg))
1989
+ ev_set_syserr_cb (void (*cb)(const char *msg) EV_NOEXCEPT) EV_NOEXCEPT
582
1990
  {
583
1991
  syserr_cb = cb;
584
1992
  }
585
1993
 
586
- static void noinline
1994
+ ecb_noinline ecb_cold
1995
+ static void
587
1996
  ev_syserr (const char *msg)
588
1997
  {
589
1998
  if (!msg)
@@ -606,14 +2015,13 @@ ev_syserr (const char *msg)
606
2015
  }
607
2016
 
608
2017
  static void *
609
- ev_realloc_emul (void *ptr, long size)
2018
+ ev_realloc_emul (void *ptr, size_t size) EV_NOEXCEPT
610
2019
  {
611
- #if __GLIBC__
612
- return realloc (ptr, size);
613
- #else
614
2020
  /* some systems, notably openbsd and darwin, fail to properly
615
2021
  * implement realloc (x, 0) (as required by both ansi c-89 and
616
2022
  * the single unix specification, so work around them here.
2023
+ * recently, also (at least) fedora and debian started breaking it,
2024
+ * despite documenting it otherwise.
617
2025
  */
618
2026
 
619
2027
  if (size)
@@ -621,19 +2029,19 @@ ev_realloc_emul (void *ptr, long size)
621
2029
 
622
2030
  free (ptr);
623
2031
  return 0;
624
- #endif
625
2032
  }
626
2033
 
627
- static void *(*alloc)(void *ptr, long size) = ev_realloc_emul;
2034
+ static void *(*alloc)(void *ptr, size_t size) EV_NOEXCEPT = ev_realloc_emul;
628
2035
 
2036
+ ecb_cold
629
2037
  void
630
- ev_set_allocator (void *(*cb)(void *ptr, long size))
2038
+ ev_set_allocator (void *(*cb)(void *ptr, size_t size) EV_NOEXCEPT) EV_NOEXCEPT
631
2039
  {
632
2040
  alloc = cb;
633
2041
  }
634
2042
 
635
2043
  inline_speed void *
636
- ev_realloc (void *ptr, long size)
2044
+ ev_realloc (void *ptr, size_t size)
637
2045
  {
638
2046
  ptr = alloc (ptr, size);
639
2047
 
@@ -664,8 +2072,8 @@ typedef struct
664
2072
  WL head;
665
2073
  unsigned char events; /* the events watched for */
666
2074
  unsigned char reify; /* flag set when this ANFD needs reification (EV_ANFD_REIFY, EV__IOFDSET) */
667
- unsigned char emask; /* the epoll backend stores the actual kernel mask in here */
668
- unsigned char unused;
2075
+ unsigned char emask; /* some backends store the actual kernel mask in here */
2076
+ unsigned char eflags; /* flags field for use by backends */
669
2077
  #if EV_USE_EPOLL
670
2078
  unsigned int egen; /* generation counter to counter epoll bugs */
671
2079
  #endif
@@ -725,11 +2133,11 @@ typedef struct
725
2133
  #include "ev_wrap.h"
726
2134
 
727
2135
  static struct ev_loop default_loop_struct;
728
- struct ev_loop *ev_default_loop_ptr;
2136
+ EV_API_DECL struct ev_loop *ev_default_loop_ptr = 0; /* needs to be initialised to make it a definition despite extern */
729
2137
 
730
2138
  #else
731
2139
 
732
- ev_tstamp ev_rt_now;
2140
+ EV_API_DECL ev_tstamp ev_rt_now = EV_TS_CONST (0.); /* needs to be initialised to make it a definition despite extern */
733
2141
  #define VAR(name,decl) static decl;
734
2142
  #include "ev_vars.h"
735
2143
  #undef VAR
@@ -739,8 +2147,8 @@ typedef struct
739
2147
  #endif
740
2148
 
741
2149
  #if EV_FEATURE_API
742
- # define EV_RELEASE_CB if (expect_false (release_cb)) release_cb (EV_A)
743
- # define EV_ACQUIRE_CB if (expect_false (acquire_cb)) acquire_cb (EV_A)
2150
+ # define EV_RELEASE_CB if (ecb_expect_false (release_cb)) release_cb (EV_A)
2151
+ # define EV_ACQUIRE_CB if (ecb_expect_false (acquire_cb)) acquire_cb (EV_A)
744
2152
  # define EV_INVOKE_PENDING invoke_cb (EV_A)
745
2153
  #else
746
2154
  # define EV_RELEASE_CB (void)0
@@ -754,20 +2162,22 @@ typedef struct
754
2162
 
755
2163
  #ifndef EV_HAVE_EV_TIME
756
2164
  ev_tstamp
757
- ev_time (void)
2165
+ ev_time (void) EV_NOEXCEPT
758
2166
  {
759
2167
  #if EV_USE_REALTIME
760
- if (expect_true (have_realtime))
2168
+ if (ecb_expect_true (have_realtime))
761
2169
  {
762
2170
  struct timespec ts;
763
2171
  clock_gettime (CLOCK_REALTIME, &ts);
764
- return ts.tv_sec + ts.tv_nsec * 1e-9;
2172
+ return EV_TS_GET (ts);
765
2173
  }
766
2174
  #endif
767
2175
 
768
- struct timeval tv;
769
- gettimeofday (&tv, 0);
770
- return tv.tv_sec + tv.tv_usec * 1e-6;
2176
+ {
2177
+ struct timeval tv;
2178
+ gettimeofday (&tv, 0);
2179
+ return EV_TV_GET (tv);
2180
+ }
771
2181
  }
772
2182
  #endif
773
2183
 
@@ -775,11 +2185,11 @@ inline_size ev_tstamp
775
2185
  get_clock (void)
776
2186
  {
777
2187
  #if EV_USE_MONOTONIC
778
- if (expect_true (have_monotonic))
2188
+ if (ecb_expect_true (have_monotonic))
779
2189
  {
780
2190
  struct timespec ts;
781
2191
  clock_gettime (CLOCK_MONOTONIC, &ts);
782
- return ts.tv_sec + ts.tv_nsec * 1e-9;
2192
+ return EV_TS_GET (ts);
783
2193
  }
784
2194
  #endif
785
2195
 
@@ -788,24 +2198,26 @@ get_clock (void)
788
2198
 
789
2199
  #if EV_MULTIPLICITY
790
2200
  ev_tstamp
791
- ev_now (EV_P)
2201
+ ev_now (EV_P) EV_NOEXCEPT
792
2202
  {
793
2203
  return ev_rt_now;
794
2204
  }
795
2205
  #endif
796
2206
 
797
2207
  void
798
- ev_sleep (ev_tstamp delay)
2208
+ ev_sleep (ev_tstamp delay) EV_NOEXCEPT
799
2209
  {
800
- if (delay > 0.)
2210
+ if (delay > EV_TS_CONST (0.))
801
2211
  {
802
2212
  #if EV_USE_NANOSLEEP
803
2213
  struct timespec ts;
804
2214
 
805
2215
  EV_TS_SET (ts, delay);
806
2216
  nanosleep (&ts, 0);
807
- #elif defined(_WIN32)
808
- Sleep ((unsigned long)(delay * 1e3));
2217
+ #elif defined _WIN32
2218
+ /* maybe this should round up, as ms is very low resolution */
2219
+ /* compared to select (µs) or nanosleep (ns) */
2220
+ Sleep ((unsigned long)(EV_TS_TO_MSEC (delay)));
809
2221
  #else
810
2222
  struct timeval tv;
811
2223
 
@@ -818,14 +2230,6 @@ ev_sleep (ev_tstamp delay)
818
2230
  }
819
2231
  }
820
2232
 
821
- inline_speed int
822
- ev_timeout_to_ms (ev_tstamp timeout)
823
- {
824
- int ms = timeout * 1000. + .999999;
825
-
826
- return expect_true (ms) ? ms : timeout < 1e-6 ? 0 : 1;
827
- }
828
-
829
2233
  /*****************************************************************************/
830
2234
 
831
2235
  #define MALLOC_ROUND 4096 /* prefer to allocate in chunks of this size, must be 2**n and >> 4 longs */
@@ -841,7 +2245,7 @@ array_nextsize (int elem, int cur, int cnt)
841
2245
  ncur <<= 1;
842
2246
  while (cnt > ncur);
843
2247
 
844
- /* if size is large, round to MALLOC_ROUND - 4 * longs to accomodate malloc overhead */
2248
+ /* if size is large, round to MALLOC_ROUND - 4 * longs to accommodate malloc overhead */
845
2249
  if (elem * ncur > MALLOC_ROUND - sizeof (void *) * 4)
846
2250
  {
847
2251
  ncur *= elem;
@@ -853,23 +2257,26 @@ array_nextsize (int elem, int cur, int cnt)
853
2257
  return ncur;
854
2258
  }
855
2259
 
856
- static noinline void *
2260
+ ecb_noinline ecb_cold
2261
+ static void *
857
2262
  array_realloc (int elem, void *base, int *cur, int cnt)
858
2263
  {
859
2264
  *cur = array_nextsize (elem, *cur, cnt);
860
2265
  return ev_realloc (base, elem * *cur);
861
2266
  }
862
2267
 
863
- #define array_init_zero(base,count) \
864
- memset ((void *)(base), 0, sizeof (*(base)) * (count))
2268
+ #define array_needsize_noinit(base,offset,count)
2269
+
2270
+ #define array_needsize_zerofill(base,offset,count) \
2271
+ memset ((void *)(base + offset), 0, sizeof (*(base)) * (count))
865
2272
 
866
2273
  #define array_needsize(type,base,cur,cnt,init) \
867
- if (expect_false ((cnt) > (cur))) \
2274
+ if (ecb_expect_false ((cnt) > (cur))) \
868
2275
  { \
869
- int ocur_ = (cur); \
2276
+ ecb_unused int ocur_ = (cur); \
870
2277
  (base) = (type *)array_realloc \
871
2278
  (sizeof (type), (base), &(cur), (cnt)); \
872
- init ((base) + (ocur_), (cur) - ocur_); \
2279
+ init ((base), ocur_, ((cur) - ocur_)); \
873
2280
  }
874
2281
 
875
2282
  #if 0
@@ -888,32 +2295,36 @@ array_realloc (int elem, void *base, int *cur, int cnt)
888
2295
  /*****************************************************************************/
889
2296
 
890
2297
  /* dummy callback for pending events */
891
- static void noinline
2298
+ ecb_noinline
2299
+ static void
892
2300
  pendingcb (EV_P_ ev_prepare *w, int revents)
893
2301
  {
894
2302
  }
895
2303
 
896
- void noinline
897
- ev_feed_event (EV_P_ void *w, int revents)
2304
+ ecb_noinline
2305
+ void
2306
+ ev_feed_event (EV_P_ void *w, int revents) EV_NOEXCEPT
898
2307
  {
899
2308
  W w_ = (W)w;
900
2309
  int pri = ABSPRI (w_);
901
2310
 
902
- if (expect_false (w_->pending))
2311
+ if (ecb_expect_false (w_->pending))
903
2312
  pendings [pri][w_->pending - 1].events |= revents;
904
2313
  else
905
2314
  {
906
2315
  w_->pending = ++pendingcnt [pri];
907
- array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, EMPTY2);
2316
+ array_needsize (ANPENDING, pendings [pri], pendingmax [pri], w_->pending, array_needsize_noinit);
908
2317
  pendings [pri][w_->pending - 1].w = w_;
909
2318
  pendings [pri][w_->pending - 1].events = revents;
910
2319
  }
2320
+
2321
+ pendingpri = NUMPRI - 1;
911
2322
  }
912
2323
 
913
2324
  inline_speed void
914
2325
  feed_reverse (EV_P_ W w)
915
2326
  {
916
- array_needsize (W, rfeeds, rfeedmax, rfeedcnt + 1, EMPTY2);
2327
+ array_needsize (W, rfeeds, rfeedmax, rfeedcnt + 1, array_needsize_noinit);
917
2328
  rfeeds [rfeedcnt++] = w;
918
2329
  }
919
2330
 
@@ -958,12 +2369,12 @@ fd_event (EV_P_ int fd, int revents)
958
2369
  {
959
2370
  ANFD *anfd = anfds + fd;
960
2371
 
961
- if (expect_true (!anfd->reify))
2372
+ if (ecb_expect_true (!anfd->reify))
962
2373
  fd_event_nocheck (EV_A_ fd, revents);
963
2374
  }
964
2375
 
965
2376
  void
966
- ev_feed_fd_event (EV_P_ int fd, int revents)
2377
+ ev_feed_fd_event (EV_P_ int fd, int revents) EV_NOEXCEPT
967
2378
  {
968
2379
  if (fd >= 0 && fd < anfdmax)
969
2380
  fd_event_nocheck (EV_A_ fd, revents);
@@ -976,13 +2387,25 @@ fd_reify (EV_P)
976
2387
  {
977
2388
  int i;
978
2389
 
2390
+ /* most backends do not modify the fdchanges list in backend_modfiy.
2391
+ * except io_uring, which has fixed-size buffers which might force us
2392
+ * to handle events in backend_modify, causing fdchanges to be amended,
2393
+ * which could result in an endless loop.
2394
+ * to avoid this, we do not dynamically handle fds that were added
2395
+ * during fd_reify. that means that for those backends, fdchangecnt
2396
+ * might be non-zero during poll, which must cause them to not block.
2397
+ * to not put too much of a burden on other backends, this detail
2398
+ * needs to be handled in the backend.
2399
+ */
2400
+ int changecnt = fdchangecnt;
2401
+
979
2402
  #if EV_SELECT_IS_WINSOCKET || EV_USE_IOCP
980
- for (i = 0; i < fdchangecnt; ++i)
2403
+ for (i = 0; i < changecnt; ++i)
981
2404
  {
982
2405
  int fd = fdchanges [i];
983
2406
  ANFD *anfd = anfds + fd;
984
2407
 
985
- if (anfd->reify & EV__IOFDSET)
2408
+ if (anfd->reify & EV__IOFDSET && anfd->head)
986
2409
  {
987
2410
  SOCKET handle = EV_FD_TO_WIN32_HANDLE (fd);
988
2411
 
@@ -1001,7 +2424,7 @@ fd_reify (EV_P)
1001
2424
  }
1002
2425
  #endif
1003
2426
 
1004
- for (i = 0; i < fdchangecnt; ++i)
2427
+ for (i = 0; i < changecnt; ++i)
1005
2428
  {
1006
2429
  int fd = fdchanges [i];
1007
2430
  ANFD *anfd = anfds + fd;
@@ -1010,9 +2433,9 @@ fd_reify (EV_P)
1010
2433
  unsigned char o_events = anfd->events;
1011
2434
  unsigned char o_reify = anfd->reify;
1012
2435
 
1013
- anfd->reify = 0;
2436
+ anfd->reify = 0;
1014
2437
 
1015
- /*if (expect_true (o_reify & EV_ANFD_REIFY)) probably a deoptimisation */
2438
+ /*if (ecb_expect_true (o_reify & EV_ANFD_REIFY)) probably a deoptimisation */
1016
2439
  {
1017
2440
  anfd->events = 0;
1018
2441
 
@@ -1027,26 +2450,34 @@ fd_reify (EV_P)
1027
2450
  backend_modify (EV_A_ fd, o_events, anfd->events);
1028
2451
  }
1029
2452
 
1030
- fdchangecnt = 0;
2453
+ /* normally, fdchangecnt hasn't changed. if it has, then new fds have been added.
2454
+ * this is a rare case (see beginning comment in this function), so we copy them to the
2455
+ * front and hope the backend handles this case.
2456
+ */
2457
+ if (ecb_expect_false (fdchangecnt != changecnt))
2458
+ memmove (fdchanges, fdchanges + changecnt, (fdchangecnt - changecnt) * sizeof (*fdchanges));
2459
+
2460
+ fdchangecnt -= changecnt;
1031
2461
  }
1032
2462
 
1033
2463
  /* something about the given fd changed */
1034
- inline_size void
2464
+ inline_size
2465
+ void
1035
2466
  fd_change (EV_P_ int fd, int flags)
1036
2467
  {
1037
2468
  unsigned char reify = anfds [fd].reify;
1038
- anfds [fd].reify |= flags;
2469
+ anfds [fd].reify = reify | flags;
1039
2470
 
1040
- if (expect_true (!reify))
2471
+ if (ecb_expect_true (!reify))
1041
2472
  {
1042
2473
  ++fdchangecnt;
1043
- array_needsize (int, fdchanges, fdchangemax, fdchangecnt, EMPTY2);
2474
+ array_needsize (int, fdchanges, fdchangemax, fdchangecnt, array_needsize_noinit);
1044
2475
  fdchanges [fdchangecnt - 1] = fd;
1045
2476
  }
1046
2477
  }
1047
2478
 
1048
2479
  /* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */
1049
- inline_speed void
2480
+ inline_speed ecb_cold void
1050
2481
  fd_kill (EV_P_ int fd)
1051
2482
  {
1052
2483
  ev_io *w;
@@ -1059,7 +2490,7 @@ fd_kill (EV_P_ int fd)
1059
2490
  }
1060
2491
 
1061
2492
  /* check whether the given fd is actually valid, for error recovery */
1062
- inline_size int
2493
+ inline_size ecb_cold int
1063
2494
  fd_valid (int fd)
1064
2495
  {
1065
2496
  #ifdef _WIN32
@@ -1070,7 +2501,8 @@ fd_valid (int fd)
1070
2501
  }
1071
2502
 
1072
2503
  /* called on EBADF to verify fds */
1073
- static void noinline
2504
+ ecb_noinline ecb_cold
2505
+ static void
1074
2506
  fd_ebadf (EV_P)
1075
2507
  {
1076
2508
  int fd;
@@ -1082,7 +2514,8 @@ fd_ebadf (EV_P)
1082
2514
  }
1083
2515
 
1084
2516
  /* called on ENOMEM in select/poll to kill some fds and retry */
1085
- static void noinline
2517
+ ecb_noinline ecb_cold
2518
+ static void
1086
2519
  fd_enomem (EV_P)
1087
2520
  {
1088
2521
  int fd;
@@ -1096,7 +2529,8 @@ fd_enomem (EV_P)
1096
2529
  }
1097
2530
 
1098
2531
  /* usually called after fork if backend needs to re-arm all fds from scratch */
1099
- static void noinline
2532
+ ecb_noinline
2533
+ static void
1100
2534
  fd_rearm_all (EV_P)
1101
2535
  {
1102
2536
  int fd;
@@ -1159,19 +2593,19 @@ downheap (ANHE *heap, int N, int k)
1159
2593
  ANHE *pos = heap + DHEAP * (k - HEAP0) + HEAP0 + 1;
1160
2594
 
1161
2595
  /* find minimum child */
1162
- if (expect_true (pos + DHEAP - 1 < E))
2596
+ if (ecb_expect_true (pos + DHEAP - 1 < E))
1163
2597
  {
1164
2598
  /* fast path */ (minpos = pos + 0), (minat = ANHE_at (*minpos));
1165
- if ( ANHE_at (pos [1]) < minat) (minpos = pos + 1), (minat = ANHE_at (*minpos));
1166
- if ( ANHE_at (pos [2]) < minat) (minpos = pos + 2), (minat = ANHE_at (*minpos));
1167
- if ( ANHE_at (pos [3]) < minat) (minpos = pos + 3), (minat = ANHE_at (*minpos));
2599
+ if ( minat > ANHE_at (pos [1])) (minpos = pos + 1), (minat = ANHE_at (*minpos));
2600
+ if ( minat > ANHE_at (pos [2])) (minpos = pos + 2), (minat = ANHE_at (*minpos));
2601
+ if ( minat > ANHE_at (pos [3])) (minpos = pos + 3), (minat = ANHE_at (*minpos));
1168
2602
  }
1169
2603
  else if (pos < E)
1170
2604
  {
1171
2605
  /* slow path */ (minpos = pos + 0), (minat = ANHE_at (*minpos));
1172
- if (pos + 1 < E && ANHE_at (pos [1]) < minat) (minpos = pos + 1), (minat = ANHE_at (*minpos));
1173
- if (pos + 2 < E && ANHE_at (pos [2]) < minat) (minpos = pos + 2), (minat = ANHE_at (*minpos));
1174
- if (pos + 3 < E && ANHE_at (pos [3]) < minat) (minpos = pos + 3), (minat = ANHE_at (*minpos));
2606
+ if (pos + 1 < E && minat > ANHE_at (pos [1])) (minpos = pos + 1), (minat = ANHE_at (*minpos));
2607
+ if (pos + 2 < E && minat > ANHE_at (pos [2])) (minpos = pos + 2), (minat = ANHE_at (*minpos));
2608
+ if (pos + 3 < E && minat > ANHE_at (pos [3])) (minpos = pos + 3), (minat = ANHE_at (*minpos));
1175
2609
  }
1176
2610
  else
1177
2611
  break;
@@ -1189,7 +2623,7 @@ downheap (ANHE *heap, int N, int k)
1189
2623
  ev_active (ANHE_w (he)) = k;
1190
2624
  }
1191
2625
 
1192
- #else /* 4HEAP */
2626
+ #else /* not 4HEAP */
1193
2627
 
1194
2628
  #define HEAP0 1
1195
2629
  #define HPARENT(k) ((k) >> 1)
@@ -1271,7 +2705,7 @@ reheap (ANHE *heap, int N)
1271
2705
 
1272
2706
  /*****************************************************************************/
1273
2707
 
1274
- /* associate signal watchers to a signal signal */
2708
+ /* associate signal watchers to a signal */
1275
2709
  typedef struct
1276
2710
  {
1277
2711
  EV_ATOMIC_T pending;
@@ -1287,62 +2721,95 @@ static ANSIG signals [EV_NSIG - 1];
1287
2721
 
1288
2722
  #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
1289
2723
 
1290
- static void noinline
2724
+ ecb_noinline ecb_cold
2725
+ static void
1291
2726
  evpipe_init (EV_P)
1292
2727
  {
1293
2728
  if (!ev_is_active (&pipe_w))
1294
2729
  {
2730
+ int fds [2];
2731
+
1295
2732
  # if EV_USE_EVENTFD
1296
- evfd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
1297
- if (evfd < 0 && errno == EINVAL)
1298
- evfd = eventfd (0, 0);
2733
+ fds [0] = -1;
2734
+ fds [1] = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
2735
+ if (fds [1] < 0 && errno == EINVAL)
2736
+ fds [1] = eventfd (0, 0);
1299
2737
 
1300
- if (evfd >= 0)
2738
+ if (fds [1] < 0)
2739
+ # endif
1301
2740
  {
1302
- evpipe [0] = -1;
1303
- fd_intern (evfd); /* doing it twice doesn't hurt */
1304
- ev_io_set (&pipe_w, evfd, EV_READ);
2741
+ while (pipe (fds))
2742
+ ev_syserr ("(libev) error creating signal/async pipe");
2743
+
2744
+ fd_intern (fds [0]);
1305
2745
  }
2746
+
2747
+ evpipe [0] = fds [0];
2748
+
2749
+ if (evpipe [1] < 0)
2750
+ evpipe [1] = fds [1]; /* first call, set write fd */
1306
2751
  else
1307
- # endif
1308
2752
  {
1309
- while (pipe (evpipe))
1310
- ev_syserr ("(libev) error creating signal/async pipe");
2753
+ /* on subsequent calls, do not change evpipe [1] */
2754
+ /* so that evpipe_write can always rely on its value. */
2755
+ /* this branch does not do anything sensible on windows, */
2756
+ /* so must not be executed on windows */
1311
2757
 
1312
- fd_intern (evpipe [0]);
1313
- fd_intern (evpipe [1]);
1314
- ev_io_set (&pipe_w, evpipe [0], EV_READ);
2758
+ dup2 (fds [1], evpipe [1]);
2759
+ close (fds [1]);
1315
2760
  }
1316
2761
 
2762
+ fd_intern (evpipe [1]);
2763
+
2764
+ ev_io_set (&pipe_w, evpipe [0] < 0 ? evpipe [1] : evpipe [0], EV_READ);
1317
2765
  ev_io_start (EV_A_ &pipe_w);
1318
2766
  ev_unref (EV_A); /* watcher should not keep loop alive */
1319
2767
  }
1320
2768
  }
1321
2769
 
1322
- inline_size void
2770
+ inline_speed void
1323
2771
  evpipe_write (EV_P_ EV_ATOMIC_T *flag)
1324
2772
  {
1325
- if (!*flag)
2773
+ ECB_MEMORY_FENCE; /* push out the write before this function was called, acquire flag */
2774
+
2775
+ if (ecb_expect_true (*flag))
2776
+ return;
2777
+
2778
+ *flag = 1;
2779
+ ECB_MEMORY_FENCE_RELEASE; /* make sure flag is visible before the wakeup */
2780
+
2781
+ pipe_write_skipped = 1;
2782
+
2783
+ ECB_MEMORY_FENCE; /* make sure pipe_write_skipped is visible before we check pipe_write_wanted */
2784
+
2785
+ if (pipe_write_wanted)
1326
2786
  {
1327
- int old_errno = errno; /* save errno because write might clobber it */
1328
- char dummy;
2787
+ int old_errno;
2788
+
2789
+ pipe_write_skipped = 0;
2790
+ ECB_MEMORY_FENCE_RELEASE;
1329
2791
 
1330
- *flag = 1;
2792
+ old_errno = errno; /* save errno because write will clobber it */
1331
2793
 
1332
2794
  #if EV_USE_EVENTFD
1333
- if (evfd >= 0)
2795
+ if (evpipe [0] < 0)
1334
2796
  {
1335
2797
  uint64_t counter = 1;
1336
- write (evfd, &counter, sizeof (uint64_t));
2798
+ write (evpipe [1], &counter, sizeof (uint64_t));
1337
2799
  }
1338
2800
  else
1339
2801
  #endif
1340
- /* win32 people keep sending patches that change this write() to send() */
1341
- /* and then run away. but send() is wrong, it wants a socket handle on win32 */
1342
- /* so when you think this write should be a send instead, please find out */
1343
- /* where your send() is from - it's definitely not the microsoft send, and */
1344
- /* tell me. thank you. */
1345
- write (evpipe [1], &dummy, 1);
2802
+ {
2803
+ #ifdef _WIN32
2804
+ WSABUF buf;
2805
+ DWORD sent;
2806
+ buf.buf = (char *)&buf;
2807
+ buf.len = 1;
2808
+ WSASend (EV_FD_TO_WIN32_HANDLE (evpipe [1]), &buf, 1, &sent, 0, 0, 0);
2809
+ #else
2810
+ write (evpipe [1], &(evpipe [1]), 1);
2811
+ #endif
2812
+ }
1346
2813
 
1347
2814
  errno = old_errno;
1348
2815
  }
@@ -1355,27 +2822,44 @@ pipecb (EV_P_ ev_io *iow, int revents)
1355
2822
  {
1356
2823
  int i;
1357
2824
 
1358
- #if EV_USE_EVENTFD
1359
- if (evfd >= 0)
2825
+ if (revents & EV_READ)
1360
2826
  {
1361
- uint64_t counter;
1362
- read (evfd, &counter, sizeof (uint64_t));
1363
- }
1364
- else
2827
+ #if EV_USE_EVENTFD
2828
+ if (evpipe [0] < 0)
2829
+ {
2830
+ uint64_t counter;
2831
+ read (evpipe [1], &counter, sizeof (uint64_t));
2832
+ }
2833
+ else
1365
2834
  #endif
1366
- {
1367
- char dummy;
1368
- /* see discussion in evpipe_write when you think this read should be recv in win32 */
1369
- read (evpipe [0], &dummy, 1);
2835
+ {
2836
+ char dummy[4];
2837
+ #ifdef _WIN32
2838
+ WSABUF buf;
2839
+ DWORD recvd;
2840
+ DWORD flags = 0;
2841
+ buf.buf = dummy;
2842
+ buf.len = sizeof (dummy);
2843
+ WSARecv (EV_FD_TO_WIN32_HANDLE (evpipe [0]), &buf, 1, &recvd, &flags, 0, 0);
2844
+ #else
2845
+ read (evpipe [0], &dummy, sizeof (dummy));
2846
+ #endif
2847
+ }
1370
2848
  }
1371
2849
 
2850
+ pipe_write_skipped = 0;
2851
+
2852
+ ECB_MEMORY_FENCE; /* push out skipped, acquire flags */
2853
+
1372
2854
  #if EV_SIGNAL_ENABLE
1373
2855
  if (sig_pending)
1374
2856
  {
1375
2857
  sig_pending = 0;
1376
2858
 
2859
+ ECB_MEMORY_FENCE;
2860
+
1377
2861
  for (i = EV_NSIG - 1; i--; )
1378
- if (expect_false (signals [i].pending))
2862
+ if (ecb_expect_false (signals [i].pending))
1379
2863
  ev_feed_signal_event (EV_A_ i + 1);
1380
2864
  }
1381
2865
  #endif
@@ -1385,10 +2869,13 @@ pipecb (EV_P_ ev_io *iow, int revents)
1385
2869
  {
1386
2870
  async_pending = 0;
1387
2871
 
2872
+ ECB_MEMORY_FENCE;
2873
+
1388
2874
  for (i = asynccnt; i--; )
1389
2875
  if (asyncs [i]->sent)
1390
2876
  {
1391
2877
  asyncs [i]->sent = 0;
2878
+ ECB_MEMORY_FENCE_RELEASE;
1392
2879
  ev_feed_event (EV_A_ asyncs [i], EV_ASYNC);
1393
2880
  }
1394
2881
  }
@@ -1398,10 +2885,12 @@ pipecb (EV_P_ ev_io *iow, int revents)
1398
2885
  /*****************************************************************************/
1399
2886
 
1400
2887
  void
1401
- ev_feed_signal (int signum)
2888
+ ev_feed_signal (int signum) EV_NOEXCEPT
1402
2889
  {
1403
2890
  #if EV_MULTIPLICITY
1404
- EV_P = signals [signum - 1].loop;
2891
+ EV_P;
2892
+ ECB_MEMORY_FENCE_ACQUIRE;
2893
+ EV_A = signals [signum - 1].loop;
1405
2894
 
1406
2895
  if (!EV_A)
1407
2896
  return;
@@ -1421,12 +2910,13 @@ ev_sighandler (int signum)
1421
2910
  ev_feed_signal (signum);
1422
2911
  }
1423
2912
 
1424
- void noinline
1425
- ev_feed_signal_event (EV_P_ int signum)
2913
+ ecb_noinline
2914
+ void
2915
+ ev_feed_signal_event (EV_P_ int signum) EV_NOEXCEPT
1426
2916
  {
1427
2917
  WL w;
1428
2918
 
1429
- if (expect_false (signum <= 0 || signum > EV_NSIG))
2919
+ if (ecb_expect_false (signum <= 0 || signum >= EV_NSIG))
1430
2920
  return;
1431
2921
 
1432
2922
  --signum;
@@ -1435,11 +2925,12 @@ ev_feed_signal_event (EV_P_ int signum)
1435
2925
  /* it is permissible to try to feed a signal to the wrong loop */
1436
2926
  /* or, likely more useful, feeding a signal nobody is waiting for */
1437
2927
 
1438
- if (expect_false (signals [signum].loop != EV_A))
2928
+ if (ecb_expect_false (signals [signum].loop != EV_A))
1439
2929
  return;
1440
2930
  #endif
1441
2931
 
1442
2932
  signals [signum].pending = 0;
2933
+ ECB_MEMORY_FENCE_RELEASE;
1443
2934
 
1444
2935
  for (w = signals [signum].head; w; w = w->next)
1445
2936
  ev_feed_event (EV_A_ (W)w, EV_SIGNAL);
@@ -1528,6 +3019,57 @@ childcb (EV_P_ ev_signal *sw, int revents)
1528
3019
 
1529
3020
  /*****************************************************************************/
1530
3021
 
3022
+ #if EV_USE_TIMERFD
3023
+
3024
+ static void periodics_reschedule (EV_P);
3025
+
3026
+ static void
3027
+ timerfdcb (EV_P_ ev_io *iow, int revents)
3028
+ {
3029
+ struct itimerspec its = { 0 };
3030
+
3031
+ its.it_value.tv_sec = ev_rt_now + (int)MAX_BLOCKTIME2;
3032
+ timerfd_settime (timerfd, TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &its, 0);
3033
+
3034
+ ev_rt_now = ev_time ();
3035
+ /* periodics_reschedule only needs ev_rt_now */
3036
+ /* but maybe in the future we want the full treatment. */
3037
+ /*
3038
+ now_floor = EV_TS_CONST (0.);
3039
+ time_update (EV_A_ EV_TSTAMP_HUGE);
3040
+ */
3041
+ #if EV_PERIODIC_ENABLE
3042
+ periodics_reschedule (EV_A);
3043
+ #endif
3044
+ }
3045
+
3046
+ ecb_noinline ecb_cold
3047
+ static void
3048
+ evtimerfd_init (EV_P)
3049
+ {
3050
+ if (!ev_is_active (&timerfd_w))
3051
+ {
3052
+ timerfd = timerfd_create (CLOCK_REALTIME, TFD_NONBLOCK | TFD_CLOEXEC);
3053
+
3054
+ if (timerfd >= 0)
3055
+ {
3056
+ fd_intern (timerfd); /* just to be sure */
3057
+
3058
+ ev_io_init (&timerfd_w, timerfdcb, timerfd, EV_READ);
3059
+ ev_set_priority (&timerfd_w, EV_MINPRI);
3060
+ ev_io_start (EV_A_ &timerfd_w);
3061
+ ev_unref (EV_A); /* watcher should not keep loop alive */
3062
+
3063
+ /* (re-) arm timer */
3064
+ timerfdcb (EV_A_ 0, 0);
3065
+ }
3066
+ }
3067
+ }
3068
+
3069
+ #endif
3070
+
3071
+ /*****************************************************************************/
3072
+
1531
3073
  #if EV_USE_IOCP
1532
3074
  # include "ev_iocp.c"
1533
3075
  #endif
@@ -1540,6 +3082,12 @@ childcb (EV_P_ ev_signal *sw, int revents)
1540
3082
  #if EV_USE_EPOLL
1541
3083
  # include "ev_epoll.c"
1542
3084
  #endif
3085
+ #if EV_USE_LINUXAIO
3086
+ # include "ev_linuxaio.c"
3087
+ #endif
3088
+ #if EV_USE_IOURING
3089
+ # include "ev_iouring.c"
3090
+ #endif
1543
3091
  #if EV_USE_POLL
1544
3092
  # include "ev_poll.c"
1545
3093
  #endif
@@ -1547,20 +3095,20 @@ childcb (EV_P_ ev_signal *sw, int revents)
1547
3095
  # include "ev_select.c"
1548
3096
  #endif
1549
3097
 
1550
- int
1551
- ev_version_major (void)
3098
+ ecb_cold int
3099
+ ev_version_major (void) EV_NOEXCEPT
1552
3100
  {
1553
3101
  return EV_VERSION_MAJOR;
1554
3102
  }
1555
3103
 
1556
- int
1557
- ev_version_minor (void)
3104
+ ecb_cold int
3105
+ ev_version_minor (void) EV_NOEXCEPT
1558
3106
  {
1559
3107
  return EV_VERSION_MINOR;
1560
3108
  }
1561
3109
 
1562
3110
  /* return true if we are running with elevated privileges and should ignore env variables */
1563
- int inline_size
3111
+ inline_size ecb_cold int
1564
3112
  enable_secure (void)
1565
3113
  {
1566
3114
  #ifdef _WIN32
@@ -1571,103 +3119,123 @@ enable_secure (void)
1571
3119
  #endif
1572
3120
  }
1573
3121
 
3122
+ ecb_cold
1574
3123
  unsigned int
1575
- ev_supported_backends (void)
3124
+ ev_supported_backends (void) EV_NOEXCEPT
1576
3125
  {
1577
3126
  unsigned int flags = 0;
1578
3127
 
1579
- if (EV_USE_PORT ) flags |= EVBACKEND_PORT;
1580
- if (EV_USE_KQUEUE) flags |= EVBACKEND_KQUEUE;
1581
- if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL;
1582
- if (EV_USE_POLL ) flags |= EVBACKEND_POLL;
1583
- if (EV_USE_SELECT) flags |= EVBACKEND_SELECT;
3128
+ if (EV_USE_PORT ) flags |= EVBACKEND_PORT;
3129
+ if (EV_USE_KQUEUE ) flags |= EVBACKEND_KQUEUE;
3130
+ if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL;
3131
+ if (EV_USE_LINUXAIO && ev_linux_version () >= 0x041300) flags |= EVBACKEND_LINUXAIO; /* 4.19+ */
3132
+ if (EV_USE_IOURING && ev_linux_version () >= 0x050601 ) flags |= EVBACKEND_IOURING; /* 5.6.1+ */
3133
+ if (EV_USE_POLL ) flags |= EVBACKEND_POLL;
3134
+ if (EV_USE_SELECT ) flags |= EVBACKEND_SELECT;
1584
3135
 
1585
3136
  return flags;
1586
3137
  }
1587
3138
 
3139
+ ecb_cold
1588
3140
  unsigned int
1589
- ev_recommended_backends (void)
3141
+ ev_recommended_backends (void) EV_NOEXCEPT
1590
3142
  {
1591
3143
  unsigned int flags = ev_supported_backends ();
1592
3144
 
1593
- #ifndef __NetBSD__
1594
- /* kqueue is borked on everything but netbsd apparently */
1595
- /* it usually doesn't work correctly on anything but sockets and pipes */
1596
- flags &= ~EVBACKEND_KQUEUE;
1597
- #endif
1598
- #ifdef __APPLE__
3145
+ /* apple has a poor track record but post 10.12.2 it seems to work sufficiently well */
3146
+ #if defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_14)
1599
3147
  /* only select works correctly on that "unix-certified" platform */
1600
3148
  flags &= ~EVBACKEND_KQUEUE; /* horribly broken, even for sockets */
1601
3149
  flags &= ~EVBACKEND_POLL; /* poll is based on kqueue from 10.5 onwards */
1602
3150
  #endif
3151
+
3152
+ #if !defined(__NetBSD__) && !defined(__APPLE__)
3153
+ /* kqueue is borked on everything but netbsd and osx >= 10.12.2 apparently */
3154
+ /* it usually doesn't work correctly on anything but sockets and pipes */
3155
+ flags &= ~EVBACKEND_KQUEUE;
3156
+ #endif
3157
+
1603
3158
  #ifdef __FreeBSD__
1604
3159
  flags &= ~EVBACKEND_POLL; /* poll return value is unusable (http://forums.freebsd.org/archive/index.php/t-10270.html) */
1605
3160
  #endif
1606
3161
 
3162
+ #ifdef __linux__
3163
+ /* NOTE: linuxaio is very experimental, never recommend */
3164
+ flags &= ~EVBACKEND_LINUXAIO;
3165
+
3166
+ /* NOTE: io_uring is super experimental, never recommend */
3167
+ flags &= ~EVBACKEND_IOURING;
3168
+ #endif
3169
+
1607
3170
  return flags;
1608
3171
  }
1609
3172
 
3173
+ ecb_cold
1610
3174
  unsigned int
1611
- ev_embeddable_backends (void)
3175
+ ev_embeddable_backends (void) EV_NOEXCEPT
1612
3176
  {
1613
- int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT;
3177
+ int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT | EVBACKEND_IOURING;
1614
3178
 
1615
3179
  /* epoll embeddability broken on all linux versions up to at least 2.6.23 */
1616
3180
  if (ev_linux_version () < 0x020620) /* disable it on linux < 2.6.32 */
1617
3181
  flags &= ~EVBACKEND_EPOLL;
1618
3182
 
3183
+ /* EVBACKEND_LINUXAIO is theoretically embeddable, but suffers from a performance overhead */
3184
+
1619
3185
  return flags;
1620
3186
  }
1621
3187
 
1622
3188
  unsigned int
1623
- ev_backend (EV_P)
3189
+ ev_backend (EV_P) EV_NOEXCEPT
1624
3190
  {
1625
3191
  return backend;
1626
3192
  }
1627
3193
 
1628
3194
  #if EV_FEATURE_API
1629
3195
  unsigned int
1630
- ev_iteration (EV_P)
3196
+ ev_iteration (EV_P) EV_NOEXCEPT
1631
3197
  {
1632
3198
  return loop_count;
1633
3199
  }
1634
3200
 
1635
3201
  unsigned int
1636
- ev_depth (EV_P)
3202
+ ev_depth (EV_P) EV_NOEXCEPT
1637
3203
  {
1638
3204
  return loop_depth;
1639
3205
  }
1640
3206
 
1641
3207
  void
1642
- ev_set_io_collect_interval (EV_P_ ev_tstamp interval)
3208
+ ev_set_io_collect_interval (EV_P_ ev_tstamp interval) EV_NOEXCEPT
1643
3209
  {
1644
3210
  io_blocktime = interval;
1645
3211
  }
1646
3212
 
1647
3213
  void
1648
- ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval)
3214
+ ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) EV_NOEXCEPT
1649
3215
  {
1650
3216
  timeout_blocktime = interval;
1651
3217
  }
1652
3218
 
1653
3219
  void
1654
- ev_set_userdata (EV_P_ void *data)
3220
+ ev_set_userdata (EV_P_ void *data) EV_NOEXCEPT
1655
3221
  {
1656
3222
  userdata = data;
1657
3223
  }
1658
3224
 
1659
3225
  void *
1660
- ev_userdata (EV_P)
3226
+ ev_userdata (EV_P) EV_NOEXCEPT
1661
3227
  {
1662
3228
  return userdata;
1663
3229
  }
1664
3230
 
1665
- void ev_set_invoke_pending_cb (EV_P_ void (*invoke_pending_cb)(EV_P))
3231
+ void
3232
+ ev_set_invoke_pending_cb (EV_P_ ev_loop_callback invoke_pending_cb) EV_NOEXCEPT
1666
3233
  {
1667
3234
  invoke_cb = invoke_pending_cb;
1668
3235
  }
1669
3236
 
1670
- void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P))
3237
+ void
3238
+ ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_NOEXCEPT, void (*acquire)(EV_P) EV_NOEXCEPT) EV_NOEXCEPT
1671
3239
  {
1672
3240
  release_cb = release;
1673
3241
  acquire_cb = acquire;
@@ -1675,8 +3243,9 @@ void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P), void (*acquire)(EV_P))
1675
3243
  #endif
1676
3244
 
1677
3245
  /* initialise a loop structure, must be zero-initialised */
1678
- static void noinline
1679
- loop_init (EV_P_ unsigned int flags)
3246
+ ecb_noinline ecb_cold
3247
+ static void
3248
+ loop_init (EV_P_ unsigned int flags) EV_NOEXCEPT
1680
3249
  {
1681
3250
  if (!backend)
1682
3251
  {
@@ -1713,49 +3282,62 @@ loop_init (EV_P_ unsigned int flags)
1713
3282
  && getenv ("LIBEV_FLAGS"))
1714
3283
  flags = atoi (getenv ("LIBEV_FLAGS"));
1715
3284
 
1716
- ev_rt_now = ev_time ();
1717
- mn_now = get_clock ();
1718
- now_floor = mn_now;
1719
- rtmn_diff = ev_rt_now - mn_now;
3285
+ ev_rt_now = ev_time ();
3286
+ mn_now = get_clock ();
3287
+ now_floor = mn_now;
3288
+ rtmn_diff = ev_rt_now - mn_now;
1720
3289
  #if EV_FEATURE_API
1721
- invoke_cb = ev_invoke_pending;
3290
+ invoke_cb = ev_invoke_pending;
1722
3291
  #endif
1723
3292
 
1724
- io_blocktime = 0.;
1725
- timeout_blocktime = 0.;
1726
- backend = 0;
1727
- backend_fd = -1;
1728
- sig_pending = 0;
3293
+ io_blocktime = 0.;
3294
+ timeout_blocktime = 0.;
3295
+ backend = 0;
3296
+ backend_fd = -1;
3297
+ sig_pending = 0;
1729
3298
  #if EV_ASYNC_ENABLE
1730
- async_pending = 0;
3299
+ async_pending = 0;
1731
3300
  #endif
3301
+ pipe_write_skipped = 0;
3302
+ pipe_write_wanted = 0;
3303
+ evpipe [0] = -1;
3304
+ evpipe [1] = -1;
1732
3305
  #if EV_USE_INOTIFY
1733
- fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
3306
+ fs_fd = flags & EVFLAG_NOINOTIFY ? -1 : -2;
1734
3307
  #endif
1735
3308
  #if EV_USE_SIGNALFD
1736
- sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
3309
+ sigfd = flags & EVFLAG_SIGNALFD ? -2 : -1;
3310
+ #endif
3311
+ #if EV_USE_TIMERFD
3312
+ timerfd = flags & EVFLAG_NOTIMERFD ? -1 : -2;
1737
3313
  #endif
1738
3314
 
1739
3315
  if (!(flags & EVBACKEND_MASK))
1740
3316
  flags |= ev_recommended_backends ();
1741
3317
 
1742
3318
  #if EV_USE_IOCP
1743
- if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
3319
+ if (!backend && (flags & EVBACKEND_IOCP )) backend = iocp_init (EV_A_ flags);
1744
3320
  #endif
1745
3321
  #if EV_USE_PORT
1746
- if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
3322
+ if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
1747
3323
  #endif
1748
3324
  #if EV_USE_KQUEUE
1749
- if (!backend && (flags & EVBACKEND_KQUEUE)) backend = kqueue_init (EV_A_ flags);
3325
+ if (!backend && (flags & EVBACKEND_KQUEUE )) backend = kqueue_init (EV_A_ flags);
3326
+ #endif
3327
+ #if EV_USE_IOURING
3328
+ if (!backend && (flags & EVBACKEND_IOURING )) backend = iouring_init (EV_A_ flags);
3329
+ #endif
3330
+ #if EV_USE_LINUXAIO
3331
+ if (!backend && (flags & EVBACKEND_LINUXAIO)) backend = linuxaio_init (EV_A_ flags);
1750
3332
  #endif
1751
3333
  #if EV_USE_EPOLL
1752
- if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);
3334
+ if (!backend && (flags & EVBACKEND_EPOLL )) backend = epoll_init (EV_A_ flags);
1753
3335
  #endif
1754
3336
  #if EV_USE_POLL
1755
- if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
3337
+ if (!backend && (flags & EVBACKEND_POLL )) backend = poll_init (EV_A_ flags);
1756
3338
  #endif
1757
3339
  #if EV_USE_SELECT
1758
- if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
3340
+ if (!backend && (flags & EVBACKEND_SELECT )) backend = select_init (EV_A_ flags);
1759
3341
  #endif
1760
3342
 
1761
3343
  ev_prepare_init (&pending_w, pendingcb);
@@ -1768,6 +3350,7 @@ loop_init (EV_P_ unsigned int flags)
1768
3350
  }
1769
3351
 
1770
3352
  /* free up a loop structure */
3353
+ ecb_cold
1771
3354
  void
1772
3355
  ev_loop_destroy (EV_P)
1773
3356
  {
@@ -1781,7 +3364,7 @@ ev_loop_destroy (EV_P)
1781
3364
 
1782
3365
  #if EV_CLEANUP_ENABLE
1783
3366
  /* queue cleanup watchers (and execute them) */
1784
- if (expect_false (cleanupcnt))
3367
+ if (ecb_expect_false (cleanupcnt))
1785
3368
  {
1786
3369
  queue_events (EV_A_ (W *)cleanups, cleanupcnt, EV_CLEANUP);
1787
3370
  EV_INVOKE_PENDING;
@@ -1789,7 +3372,7 @@ ev_loop_destroy (EV_P)
1789
3372
  #endif
1790
3373
 
1791
3374
  #if EV_CHILD_ENABLE
1792
- if (ev_is_active (&childev))
3375
+ if (ev_is_default_loop (EV_A) && ev_is_active (&childev))
1793
3376
  {
1794
3377
  ev_ref (EV_A); /* child watcher */
1795
3378
  ev_signal_stop (EV_A_ &childev);
@@ -1801,16 +3384,8 @@ ev_loop_destroy (EV_P)
1801
3384
  /*ev_ref (EV_A);*/
1802
3385
  /*ev_io_stop (EV_A_ &pipe_w);*/
1803
3386
 
1804
- #if EV_USE_EVENTFD
1805
- if (evfd >= 0)
1806
- close (evfd);
1807
- #endif
1808
-
1809
- if (evpipe [0] >= 0)
1810
- {
1811
- EV_WIN32_CLOSE_FD (evpipe [0]);
1812
- EV_WIN32_CLOSE_FD (evpipe [1]);
1813
- }
3387
+ if (evpipe [0] >= 0) EV_WIN32_CLOSE_FD (evpipe [0]);
3388
+ if (evpipe [1] >= 0) EV_WIN32_CLOSE_FD (evpipe [1]);
1814
3389
  }
1815
3390
 
1816
3391
  #if EV_USE_SIGNALFD
@@ -1818,6 +3393,11 @@ ev_loop_destroy (EV_P)
1818
3393
  close (sigfd);
1819
3394
  #endif
1820
3395
 
3396
+ #if EV_USE_TIMERFD
3397
+ if (ev_is_active (&timerfd_w))
3398
+ close (timerfd);
3399
+ #endif
3400
+
1821
3401
  #if EV_USE_INOTIFY
1822
3402
  if (fs_fd >= 0)
1823
3403
  close (fs_fd);
@@ -1827,22 +3407,28 @@ ev_loop_destroy (EV_P)
1827
3407
  close (backend_fd);
1828
3408
 
1829
3409
  #if EV_USE_IOCP
1830
- if (backend == EVBACKEND_IOCP ) iocp_destroy (EV_A);
3410
+ if (backend == EVBACKEND_IOCP ) iocp_destroy (EV_A);
1831
3411
  #endif
1832
3412
  #if EV_USE_PORT
1833
- if (backend == EVBACKEND_PORT ) port_destroy (EV_A);
3413
+ if (backend == EVBACKEND_PORT ) port_destroy (EV_A);
1834
3414
  #endif
1835
3415
  #if EV_USE_KQUEUE
1836
- if (backend == EVBACKEND_KQUEUE) kqueue_destroy (EV_A);
3416
+ if (backend == EVBACKEND_KQUEUE ) kqueue_destroy (EV_A);
3417
+ #endif
3418
+ #if EV_USE_IOURING
3419
+ if (backend == EVBACKEND_IOURING ) iouring_destroy (EV_A);
3420
+ #endif
3421
+ #if EV_USE_LINUXAIO
3422
+ if (backend == EVBACKEND_LINUXAIO) linuxaio_destroy (EV_A);
1837
3423
  #endif
1838
3424
  #if EV_USE_EPOLL
1839
- if (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A);
3425
+ if (backend == EVBACKEND_EPOLL ) epoll_destroy (EV_A);
1840
3426
  #endif
1841
3427
  #if EV_USE_POLL
1842
- if (backend == EVBACKEND_POLL ) poll_destroy (EV_A);
3428
+ if (backend == EVBACKEND_POLL ) poll_destroy (EV_A);
1843
3429
  #endif
1844
3430
  #if EV_USE_SELECT
1845
- if (backend == EVBACKEND_SELECT) select_destroy (EV_A);
3431
+ if (backend == EVBACKEND_SELECT ) select_destroy (EV_A);
1846
3432
  #endif
1847
3433
 
1848
3434
  for (i = NUMPRI; i--; )
@@ -1894,46 +3480,61 @@ inline_size void
1894
3480
  loop_fork (EV_P)
1895
3481
  {
1896
3482
  #if EV_USE_PORT
1897
- if (backend == EVBACKEND_PORT ) port_fork (EV_A);
3483
+ if (backend == EVBACKEND_PORT ) port_fork (EV_A);
1898
3484
  #endif
1899
3485
  #if EV_USE_KQUEUE
1900
- if (backend == EVBACKEND_KQUEUE) kqueue_fork (EV_A);
3486
+ if (backend == EVBACKEND_KQUEUE ) kqueue_fork (EV_A);
3487
+ #endif
3488
+ #if EV_USE_IOURING
3489
+ if (backend == EVBACKEND_IOURING ) iouring_fork (EV_A);
3490
+ #endif
3491
+ #if EV_USE_LINUXAIO
3492
+ if (backend == EVBACKEND_LINUXAIO) linuxaio_fork (EV_A);
1901
3493
  #endif
1902
3494
  #if EV_USE_EPOLL
1903
- if (backend == EVBACKEND_EPOLL ) epoll_fork (EV_A);
3495
+ if (backend == EVBACKEND_EPOLL ) epoll_fork (EV_A);
1904
3496
  #endif
1905
3497
  #if EV_USE_INOTIFY
1906
3498
  infy_fork (EV_A);
1907
3499
  #endif
1908
3500
 
1909
- if (ev_is_active (&pipe_w))
3501
+ if (postfork != 2)
1910
3502
  {
1911
- /* this "locks" the handlers against writing to the pipe */
1912
- /* while we modify the fd vars */
1913
- sig_pending = 1;
1914
- #if EV_ASYNC_ENABLE
1915
- async_pending = 1;
1916
- #endif
3503
+ #if EV_USE_SIGNALFD
3504
+ /* surprisingly, nothing needs to be done for signalfd, accoridng to docs, it does the right thing on fork */
3505
+ #endif
1917
3506
 
1918
- ev_ref (EV_A);
1919
- ev_io_stop (EV_A_ &pipe_w);
3507
+ #if EV_USE_TIMERFD
3508
+ if (ev_is_active (&timerfd_w))
3509
+ {
3510
+ ev_ref (EV_A);
3511
+ ev_io_stop (EV_A_ &timerfd_w);
1920
3512
 
1921
- #if EV_USE_EVENTFD
1922
- if (evfd >= 0)
1923
- close (evfd);
1924
- #endif
3513
+ close (timerfd);
3514
+ timerfd = -2;
1925
3515
 
1926
- if (evpipe [0] >= 0)
1927
- {
1928
- EV_WIN32_CLOSE_FD (evpipe [0]);
1929
- EV_WIN32_CLOSE_FD (evpipe [1]);
1930
- }
3516
+ evtimerfd_init (EV_A);
3517
+ /* reschedule periodics, in case we missed something */
3518
+ ev_feed_event (EV_A_ &timerfd_w, EV_CUSTOM);
3519
+ }
3520
+ #endif
1931
3521
 
1932
- #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
1933
- evpipe_init (EV_A);
1934
- /* now iterate over everything, in case we missed something */
1935
- pipecb (EV_A_ &pipe_w, EV_READ);
1936
- #endif
3522
+ #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
3523
+ if (ev_is_active (&pipe_w))
3524
+ {
3525
+ /* pipe_write_wanted must be false now, so modifying fd vars should be safe */
3526
+
3527
+ ev_ref (EV_A);
3528
+ ev_io_stop (EV_A_ &pipe_w);
3529
+
3530
+ if (evpipe [0] >= 0)
3531
+ EV_WIN32_CLOSE_FD (evpipe [0]);
3532
+
3533
+ evpipe_init (EV_A);
3534
+ /* iterate over everything, in case we missed something before */
3535
+ ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
3536
+ }
3537
+ #endif
1937
3538
  }
1938
3539
 
1939
3540
  postfork = 0;
@@ -1941,8 +3542,9 @@ loop_fork (EV_P)
1941
3542
 
1942
3543
  #if EV_MULTIPLICITY
1943
3544
 
3545
+ ecb_cold
1944
3546
  struct ev_loop *
1945
- ev_loop_new (unsigned int flags)
3547
+ ev_loop_new (unsigned int flags) EV_NOEXCEPT
1946
3548
  {
1947
3549
  EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop));
1948
3550
 
@@ -1959,7 +3561,8 @@ ev_loop_new (unsigned int flags)
1959
3561
  #endif /* multiplicity */
1960
3562
 
1961
3563
  #if EV_VERIFY
1962
- static void noinline
3564
+ ecb_noinline ecb_cold
3565
+ static void
1963
3566
  verify_watcher (EV_P_ W w)
1964
3567
  {
1965
3568
  assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI));
@@ -1968,7 +3571,8 @@ verify_watcher (EV_P_ W w)
1968
3571
  assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w));
1969
3572
  }
1970
3573
 
1971
- static void noinline
3574
+ ecb_noinline ecb_cold
3575
+ static void
1972
3576
  verify_heap (EV_P_ ANHE *heap, int N)
1973
3577
  {
1974
3578
  int i;
@@ -1983,7 +3587,8 @@ verify_heap (EV_P_ ANHE *heap, int N)
1983
3587
  }
1984
3588
  }
1985
3589
 
1986
- static void noinline
3590
+ ecb_noinline ecb_cold
3591
+ static void
1987
3592
  array_verify (EV_P_ W *ws, int cnt)
1988
3593
  {
1989
3594
  while (cnt--)
@@ -1995,12 +3600,12 @@ array_verify (EV_P_ W *ws, int cnt)
1995
3600
  #endif
1996
3601
 
1997
3602
  #if EV_FEATURE_API
1998
- void
1999
- ev_verify (EV_P)
3603
+ void ecb_cold
3604
+ ev_verify (EV_P) EV_NOEXCEPT
2000
3605
  {
2001
3606
  #if EV_VERIFY
2002
3607
  int i;
2003
- WL w;
3608
+ WL w, w2;
2004
3609
 
2005
3610
  assert (activecnt >= -1);
2006
3611
 
@@ -2010,12 +3615,23 @@ ev_verify (EV_P)
2010
3615
 
2011
3616
  assert (anfdmax >= 0);
2012
3617
  for (i = 0; i < anfdmax; ++i)
2013
- for (w = anfds [i].head; w; w = w->next)
2014
- {
2015
- verify_watcher (EV_A_ (W)w);
2016
- assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1));
2017
- assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i));
2018
- }
3618
+ {
3619
+ int j = 0;
3620
+
3621
+ for (w = w2 = anfds [i].head; w; w = w->next)
3622
+ {
3623
+ verify_watcher (EV_A_ (W)w);
3624
+
3625
+ if (j++ & 1)
3626
+ {
3627
+ assert (("libev: io watcher list contains a loop", w != w2));
3628
+ w2 = w2->next;
3629
+ }
3630
+
3631
+ assert (("libev: inactive fd watcher on anfd list", ev_active (w) == 1));
3632
+ assert (("libev: fd mismatch between watcher and anfd", ((ev_io *)w)->fd == i));
3633
+ }
3634
+ }
2019
3635
 
2020
3636
  assert (timermax >= timercnt);
2021
3637
  verify_heap (EV_A_ timers, timercnt);
@@ -2071,11 +3687,12 @@ ev_verify (EV_P)
2071
3687
  #endif
2072
3688
 
2073
3689
  #if EV_MULTIPLICITY
3690
+ ecb_cold
2074
3691
  struct ev_loop *
2075
3692
  #else
2076
3693
  int
2077
3694
  #endif
2078
- ev_default_loop (unsigned int flags)
3695
+ ev_default_loop (unsigned int flags) EV_NOEXCEPT
2079
3696
  {
2080
3697
  if (!ev_default_loop_ptr)
2081
3698
  {
@@ -2104,9 +3721,9 @@ ev_default_loop (unsigned int flags)
2104
3721
  }
2105
3722
 
2106
3723
  void
2107
- ev_loop_fork (EV_P)
3724
+ ev_loop_fork (EV_P) EV_NOEXCEPT
2108
3725
  {
2109
- postfork = 1; /* must be in line with ev_default_fork */
3726
+ postfork = 1;
2110
3727
  }
2111
3728
 
2112
3729
  /*****************************************************************************/
@@ -2118,7 +3735,7 @@ ev_invoke (EV_P_ void *w, int revents)
2118
3735
  }
2119
3736
 
2120
3737
  unsigned int
2121
- ev_pending_count (EV_P)
3738
+ ev_pending_count (EV_P) EV_NOEXCEPT
2122
3739
  {
2123
3740
  int pri;
2124
3741
  unsigned int count = 0;
@@ -2129,20 +3746,27 @@ ev_pending_count (EV_P)
2129
3746
  return count;
2130
3747
  }
2131
3748
 
2132
- void noinline
3749
+ ecb_noinline
3750
+ void
2133
3751
  ev_invoke_pending (EV_P)
2134
3752
  {
2135
- int pri;
3753
+ pendingpri = NUMPRI;
2136
3754
 
2137
- for (pri = NUMPRI; pri--; )
2138
- while (pendingcnt [pri])
2139
- {
2140
- ANPENDING *p = pendings [pri] + --pendingcnt [pri];
3755
+ do
3756
+ {
3757
+ --pendingpri;
2141
3758
 
2142
- p->w->pending = 0;
2143
- EV_CB_INVOKE (p->w, p->events);
2144
- EV_FREQUENT_CHECK;
2145
- }
3759
+ /* pendingpri possibly gets modified in the inner loop */
3760
+ while (pendingcnt [pendingpri])
3761
+ {
3762
+ ANPENDING *p = pendings [pendingpri] + --pendingcnt [pendingpri];
3763
+
3764
+ p->w->pending = 0;
3765
+ EV_CB_INVOKE (p->w, p->events);
3766
+ EV_FREQUENT_CHECK;
3767
+ }
3768
+ }
3769
+ while (pendingpri);
2146
3770
  }
2147
3771
 
2148
3772
  #if EV_IDLE_ENABLE
@@ -2151,7 +3775,7 @@ ev_invoke_pending (EV_P)
2151
3775
  inline_size void
2152
3776
  idle_reify (EV_P)
2153
3777
  {
2154
- if (expect_false (idleall))
3778
+ if (ecb_expect_false (idleall))
2155
3779
  {
2156
3780
  int pri;
2157
3781
 
@@ -2191,7 +3815,7 @@ timers_reify (EV_P)
2191
3815
  if (ev_at (w) < mn_now)
2192
3816
  ev_at (w) = mn_now;
2193
3817
 
2194
- assert (("libev: negative ev_timer repeat value found while processing timers", w->repeat > 0.));
3818
+ assert (("libev: negative ev_timer repeat value found while processing timers", w->repeat > EV_TS_CONST (0.)));
2195
3819
 
2196
3820
  ANHE_at_cache (timers [HEAP0]);
2197
3821
  downheap (timers, timercnt, HEAP0);
@@ -2210,12 +3834,29 @@ timers_reify (EV_P)
2210
3834
 
2211
3835
  #if EV_PERIODIC_ENABLE
2212
3836
 
2213
- inline_speed void
3837
+ ecb_noinline
3838
+ static void
2214
3839
  periodic_recalc (EV_P_ ev_periodic *w)
2215
3840
  {
2216
- /* TODO: use slow but potentially more correct incremental algo, */
2217
- /* also do not rely on ceil */
2218
- ev_at (w) = w->offset + ceil ((ev_rt_now - w->offset) / w->interval) * w->interval;
3841
+ ev_tstamp interval = w->interval > MIN_INTERVAL ? w->interval : MIN_INTERVAL;
3842
+ ev_tstamp at = w->offset + interval * ev_floor ((ev_rt_now - w->offset) / interval);
3843
+
3844
+ /* the above almost always errs on the low side */
3845
+ while (at <= ev_rt_now)
3846
+ {
3847
+ ev_tstamp nat = at + w->interval;
3848
+
3849
+ /* when resolution fails us, we use ev_rt_now */
3850
+ if (ecb_expect_false (nat == at))
3851
+ {
3852
+ at = ev_rt_now;
3853
+ break;
3854
+ }
3855
+
3856
+ at = nat;
3857
+ }
3858
+
3859
+ ev_at (w) = at;
2219
3860
  }
2220
3861
 
2221
3862
  /* make periodics pending */
@@ -2226,8 +3867,6 @@ periodics_reify (EV_P)
2226
3867
 
2227
3868
  while (periodiccnt && ANHE_at (periodics [HEAP0]) < ev_rt_now)
2228
3869
  {
2229
- int feed_count = 0;
2230
-
2231
3870
  do
2232
3871
  {
2233
3872
  ev_periodic *w = (ev_periodic *)ANHE_w (periodics [HEAP0]);
@@ -2247,20 +3886,6 @@ periodics_reify (EV_P)
2247
3886
  else if (w->interval)
2248
3887
  {
2249
3888
  periodic_recalc (EV_A_ w);
2250
-
2251
- /* if next trigger time is not sufficiently in the future, put it there */
2252
- /* this might happen because of floating point inexactness */
2253
- if (ev_at (w) - ev_rt_now < TIME_EPSILON)
2254
- {
2255
- ev_at (w) += w->interval;
2256
-
2257
- /* if interval is unreasonably low we might still have a time in the past */
2258
- /* so correct this. this will make the periodic very inexact, but the user */
2259
- /* has effectively asked to get triggered more often than possible */
2260
- if (ev_at (w) < ev_rt_now)
2261
- ev_at (w) = ev_rt_now;
2262
- }
2263
-
2264
3889
  ANHE_at_cache (periodics [HEAP0]);
2265
3890
  downheap (periodics, periodiccnt, HEAP0);
2266
3891
  }
@@ -2278,7 +3903,8 @@ periodics_reify (EV_P)
2278
3903
 
2279
3904
  /* simply recalculate all periodics */
2280
3905
  /* TODO: maybe ensure that at least one event happens when jumping forward? */
2281
- static void noinline
3906
+ ecb_noinline ecb_cold
3907
+ static void
2282
3908
  periodics_reschedule (EV_P)
2283
3909
  {
2284
3910
  int i;
@@ -2301,7 +3927,8 @@ periodics_reschedule (EV_P)
2301
3927
  #endif
2302
3928
 
2303
3929
  /* adjust all timers by a given offset */
2304
- static void noinline
3930
+ ecb_noinline ecb_cold
3931
+ static void
2305
3932
  timers_reschedule (EV_P_ ev_tstamp adjust)
2306
3933
  {
2307
3934
  int i;
@@ -2320,7 +3947,7 @@ inline_speed void
2320
3947
  time_update (EV_P_ ev_tstamp max_block)
2321
3948
  {
2322
3949
  #if EV_USE_MONOTONIC
2323
- if (expect_true (have_monotonic))
3950
+ if (ecb_expect_true (have_monotonic))
2324
3951
  {
2325
3952
  int i;
2326
3953
  ev_tstamp odiff = rtmn_diff;
@@ -2329,7 +3956,7 @@ time_update (EV_P_ ev_tstamp max_block)
2329
3956
 
2330
3957
  /* only fetch the realtime clock every 0.5*MIN_TIMEJUMP seconds */
2331
3958
  /* interpolate in the meantime */
2332
- if (expect_true (mn_now - now_floor < MIN_TIMEJUMP * .5))
3959
+ if (ecb_expect_true (mn_now - now_floor < EV_TS_CONST (MIN_TIMEJUMP * .5)))
2333
3960
  {
2334
3961
  ev_rt_now = rtmn_diff + mn_now;
2335
3962
  return;
@@ -2348,9 +3975,12 @@ time_update (EV_P_ ev_tstamp max_block)
2348
3975
  */
2349
3976
  for (i = 4; --i; )
2350
3977
  {
3978
+ ev_tstamp diff;
2351
3979
  rtmn_diff = ev_rt_now - mn_now;
2352
3980
 
2353
- if (expect_true (fabs (odiff - rtmn_diff) < MIN_TIMEJUMP))
3981
+ diff = odiff - rtmn_diff;
3982
+
3983
+ if (ecb_expect_true ((diff < EV_TS_CONST (0.) ? -diff : diff) < EV_TS_CONST (MIN_TIMEJUMP)))
2354
3984
  return; /* all is well */
2355
3985
 
2356
3986
  ev_rt_now = ev_time ();
@@ -2369,7 +3999,7 @@ time_update (EV_P_ ev_tstamp max_block)
2369
3999
  {
2370
4000
  ev_rt_now = ev_time ();
2371
4001
 
2372
- if (expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + MIN_TIMEJUMP))
4002
+ if (ecb_expect_false (mn_now > ev_rt_now || ev_rt_now > mn_now + max_block + EV_TS_CONST (MIN_TIMEJUMP)))
2373
4003
  {
2374
4004
  /* adjust timers. this is easy, as the offset is the same for all of them */
2375
4005
  timers_reschedule (EV_A_ ev_rt_now - mn_now);
@@ -2382,9 +4012,30 @@ time_update (EV_P_ ev_tstamp max_block)
2382
4012
  }
2383
4013
  }
2384
4014
 
2385
- void
4015
+ /* ########## NIO4R PATCHERY HO! ########## */
4016
+ struct ev_poll_args {
4017
+ struct ev_loop *loop;
4018
+ ev_tstamp waittime;
4019
+ };
4020
+
4021
+ static
4022
+ void * ev_backend_poll(void *ptr)
4023
+ {
4024
+ struct ev_poll_args *args = (struct ev_poll_args *)ptr;
4025
+ struct ev_loop *loop = args->loop;
4026
+ backend_poll (EV_A_ args->waittime);
4027
+
4028
+ return NULL;
4029
+ }
4030
+ /* ######################################## */
4031
+
4032
+ int
2386
4033
  ev_run (EV_P_ int flags)
2387
4034
  {
4035
+ /* ########## NIO4R PATCHERY HO! ########## */
4036
+ struct ev_poll_args poll_args;
4037
+ /* ######################################## */
4038
+
2388
4039
  #if EV_FEATURE_API
2389
4040
  ++loop_depth;
2390
4041
  #endif
@@ -2402,8 +4053,8 @@ ev_run (EV_P_ int flags)
2402
4053
  #endif
2403
4054
 
2404
4055
  #ifndef _WIN32
2405
- if (expect_false (curpid)) /* penalise the forking check even more */
2406
- if (expect_false (getpid () != curpid))
4056
+ if (ecb_expect_false (curpid)) /* penalise the forking check even more */
4057
+ if (ecb_expect_false (getpid () != curpid))
2407
4058
  {
2408
4059
  curpid = getpid ();
2409
4060
  postfork = 1;
@@ -2412,7 +4063,7 @@ ev_run (EV_P_ int flags)
2412
4063
 
2413
4064
  #if EV_FORK_ENABLE
2414
4065
  /* we might have forked, so queue fork handlers */
2415
- if (expect_false (postfork))
4066
+ if (ecb_expect_false (postfork))
2416
4067
  if (forkcnt)
2417
4068
  {
2418
4069
  queue_events (EV_A_ (W *)forks, forkcnt, EV_FORK);
@@ -2422,18 +4073,18 @@ ev_run (EV_P_ int flags)
2422
4073
 
2423
4074
  #if EV_PREPARE_ENABLE
2424
4075
  /* queue prepare watchers (and execute them) */
2425
- if (expect_false (preparecnt))
4076
+ if (ecb_expect_false (preparecnt))
2426
4077
  {
2427
4078
  queue_events (EV_A_ (W *)prepares, preparecnt, EV_PREPARE);
2428
4079
  EV_INVOKE_PENDING;
2429
4080
  }
2430
4081
  #endif
2431
4082
 
2432
- if (expect_false (loop_done))
4083
+ if (ecb_expect_false (loop_done))
2433
4084
  break;
2434
4085
 
2435
4086
  /* we might have forked, so reify kernel state if necessary */
2436
- if (expect_false (postfork))
4087
+ if (ecb_expect_false (postfork))
2437
4088
  loop_fork (EV_A);
2438
4089
 
2439
4090
  /* update fd-related kernel structures */
@@ -2448,39 +4099,66 @@ ev_run (EV_P_ int flags)
2448
4099
  ev_tstamp prev_mn_now = mn_now;
2449
4100
 
2450
4101
  /* update time to cancel out callback processing overhead */
2451
- time_update (EV_A_ 1e100);
4102
+ time_update (EV_A_ EV_TS_CONST (EV_TSTAMP_HUGE));
4103
+
4104
+ /* from now on, we want a pipe-wake-up */
4105
+ pipe_write_wanted = 1;
2452
4106
 
2453
- if (expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt)))
4107
+ ECB_MEMORY_FENCE; /* make sure pipe_write_wanted is visible before we check for potential skips */
4108
+
4109
+ if (ecb_expect_true (!(flags & EVRUN_NOWAIT || idleall || !activecnt || pipe_write_skipped)))
2454
4110
  {
2455
- waittime = MAX_BLOCKTIME;
4111
+ waittime = EV_TS_CONST (MAX_BLOCKTIME);
4112
+
4113
+ #if EV_USE_TIMERFD
4114
+ /* sleep a lot longer when we can reliably detect timejumps */
4115
+ if (ecb_expect_true (timerfd >= 0))
4116
+ waittime = EV_TS_CONST (MAX_BLOCKTIME2);
4117
+ #endif
4118
+ #if !EV_PERIODIC_ENABLE
4119
+ /* without periodics but with monotonic clock there is no need */
4120
+ /* for any time jump detection, so sleep longer */
4121
+ if (ecb_expect_true (have_monotonic))
4122
+ waittime = EV_TS_CONST (MAX_BLOCKTIME2);
4123
+ #endif
2456
4124
 
2457
4125
  if (timercnt)
2458
4126
  {
2459
- ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now + backend_fudge;
4127
+ ev_tstamp to = ANHE_at (timers [HEAP0]) - mn_now;
2460
4128
  if (waittime > to) waittime = to;
2461
4129
  }
2462
4130
 
2463
4131
  #if EV_PERIODIC_ENABLE
2464
4132
  if (periodiccnt)
2465
4133
  {
2466
- ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now + backend_fudge;
4134
+ ev_tstamp to = ANHE_at (periodics [HEAP0]) - ev_rt_now;
2467
4135
  if (waittime > to) waittime = to;
2468
4136
  }
2469
4137
  #endif
2470
4138
 
2471
4139
  /* don't let timeouts decrease the waittime below timeout_blocktime */
2472
- if (expect_false (waittime < timeout_blocktime))
4140
+ if (ecb_expect_false (waittime < timeout_blocktime))
2473
4141
  waittime = timeout_blocktime;
2474
4142
 
4143
+ /* now there are two more special cases left, either we have
4144
+ * already-expired timers, so we should not sleep, or we have timers
4145
+ * that expire very soon, in which case we need to wait for a minimum
4146
+ * amount of time for some event loop backends.
4147
+ */
4148
+ if (ecb_expect_false (waittime < backend_mintime))
4149
+ waittime = waittime <= EV_TS_CONST (0.)
4150
+ ? EV_TS_CONST (0.)
4151
+ : backend_mintime;
4152
+
2475
4153
  /* extra check because io_blocktime is commonly 0 */
2476
- if (expect_false (io_blocktime))
4154
+ if (ecb_expect_false (io_blocktime))
2477
4155
  {
2478
4156
  sleeptime = io_blocktime - (mn_now - prev_mn_now);
2479
4157
 
2480
- if (sleeptime > waittime - backend_fudge)
2481
- sleeptime = waittime - backend_fudge;
4158
+ if (sleeptime > waittime - backend_mintime)
4159
+ sleeptime = waittime - backend_mintime;
2482
4160
 
2483
- if (expect_true (sleeptime > 0.))
4161
+ if (ecb_expect_true (sleeptime > EV_TS_CONST (0.)))
2484
4162
  {
2485
4163
  ev_sleep (sleeptime);
2486
4164
  waittime -= sleeptime;
@@ -2492,9 +4170,65 @@ ev_run (EV_P_ int flags)
2492
4170
  ++loop_count;
2493
4171
  #endif
2494
4172
  assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
2495
- backend_poll (EV_A_ waittime);
4173
+
4174
+ /*
4175
+ ########################## NIO4R PATCHERY HO! ##########################
4176
+
4177
+ According to the grandwizards of Ruby, locking and unlocking of the global
4178
+ interpreter lock are apparently too powerful a concept for a mere mortal to
4179
+ wield (although redefining what + and - do to numbers is totally cool).
4180
+ And so it came to pass that the only acceptable way to release the global
4181
+ interpreter lock is through a convoluted callback system that thakes a
4182
+ function pointer. While the grandwizard of libev foresaw this sort of scenario,
4183
+ he too attempted to place an API with callbacks on it, one that runs before
4184
+ the system call, and one that runs immediately after.
4185
+
4186
+ And so it came to pass that trying to wrap everything up in callbacks created
4187
+ two incompatible APIs, Ruby's which releases the global interpreter lock and
4188
+ reacquires it when the callback returns, and libev's, which wants two
4189
+ callbacks, one which runs before the polling operation starts, and one which
4190
+ runs after it finishes.
4191
+
4192
+ These two systems are incompatible as they both want to use callbacks to
4193
+ solve the same problem, however libev wants to use before/after callbacks,
4194
+ and Ruby wants to use an "around" callback. This presents a significant
4195
+ problem as these two patterns of callbacks are diametrical opposites of each
4196
+ other and thus cannot be composed.
4197
+
4198
+ And thus we are left with no choice but to patch the internals of libev in
4199
+ order to release a mutex at just the precise moment.
4200
+
4201
+ This is a great example of a situation where granular locking and unlocking
4202
+ of the GVL is practically required. The goal is to get as close to the
4203
+ system call as possible, and to keep the GVL unlocked for the shortest
4204
+ amount of time possible.
4205
+
4206
+ Perhaps Ruby could benefit from such an API, e.g:
4207
+
4208
+ rb_thread_unsafe_dangerous_crazy_blocking_region_begin(...);
4209
+ rb_thread_unsafe_dangerous_crazy_blocking_region_end(...);
4210
+
4211
+ #######################################################################
4212
+ */
4213
+
4214
+ poll_args.loop = loop;
4215
+ poll_args.waittime = waittime;
4216
+ rb_thread_call_without_gvl(ev_backend_poll, (void *)&poll_args, RUBY_UBF_IO, 0);
4217
+ /*
4218
+ ############################# END PATCHERY ############################
4219
+ */
4220
+
2496
4221
  assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
2497
4222
 
4223
+ pipe_write_wanted = 0; /* just an optimisation, no fence needed */
4224
+
4225
+ ECB_MEMORY_FENCE_ACQUIRE;
4226
+ if (pipe_write_skipped)
4227
+ {
4228
+ assert (("libev: pipe_w not active, but pipe not written", ev_is_active (&pipe_w)));
4229
+ ev_feed_event (EV_A_ &pipe_w, EV_CUSTOM);
4230
+ }
4231
+
2498
4232
  /* update ev_rt_now, do magic */
2499
4233
  time_update (EV_A_ waittime + sleeptime);
2500
4234
  }
@@ -2512,13 +4246,13 @@ ev_run (EV_P_ int flags)
2512
4246
 
2513
4247
  #if EV_CHECK_ENABLE
2514
4248
  /* queue check watchers, to be executed first */
2515
- if (expect_false (checkcnt))
4249
+ if (ecb_expect_false (checkcnt))
2516
4250
  queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
2517
4251
  #endif
2518
4252
 
2519
4253
  EV_INVOKE_PENDING;
2520
4254
  }
2521
- while (expect_true (
4255
+ while (ecb_expect_true (
2522
4256
  activecnt
2523
4257
  && !loop_done
2524
4258
  && !(flags & (EVRUN_ONCE | EVRUN_NOWAIT))
@@ -2530,40 +4264,42 @@ ev_run (EV_P_ int flags)
2530
4264
  #if EV_FEATURE_API
2531
4265
  --loop_depth;
2532
4266
  #endif
4267
+
4268
+ return activecnt;
2533
4269
  }
2534
4270
 
2535
4271
  void
2536
- ev_break (EV_P_ int how)
4272
+ ev_break (EV_P_ int how) EV_NOEXCEPT
2537
4273
  {
2538
4274
  loop_done = how;
2539
4275
  }
2540
4276
 
2541
4277
  void
2542
- ev_ref (EV_P)
4278
+ ev_ref (EV_P) EV_NOEXCEPT
2543
4279
  {
2544
4280
  ++activecnt;
2545
4281
  }
2546
4282
 
2547
4283
  void
2548
- ev_unref (EV_P)
4284
+ ev_unref (EV_P) EV_NOEXCEPT
2549
4285
  {
2550
4286
  --activecnt;
2551
4287
  }
2552
4288
 
2553
4289
  void
2554
- ev_now_update (EV_P)
4290
+ ev_now_update (EV_P) EV_NOEXCEPT
2555
4291
  {
2556
- time_update (EV_A_ 1e100);
4292
+ time_update (EV_A_ EV_TSTAMP_HUGE);
2557
4293
  }
2558
4294
 
2559
4295
  void
2560
- ev_suspend (EV_P)
4296
+ ev_suspend (EV_P) EV_NOEXCEPT
2561
4297
  {
2562
4298
  ev_now_update (EV_A);
2563
4299
  }
2564
4300
 
2565
4301
  void
2566
- ev_resume (EV_P)
4302
+ ev_resume (EV_P) EV_NOEXCEPT
2567
4303
  {
2568
4304
  ev_tstamp mn_prev = mn_now;
2569
4305
 
@@ -2590,7 +4326,7 @@ wlist_del (WL *head, WL elem)
2590
4326
  {
2591
4327
  while (*head)
2592
4328
  {
2593
- if (expect_true (*head == elem))
4329
+ if (ecb_expect_true (*head == elem))
2594
4330
  {
2595
4331
  *head = elem->next;
2596
4332
  break;
@@ -2612,12 +4348,12 @@ clear_pending (EV_P_ W w)
2612
4348
  }
2613
4349
 
2614
4350
  int
2615
- ev_clear_pending (EV_P_ void *w)
4351
+ ev_clear_pending (EV_P_ void *w) EV_NOEXCEPT
2616
4352
  {
2617
4353
  W w_ = (W)w;
2618
4354
  int pending = w_->pending;
2619
4355
 
2620
- if (expect_true (pending))
4356
+ if (ecb_expect_true (pending))
2621
4357
  {
2622
4358
  ANPENDING *p = pendings [ABSPRI (w_)] + pending - 1;
2623
4359
  p->w = (W)&pending_w;
@@ -2654,38 +4390,49 @@ ev_stop (EV_P_ W w)
2654
4390
 
2655
4391
  /*****************************************************************************/
2656
4392
 
2657
- void noinline
2658
- ev_io_start (EV_P_ ev_io *w)
4393
+ ecb_noinline
4394
+ void
4395
+ ev_io_start (EV_P_ ev_io *w) EV_NOEXCEPT
2659
4396
  {
2660
4397
  int fd = w->fd;
2661
4398
 
2662
- if (expect_false (ev_is_active (w)))
4399
+ if (ecb_expect_false (ev_is_active (w)))
2663
4400
  return;
2664
4401
 
2665
4402
  assert (("libev: ev_io_start called with negative fd", fd >= 0));
2666
4403
  assert (("libev: ev_io_start called with illegal event mask", !(w->events & ~(EV__IOFDSET | EV_READ | EV_WRITE))));
2667
4404
 
4405
+ #if EV_VERIFY >= 2
4406
+ assert (("libev: ev_io_start called on watcher with invalid fd", fd_valid (fd)));
4407
+ #endif
2668
4408
  EV_FREQUENT_CHECK;
2669
4409
 
2670
4410
  ev_start (EV_A_ (W)w, 1);
2671
- array_needsize (ANFD, anfds, anfdmax, fd + 1, array_init_zero);
4411
+ array_needsize (ANFD, anfds, anfdmax, fd + 1, array_needsize_zerofill);
2672
4412
  wlist_add (&anfds[fd].head, (WL)w);
2673
4413
 
4414
+ /* common bug, apparently */
4415
+ assert (("libev: ev_io_start called with corrupted watcher", ((WL)w)->next != (WL)w));
4416
+
2674
4417
  fd_change (EV_A_ fd, w->events & EV__IOFDSET | EV_ANFD_REIFY);
2675
4418
  w->events &= ~EV__IOFDSET;
2676
4419
 
2677
4420
  EV_FREQUENT_CHECK;
2678
4421
  }
2679
4422
 
2680
- void noinline
2681
- ev_io_stop (EV_P_ ev_io *w)
4423
+ ecb_noinline
4424
+ void
4425
+ ev_io_stop (EV_P_ ev_io *w) EV_NOEXCEPT
2682
4426
  {
2683
4427
  clear_pending (EV_A_ (W)w);
2684
- if (expect_false (!ev_is_active (w)))
4428
+ if (ecb_expect_false (!ev_is_active (w)))
2685
4429
  return;
2686
4430
 
2687
4431
  assert (("libev: ev_io_stop called with illegal fd (must stay constant after start!)", w->fd >= 0 && w->fd < anfdmax));
2688
4432
 
4433
+ #if EV_VERIFY >= 2
4434
+ assert (("libev: ev_io_stop called on watcher with invalid fd", fd_valid (w->fd)));
4435
+ #endif
2689
4436
  EV_FREQUENT_CHECK;
2690
4437
 
2691
4438
  wlist_del (&anfds[w->fd].head, (WL)w);
@@ -2696,10 +4443,11 @@ ev_io_stop (EV_P_ ev_io *w)
2696
4443
  EV_FREQUENT_CHECK;
2697
4444
  }
2698
4445
 
2699
- void noinline
2700
- ev_timer_start (EV_P_ ev_timer *w)
4446
+ ecb_noinline
4447
+ void
4448
+ ev_timer_start (EV_P_ ev_timer *w) EV_NOEXCEPT
2701
4449
  {
2702
- if (expect_false (ev_is_active (w)))
4450
+ if (ecb_expect_false (ev_is_active (w)))
2703
4451
  return;
2704
4452
 
2705
4453
  ev_at (w) += mn_now;
@@ -2710,7 +4458,7 @@ ev_timer_start (EV_P_ ev_timer *w)
2710
4458
 
2711
4459
  ++timercnt;
2712
4460
  ev_start (EV_A_ (W)w, timercnt + HEAP0 - 1);
2713
- array_needsize (ANHE, timers, timermax, ev_active (w) + 1, EMPTY2);
4461
+ array_needsize (ANHE, timers, timermax, ev_active (w) + 1, array_needsize_noinit);
2714
4462
  ANHE_w (timers [ev_active (w)]) = (WT)w;
2715
4463
  ANHE_at_cache (timers [ev_active (w)]);
2716
4464
  upheap (timers, ev_active (w));
@@ -2720,11 +4468,12 @@ ev_timer_start (EV_P_ ev_timer *w)
2720
4468
  /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/
2721
4469
  }
2722
4470
 
2723
- void noinline
2724
- ev_timer_stop (EV_P_ ev_timer *w)
4471
+ ecb_noinline
4472
+ void
4473
+ ev_timer_stop (EV_P_ ev_timer *w) EV_NOEXCEPT
2725
4474
  {
2726
4475
  clear_pending (EV_A_ (W)w);
2727
- if (expect_false (!ev_is_active (w)))
4476
+ if (ecb_expect_false (!ev_is_active (w)))
2728
4477
  return;
2729
4478
 
2730
4479
  EV_FREQUENT_CHECK;
@@ -2736,7 +4485,7 @@ ev_timer_stop (EV_P_ ev_timer *w)
2736
4485
 
2737
4486
  --timercnt;
2738
4487
 
2739
- if (expect_true (active < timercnt + HEAP0))
4488
+ if (ecb_expect_true (active < timercnt + HEAP0))
2740
4489
  {
2741
4490
  timers [active] = timers [timercnt + HEAP0];
2742
4491
  adjustheap (timers, timercnt, active);
@@ -2750,11 +4499,14 @@ ev_timer_stop (EV_P_ ev_timer *w)
2750
4499
  EV_FREQUENT_CHECK;
2751
4500
  }
2752
4501
 
2753
- void noinline
2754
- ev_timer_again (EV_P_ ev_timer *w)
4502
+ ecb_noinline
4503
+ void
4504
+ ev_timer_again (EV_P_ ev_timer *w) EV_NOEXCEPT
2755
4505
  {
2756
4506
  EV_FREQUENT_CHECK;
2757
4507
 
4508
+ clear_pending (EV_A_ (W)w);
4509
+
2758
4510
  if (ev_is_active (w))
2759
4511
  {
2760
4512
  if (w->repeat)
@@ -2776,18 +4528,24 @@ ev_timer_again (EV_P_ ev_timer *w)
2776
4528
  }
2777
4529
 
2778
4530
  ev_tstamp
2779
- ev_timer_remaining (EV_P_ ev_timer *w)
4531
+ ev_timer_remaining (EV_P_ ev_timer *w) EV_NOEXCEPT
2780
4532
  {
2781
- return ev_at (w) - (ev_is_active (w) ? mn_now : 0.);
4533
+ return ev_at (w) - (ev_is_active (w) ? mn_now : EV_TS_CONST (0.));
2782
4534
  }
2783
4535
 
2784
4536
  #if EV_PERIODIC_ENABLE
2785
- void noinline
2786
- ev_periodic_start (EV_P_ ev_periodic *w)
4537
+ ecb_noinline
4538
+ void
4539
+ ev_periodic_start (EV_P_ ev_periodic *w) EV_NOEXCEPT
2787
4540
  {
2788
- if (expect_false (ev_is_active (w)))
4541
+ if (ecb_expect_false (ev_is_active (w)))
2789
4542
  return;
2790
4543
 
4544
+ #if EV_USE_TIMERFD
4545
+ if (timerfd == -2)
4546
+ evtimerfd_init (EV_A);
4547
+ #endif
4548
+
2791
4549
  if (w->reschedule_cb)
2792
4550
  ev_at (w) = w->reschedule_cb (w, ev_rt_now);
2793
4551
  else if (w->interval)
@@ -2802,7 +4560,7 @@ ev_periodic_start (EV_P_ ev_periodic *w)
2802
4560
 
2803
4561
  ++periodiccnt;
2804
4562
  ev_start (EV_A_ (W)w, periodiccnt + HEAP0 - 1);
2805
- array_needsize (ANHE, periodics, periodicmax, ev_active (w) + 1, EMPTY2);
4563
+ array_needsize (ANHE, periodics, periodicmax, ev_active (w) + 1, array_needsize_noinit);
2806
4564
  ANHE_w (periodics [ev_active (w)]) = (WT)w;
2807
4565
  ANHE_at_cache (periodics [ev_active (w)]);
2808
4566
  upheap (periodics, ev_active (w));
@@ -2812,11 +4570,12 @@ ev_periodic_start (EV_P_ ev_periodic *w)
2812
4570
  /*assert (("libev: internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/
2813
4571
  }
2814
4572
 
2815
- void noinline
2816
- ev_periodic_stop (EV_P_ ev_periodic *w)
4573
+ ecb_noinline
4574
+ void
4575
+ ev_periodic_stop (EV_P_ ev_periodic *w) EV_NOEXCEPT
2817
4576
  {
2818
4577
  clear_pending (EV_A_ (W)w);
2819
- if (expect_false (!ev_is_active (w)))
4578
+ if (ecb_expect_false (!ev_is_active (w)))
2820
4579
  return;
2821
4580
 
2822
4581
  EV_FREQUENT_CHECK;
@@ -2828,7 +4587,7 @@ ev_periodic_stop (EV_P_ ev_periodic *w)
2828
4587
 
2829
4588
  --periodiccnt;
2830
4589
 
2831
- if (expect_true (active < periodiccnt + HEAP0))
4590
+ if (ecb_expect_true (active < periodiccnt + HEAP0))
2832
4591
  {
2833
4592
  periodics [active] = periodics [periodiccnt + HEAP0];
2834
4593
  adjustheap (periodics, periodiccnt, active);
@@ -2840,8 +4599,9 @@ ev_periodic_stop (EV_P_ ev_periodic *w)
2840
4599
  EV_FREQUENT_CHECK;
2841
4600
  }
2842
4601
 
2843
- void noinline
2844
- ev_periodic_again (EV_P_ ev_periodic *w)
4602
+ ecb_noinline
4603
+ void
4604
+ ev_periodic_again (EV_P_ ev_periodic *w) EV_NOEXCEPT
2845
4605
  {
2846
4606
  /* TODO: use adjustheap and recalculation */
2847
4607
  ev_periodic_stop (EV_A_ w);
@@ -2855,10 +4615,11 @@ ev_periodic_again (EV_P_ ev_periodic *w)
2855
4615
 
2856
4616
  #if EV_SIGNAL_ENABLE
2857
4617
 
2858
- void noinline
2859
- ev_signal_start (EV_P_ ev_signal *w)
4618
+ ecb_noinline
4619
+ void
4620
+ ev_signal_start (EV_P_ ev_signal *w) EV_NOEXCEPT
2860
4621
  {
2861
- if (expect_false (ev_is_active (w)))
4622
+ if (ecb_expect_false (ev_is_active (w)))
2862
4623
  return;
2863
4624
 
2864
4625
  assert (("libev: ev_signal_start called with illegal signal number", w->signum > 0 && w->signum < EV_NSIG));
@@ -2868,6 +4629,7 @@ ev_signal_start (EV_P_ ev_signal *w)
2868
4629
  !signals [w->signum - 1].loop || signals [w->signum - 1].loop == loop));
2869
4630
 
2870
4631
  signals [w->signum - 1].loop = EV_A;
4632
+ ECB_MEMORY_FENCE_RELEASE;
2871
4633
  #endif
2872
4634
 
2873
4635
  EV_FREQUENT_CHECK;
@@ -2936,11 +4698,12 @@ ev_signal_start (EV_P_ ev_signal *w)
2936
4698
  EV_FREQUENT_CHECK;
2937
4699
  }
2938
4700
 
2939
- void noinline
2940
- ev_signal_stop (EV_P_ ev_signal *w)
4701
+ ecb_noinline
4702
+ void
4703
+ ev_signal_stop (EV_P_ ev_signal *w) EV_NOEXCEPT
2941
4704
  {
2942
4705
  clear_pending (EV_A_ (W)w);
2943
- if (expect_false (!ev_is_active (w)))
4706
+ if (ecb_expect_false (!ev_is_active (w)))
2944
4707
  return;
2945
4708
 
2946
4709
  EV_FREQUENT_CHECK;
@@ -2978,12 +4741,12 @@ ev_signal_stop (EV_P_ ev_signal *w)
2978
4741
  #if EV_CHILD_ENABLE
2979
4742
 
2980
4743
  void
2981
- ev_child_start (EV_P_ ev_child *w)
4744
+ ev_child_start (EV_P_ ev_child *w) EV_NOEXCEPT
2982
4745
  {
2983
4746
  #if EV_MULTIPLICITY
2984
4747
  assert (("libev: child watchers are only supported in the default loop", loop == ev_default_loop_ptr));
2985
4748
  #endif
2986
- if (expect_false (ev_is_active (w)))
4749
+ if (ecb_expect_false (ev_is_active (w)))
2987
4750
  return;
2988
4751
 
2989
4752
  EV_FREQUENT_CHECK;
@@ -2995,10 +4758,10 @@ ev_child_start (EV_P_ ev_child *w)
2995
4758
  }
2996
4759
 
2997
4760
  void
2998
- ev_child_stop (EV_P_ ev_child *w)
4761
+ ev_child_stop (EV_P_ ev_child *w) EV_NOEXCEPT
2999
4762
  {
3000
4763
  clear_pending (EV_A_ (W)w);
3001
- if (expect_false (!ev_is_active (w)))
4764
+ if (ecb_expect_false (!ev_is_active (w)))
3002
4765
  return;
3003
4766
 
3004
4767
  EV_FREQUENT_CHECK;
@@ -3022,17 +4785,21 @@ ev_child_stop (EV_P_ ev_child *w)
3022
4785
  #define NFS_STAT_INTERVAL 30.1074891 /* for filesystems potentially failing inotify */
3023
4786
  #define MIN_STAT_INTERVAL 0.1074891
3024
4787
 
3025
- static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents);
4788
+ ecb_noinline static void stat_timer_cb (EV_P_ ev_timer *w_, int revents);
3026
4789
 
3027
4790
  #if EV_USE_INOTIFY
3028
4791
 
3029
4792
  /* the * 2 is to allow for alignment padding, which for some reason is >> 8 */
3030
4793
  # define EV_INOTIFY_BUFSIZE (sizeof (struct inotify_event) * 2 + NAME_MAX)
3031
4794
 
3032
- static void noinline
4795
+ ecb_noinline
4796
+ static void
3033
4797
  infy_add (EV_P_ ev_stat *w)
3034
4798
  {
3035
- 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);
4799
+ w->wd = inotify_add_watch (fs_fd, w->path,
4800
+ IN_ATTRIB | IN_DELETE_SELF | IN_MOVE_SELF | IN_MODIFY
4801
+ | IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO
4802
+ | IN_DONT_FOLLOW | IN_MASK_ADD);
3036
4803
 
3037
4804
  if (w->wd >= 0)
3038
4805
  {
@@ -3046,10 +4813,16 @@ infy_add (EV_P_ ev_stat *w)
3046
4813
  w->timer.repeat = w->interval ? w->interval : DEF_STAT_INTERVAL;
3047
4814
  else if (!statfs (w->path, &sfs)
3048
4815
  && (sfs.f_type == 0x1373 /* devfs */
4816
+ || sfs.f_type == 0x4006 /* fat */
4817
+ || sfs.f_type == 0x4d44 /* msdos */
3049
4818
  || sfs.f_type == 0xEF53 /* ext2/3 */
4819
+ || sfs.f_type == 0x72b6 /* jffs2 */
4820
+ || sfs.f_type == 0x858458f6 /* ramfs */
4821
+ || sfs.f_type == 0x5346544e /* ntfs */
3050
4822
  || sfs.f_type == 0x3153464a /* jfs */
4823
+ || sfs.f_type == 0x9123683e /* btrfs */
3051
4824
  || sfs.f_type == 0x52654973 /* reiser3 */
3052
- || sfs.f_type == 0x01021994 /* tempfs */
4825
+ || sfs.f_type == 0x01021994 /* tmpfs */
3053
4826
  || sfs.f_type == 0x58465342 /* xfs */))
3054
4827
  w->timer.repeat = 0.; /* filesystem is local, kernel new enough */
3055
4828
  else
@@ -3094,7 +4867,8 @@ infy_add (EV_P_ ev_stat *w)
3094
4867
  if (ev_is_active (&w->timer)) ev_unref (EV_A);
3095
4868
  }
3096
4869
 
3097
- static void noinline
4870
+ ecb_noinline
4871
+ static void
3098
4872
  infy_del (EV_P_ ev_stat *w)
3099
4873
  {
3100
4874
  int slot;
@@ -3111,7 +4885,8 @@ infy_del (EV_P_ ev_stat *w)
3111
4885
  inotify_rm_watch (fs_fd, wd);
3112
4886
  }
3113
4887
 
3114
- static void noinline
4888
+ ecb_noinline
4889
+ static void
3115
4890
  infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev)
3116
4891
  {
3117
4892
  if (slot < 0)
@@ -3157,7 +4932,8 @@ infy_cb (EV_P_ ev_io *w, int revents)
3157
4932
  }
3158
4933
  }
3159
4934
 
3160
- inline_size void
4935
+ inline_size ecb_cold
4936
+ void
3161
4937
  ev_check_2625 (EV_P)
3162
4938
  {
3163
4939
  /* kernels < 2.6.25 are borked
@@ -3172,7 +4948,7 @@ ev_check_2625 (EV_P)
3172
4948
  inline_size int
3173
4949
  infy_newfd (void)
3174
4950
  {
3175
- #if defined (IN_CLOEXEC) && defined (IN_NONBLOCK)
4951
+ #if defined IN_CLOEXEC && defined IN_NONBLOCK
3176
4952
  int fd = inotify_init1 (IN_CLOEXEC | IN_NONBLOCK);
3177
4953
  if (fd >= 0)
3178
4954
  return fd;
@@ -3257,7 +5033,7 @@ infy_fork (EV_P)
3257
5033
  #endif
3258
5034
 
3259
5035
  void
3260
- ev_stat_stat (EV_P_ ev_stat *w)
5036
+ ev_stat_stat (EV_P_ ev_stat *w) EV_NOEXCEPT
3261
5037
  {
3262
5038
  if (lstat (w->path, &w->attr) < 0)
3263
5039
  w->attr.st_nlink = 0;
@@ -3265,7 +5041,8 @@ ev_stat_stat (EV_P_ ev_stat *w)
3265
5041
  w->attr.st_nlink = 1;
3266
5042
  }
3267
5043
 
3268
- static void noinline
5044
+ ecb_noinline
5045
+ static void
3269
5046
  stat_timer_cb (EV_P_ ev_timer *w_, int revents)
3270
5047
  {
3271
5048
  ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer));
@@ -3306,9 +5083,9 @@ stat_timer_cb (EV_P_ ev_timer *w_, int revents)
3306
5083
  }
3307
5084
 
3308
5085
  void
3309
- ev_stat_start (EV_P_ ev_stat *w)
5086
+ ev_stat_start (EV_P_ ev_stat *w) EV_NOEXCEPT
3310
5087
  {
3311
- if (expect_false (ev_is_active (w)))
5088
+ if (ecb_expect_false (ev_is_active (w)))
3312
5089
  return;
3313
5090
 
3314
5091
  ev_stat_stat (EV_A_ w);
@@ -3337,10 +5114,10 @@ ev_stat_start (EV_P_ ev_stat *w)
3337
5114
  }
3338
5115
 
3339
5116
  void
3340
- ev_stat_stop (EV_P_ ev_stat *w)
5117
+ ev_stat_stop (EV_P_ ev_stat *w) EV_NOEXCEPT
3341
5118
  {
3342
5119
  clear_pending (EV_A_ (W)w);
3343
- if (expect_false (!ev_is_active (w)))
5120
+ if (ecb_expect_false (!ev_is_active (w)))
3344
5121
  return;
3345
5122
 
3346
5123
  EV_FREQUENT_CHECK;
@@ -3363,9 +5140,9 @@ ev_stat_stop (EV_P_ ev_stat *w)
3363
5140
 
3364
5141
  #if EV_IDLE_ENABLE
3365
5142
  void
3366
- ev_idle_start (EV_P_ ev_idle *w)
5143
+ ev_idle_start (EV_P_ ev_idle *w) EV_NOEXCEPT
3367
5144
  {
3368
- if (expect_false (ev_is_active (w)))
5145
+ if (ecb_expect_false (ev_is_active (w)))
3369
5146
  return;
3370
5147
 
3371
5148
  pri_adjust (EV_A_ (W)w);
@@ -3378,7 +5155,7 @@ ev_idle_start (EV_P_ ev_idle *w)
3378
5155
  ++idleall;
3379
5156
  ev_start (EV_A_ (W)w, active);
3380
5157
 
3381
- array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, EMPTY2);
5158
+ array_needsize (ev_idle *, idles [ABSPRI (w)], idlemax [ABSPRI (w)], active, array_needsize_noinit);
3382
5159
  idles [ABSPRI (w)][active - 1] = w;
3383
5160
  }
3384
5161
 
@@ -3386,10 +5163,10 @@ ev_idle_start (EV_P_ ev_idle *w)
3386
5163
  }
3387
5164
 
3388
5165
  void
3389
- ev_idle_stop (EV_P_ ev_idle *w)
5166
+ ev_idle_stop (EV_P_ ev_idle *w) EV_NOEXCEPT
3390
5167
  {
3391
5168
  clear_pending (EV_A_ (W)w);
3392
- if (expect_false (!ev_is_active (w)))
5169
+ if (ecb_expect_false (!ev_is_active (w)))
3393
5170
  return;
3394
5171
 
3395
5172
  EV_FREQUENT_CHECK;
@@ -3410,25 +5187,25 @@ ev_idle_stop (EV_P_ ev_idle *w)
3410
5187
 
3411
5188
  #if EV_PREPARE_ENABLE
3412
5189
  void
3413
- ev_prepare_start (EV_P_ ev_prepare *w)
5190
+ ev_prepare_start (EV_P_ ev_prepare *w) EV_NOEXCEPT
3414
5191
  {
3415
- if (expect_false (ev_is_active (w)))
5192
+ if (ecb_expect_false (ev_is_active (w)))
3416
5193
  return;
3417
5194
 
3418
5195
  EV_FREQUENT_CHECK;
3419
5196
 
3420
5197
  ev_start (EV_A_ (W)w, ++preparecnt);
3421
- array_needsize (ev_prepare *, prepares, preparemax, preparecnt, EMPTY2);
5198
+ array_needsize (ev_prepare *, prepares, preparemax, preparecnt, array_needsize_noinit);
3422
5199
  prepares [preparecnt - 1] = w;
3423
5200
 
3424
5201
  EV_FREQUENT_CHECK;
3425
5202
  }
3426
5203
 
3427
5204
  void
3428
- ev_prepare_stop (EV_P_ ev_prepare *w)
5205
+ ev_prepare_stop (EV_P_ ev_prepare *w) EV_NOEXCEPT
3429
5206
  {
3430
5207
  clear_pending (EV_A_ (W)w);
3431
- if (expect_false (!ev_is_active (w)))
5208
+ if (ecb_expect_false (!ev_is_active (w)))
3432
5209
  return;
3433
5210
 
3434
5211
  EV_FREQUENT_CHECK;
@@ -3448,25 +5225,25 @@ ev_prepare_stop (EV_P_ ev_prepare *w)
3448
5225
 
3449
5226
  #if EV_CHECK_ENABLE
3450
5227
  void
3451
- ev_check_start (EV_P_ ev_check *w)
5228
+ ev_check_start (EV_P_ ev_check *w) EV_NOEXCEPT
3452
5229
  {
3453
- if (expect_false (ev_is_active (w)))
5230
+ if (ecb_expect_false (ev_is_active (w)))
3454
5231
  return;
3455
5232
 
3456
5233
  EV_FREQUENT_CHECK;
3457
5234
 
3458
5235
  ev_start (EV_A_ (W)w, ++checkcnt);
3459
- array_needsize (ev_check *, checks, checkmax, checkcnt, EMPTY2);
5236
+ array_needsize (ev_check *, checks, checkmax, checkcnt, array_needsize_noinit);
3460
5237
  checks [checkcnt - 1] = w;
3461
5238
 
3462
5239
  EV_FREQUENT_CHECK;
3463
5240
  }
3464
5241
 
3465
5242
  void
3466
- ev_check_stop (EV_P_ ev_check *w)
5243
+ ev_check_stop (EV_P_ ev_check *w) EV_NOEXCEPT
3467
5244
  {
3468
5245
  clear_pending (EV_A_ (W)w);
3469
- if (expect_false (!ev_is_active (w)))
5246
+ if (ecb_expect_false (!ev_is_active (w)))
3470
5247
  return;
3471
5248
 
3472
5249
  EV_FREQUENT_CHECK;
@@ -3485,8 +5262,9 @@ ev_check_stop (EV_P_ ev_check *w)
3485
5262
  #endif
3486
5263
 
3487
5264
  #if EV_EMBED_ENABLE
3488
- void noinline
3489
- ev_embed_sweep (EV_P_ ev_embed *w)
5265
+ ecb_noinline
5266
+ void
5267
+ ev_embed_sweep (EV_P_ ev_embed *w) EV_NOEXCEPT
3490
5268
  {
3491
5269
  ev_run (w->other, EVRUN_NOWAIT);
3492
5270
  }
@@ -3518,6 +5296,7 @@ embed_prepare_cb (EV_P_ ev_prepare *prepare, int revents)
3518
5296
  }
3519
5297
  }
3520
5298
 
5299
+ #if EV_FORK_ENABLE
3521
5300
  static void
3522
5301
  embed_fork_cb (EV_P_ ev_fork *fork_w, int revents)
3523
5302
  {
@@ -3534,6 +5313,7 @@ embed_fork_cb (EV_P_ ev_fork *fork_w, int revents)
3534
5313
 
3535
5314
  ev_embed_start (EV_A_ w);
3536
5315
  }
5316
+ #endif
3537
5317
 
3538
5318
  #if 0
3539
5319
  static void
@@ -3544,9 +5324,9 @@ embed_idle_cb (EV_P_ ev_idle *idle, int revents)
3544
5324
  #endif
3545
5325
 
3546
5326
  void
3547
- ev_embed_start (EV_P_ ev_embed *w)
5327
+ ev_embed_start (EV_P_ ev_embed *w) EV_NOEXCEPT
3548
5328
  {
3549
- if (expect_false (ev_is_active (w)))
5329
+ if (ecb_expect_false (ev_is_active (w)))
3550
5330
  return;
3551
5331
 
3552
5332
  {
@@ -3564,8 +5344,10 @@ ev_embed_start (EV_P_ ev_embed *w)
3564
5344
  ev_set_priority (&w->prepare, EV_MINPRI);
3565
5345
  ev_prepare_start (EV_A_ &w->prepare);
3566
5346
 
5347
+ #if EV_FORK_ENABLE
3567
5348
  ev_fork_init (&w->fork, embed_fork_cb);
3568
5349
  ev_fork_start (EV_A_ &w->fork);
5350
+ #endif
3569
5351
 
3570
5352
  /*ev_idle_init (&w->idle, e,bed_idle_cb);*/
3571
5353
 
@@ -3575,17 +5357,19 @@ ev_embed_start (EV_P_ ev_embed *w)
3575
5357
  }
3576
5358
 
3577
5359
  void
3578
- ev_embed_stop (EV_P_ ev_embed *w)
5360
+ ev_embed_stop (EV_P_ ev_embed *w) EV_NOEXCEPT
3579
5361
  {
3580
5362
  clear_pending (EV_A_ (W)w);
3581
- if (expect_false (!ev_is_active (w)))
5363
+ if (ecb_expect_false (!ev_is_active (w)))
3582
5364
  return;
3583
5365
 
3584
5366
  EV_FREQUENT_CHECK;
3585
5367
 
3586
5368
  ev_io_stop (EV_A_ &w->io);
3587
5369
  ev_prepare_stop (EV_A_ &w->prepare);
5370
+ #if EV_FORK_ENABLE
3588
5371
  ev_fork_stop (EV_A_ &w->fork);
5372
+ #endif
3589
5373
 
3590
5374
  ev_stop (EV_A_ (W)w);
3591
5375
 
@@ -3595,25 +5379,25 @@ ev_embed_stop (EV_P_ ev_embed *w)
3595
5379
 
3596
5380
  #if EV_FORK_ENABLE
3597
5381
  void
3598
- ev_fork_start (EV_P_ ev_fork *w)
5382
+ ev_fork_start (EV_P_ ev_fork *w) EV_NOEXCEPT
3599
5383
  {
3600
- if (expect_false (ev_is_active (w)))
5384
+ if (ecb_expect_false (ev_is_active (w)))
3601
5385
  return;
3602
5386
 
3603
5387
  EV_FREQUENT_CHECK;
3604
5388
 
3605
5389
  ev_start (EV_A_ (W)w, ++forkcnt);
3606
- array_needsize (ev_fork *, forks, forkmax, forkcnt, EMPTY2);
5390
+ array_needsize (ev_fork *, forks, forkmax, forkcnt, array_needsize_noinit);
3607
5391
  forks [forkcnt - 1] = w;
3608
5392
 
3609
5393
  EV_FREQUENT_CHECK;
3610
5394
  }
3611
5395
 
3612
5396
  void
3613
- ev_fork_stop (EV_P_ ev_fork *w)
5397
+ ev_fork_stop (EV_P_ ev_fork *w) EV_NOEXCEPT
3614
5398
  {
3615
5399
  clear_pending (EV_A_ (W)w);
3616
- if (expect_false (!ev_is_active (w)))
5400
+ if (ecb_expect_false (!ev_is_active (w)))
3617
5401
  return;
3618
5402
 
3619
5403
  EV_FREQUENT_CHECK;
@@ -3633,15 +5417,15 @@ ev_fork_stop (EV_P_ ev_fork *w)
3633
5417
 
3634
5418
  #if EV_CLEANUP_ENABLE
3635
5419
  void
3636
- ev_cleanup_start (EV_P_ ev_cleanup *w)
5420
+ ev_cleanup_start (EV_P_ ev_cleanup *w) EV_NOEXCEPT
3637
5421
  {
3638
- if (expect_false (ev_is_active (w)))
5422
+ if (ecb_expect_false (ev_is_active (w)))
3639
5423
  return;
3640
5424
 
3641
5425
  EV_FREQUENT_CHECK;
3642
5426
 
3643
5427
  ev_start (EV_A_ (W)w, ++cleanupcnt);
3644
- array_needsize (ev_cleanup *, cleanups, cleanupmax, cleanupcnt, EMPTY2);
5428
+ array_needsize (ev_cleanup *, cleanups, cleanupmax, cleanupcnt, array_needsize_noinit);
3645
5429
  cleanups [cleanupcnt - 1] = w;
3646
5430
 
3647
5431
  /* cleanup watchers should never keep a refcount on the loop */
@@ -3650,10 +5434,10 @@ ev_cleanup_start (EV_P_ ev_cleanup *w)
3650
5434
  }
3651
5435
 
3652
5436
  void
3653
- ev_cleanup_stop (EV_P_ ev_cleanup *w)
5437
+ ev_cleanup_stop (EV_P_ ev_cleanup *w) EV_NOEXCEPT
3654
5438
  {
3655
5439
  clear_pending (EV_A_ (W)w);
3656
- if (expect_false (!ev_is_active (w)))
5440
+ if (ecb_expect_false (!ev_is_active (w)))
3657
5441
  return;
3658
5442
 
3659
5443
  EV_FREQUENT_CHECK;
@@ -3674,9 +5458,9 @@ ev_cleanup_stop (EV_P_ ev_cleanup *w)
3674
5458
 
3675
5459
  #if EV_ASYNC_ENABLE
3676
5460
  void
3677
- ev_async_start (EV_P_ ev_async *w)
5461
+ ev_async_start (EV_P_ ev_async *w) EV_NOEXCEPT
3678
5462
  {
3679
- if (expect_false (ev_is_active (w)))
5463
+ if (ecb_expect_false (ev_is_active (w)))
3680
5464
  return;
3681
5465
 
3682
5466
  w->sent = 0;
@@ -3686,17 +5470,17 @@ ev_async_start (EV_P_ ev_async *w)
3686
5470
  EV_FREQUENT_CHECK;
3687
5471
 
3688
5472
  ev_start (EV_A_ (W)w, ++asynccnt);
3689
- array_needsize (ev_async *, asyncs, asyncmax, asynccnt, EMPTY2);
5473
+ array_needsize (ev_async *, asyncs, asyncmax, asynccnt, array_needsize_noinit);
3690
5474
  asyncs [asynccnt - 1] = w;
3691
5475
 
3692
5476
  EV_FREQUENT_CHECK;
3693
5477
  }
3694
5478
 
3695
5479
  void
3696
- ev_async_stop (EV_P_ ev_async *w)
5480
+ ev_async_stop (EV_P_ ev_async *w) EV_NOEXCEPT
3697
5481
  {
3698
5482
  clear_pending (EV_A_ (W)w);
3699
- if (expect_false (!ev_is_active (w)))
5483
+ if (ecb_expect_false (!ev_is_active (w)))
3700
5484
  return;
3701
5485
 
3702
5486
  EV_FREQUENT_CHECK;
@@ -3714,7 +5498,7 @@ ev_async_stop (EV_P_ ev_async *w)
3714
5498
  }
3715
5499
 
3716
5500
  void
3717
- ev_async_send (EV_P_ ev_async *w)
5501
+ ev_async_send (EV_P_ ev_async *w) EV_NOEXCEPT
3718
5502
  {
3719
5503
  w->sent = 1;
3720
5504
  evpipe_write (EV_A_ &async_pending);
@@ -3761,16 +5545,10 @@ once_cb_to (EV_P_ ev_timer *w, int revents)
3761
5545
  }
3762
5546
 
3763
5547
  void
3764
- ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg)
5548
+ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg) EV_NOEXCEPT
3765
5549
  {
3766
5550
  struct ev_once *once = (struct ev_once *)ev_malloc (sizeof (struct ev_once));
3767
5551
 
3768
- if (expect_false (!once))
3769
- {
3770
- cb (EV_ERROR | EV_READ | EV_WRITE | EV_TIMER, arg);
3771
- return;
3772
- }
3773
-
3774
5552
  once->cb = cb;
3775
5553
  once->arg = arg;
3776
5554
 
@@ -3792,8 +5570,9 @@ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, vo
3792
5570
  /*****************************************************************************/
3793
5571
 
3794
5572
  #if EV_WALK_ENABLE
5573
+ ecb_cold
3795
5574
  void
3796
- ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
5575
+ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) EV_NOEXCEPT
3797
5576
  {
3798
5577
  int i, j;
3799
5578
  ev_watcher_list *wl, *wn;
@@ -3846,7 +5625,7 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
3846
5625
 
3847
5626
  #if EV_IDLE_ENABLE
3848
5627
  if (types & EV_IDLE)
3849
- for (j = NUMPRI; i--; )
5628
+ for (j = NUMPRI; j--; )
3850
5629
  for (i = idlecnt [j]; i--; )
3851
5630
  cb (EV_A_ EV_IDLE, idles [j][i]);
3852
5631
  #endif
@@ -3908,6 +5687,3 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w))
3908
5687
  #if EV_MULTIPLICITY
3909
5688
  #include "ev_wrap.h"
3910
5689
  #endif
3911
-
3912
- EV_CPP(})
3913
-