diff --git a/ext/libev/Changes b/ext/libev/Changes index 1ed0c4d..bb1e6d4 100644 --- a/ext/libev/Changes +++ b/ext/libev/Changes @@ -1,19 +1,24 @@ Revision history for libev, a high-performance and full-featured event loop. -TODO: ev_loop_wakeup -TODO: EV_STANDALONE == NO_HASSEL (do not use clock_gettime in ev_standalone) -TODO: faq, process a thing in each iteration -TODO: dbeugging tips, ev_verify, ev_init twice -TODO: ev_break for immediate exit (EVBREAK_NOW?) -TODO: ev_feed_child_event -TODO: document the special problem of signals around fork. -TODO: store pid for each signal -TODO: document file descriptor usage per loop -TODO: store loop pid_t and compare isndie signal handler,store 1 for same, 2 for differign pid, clean up in loop_fork -TODO: embed watchers need updating when fd changes -TODO: document portability requirements for atomic pointer access -TODO: possible cb aliasing? -TODO: document requirements for function pointers and calling conventions. +4.24 Wed Dec 28 05:19:55 CET 2016 + - bump version to 4.24, as the release tarball inexplicably + didn't have the right version in ev.h, even though the cvs-tagged + version did have the right one (reported by Ales Teska). + +4.23 Wed Nov 16 18:23:41 CET 2016 + - move some declarations at the beginning to help certain retarded + microsoft compilers, even though their documentation claims + otherwise (reported by Ruslan Osmanov). + +4.22 Sun Dec 20 22:11:50 CET 2015 + - when epoll detects unremovable fds in the fd set, rebuild + only the epoll descriptor, not the signal pipe, to avoid + SIGPIPE in ev_async_send. This doesn't solve it on fork, + so document what needs to be done in ev_loop_fork + (analyzed by Benjamin Mahler). + - remove superfluous sys/timeb.h include on win32 + (analyzed by Jason Madden). + - updated libecb. 4.20 Sat Jun 20 13:01:43 CEST 2015 - prefer noexcept over throw () with C++ 11. @@ -505,3 +510,4 @@ TODO: document requirements for function pointers and calling conventions. 0.1 Wed Oct 31 21:31:48 CET 2007 - original version; hacked together in <24h. + diff --git a/ext/libev/ev.c b/ext/libev/ev.c index 710dde0..b2572b1 100644 --- a/ext/libev/ev.c +++ b/ext/libev/ev.c @@ -539,7 +539,7 @@ struct signalfd_siginfo #define ECB_H /* 16 bits major, 16 bits minor */ -#define ECB_VERSION 0x00010004 +#define ECB_VERSION 0x00010005 #ifdef _WIN32 typedef signed char int8_t; @@ -566,7 +566,7 @@ struct signalfd_siginfo #endif #else #include - #if UINTMAX_MAX > 0xffffffffU + #if (defined INTPTR_MAX ? INTPTR_MAX : ULONG_MAX) > 0xffffffffU #define ECB_PTRSIZE 8 #else #define ECB_PTRSIZE 4 @@ -654,6 +654,10 @@ struct signalfd_siginfo #include #endif +#if 1400 <= _MSC_VER + #include /* fence functions _ReadBarrier, also bit search functions _BitScanReverse */ +#endif + #ifndef ECB_MEMORY_FENCE #if ECB_GCC_VERSION(2,5) || defined __INTEL_COMPILER || (__llvm__ && __GNUC__) || __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110 #if __i386 || __i386__ @@ -666,15 +670,23 @@ struct signalfd_siginfo #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("") #elif __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory") + #elif defined __ARM_ARCH_2__ \ + || defined __ARM_ARCH_3__ || defined __ARM_ARCH_3M__ \ + || defined __ARM_ARCH_4__ || defined __ARM_ARCH_4T__ \ + || defined __ARM_ARCH_5__ || defined __ARM_ARCH_5E__ \ + || defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__ \ + || defined __ARM_ARCH_5TEJ__ + /* should not need any, unless running old code on newer cpu - arm doesn't support that */ #elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ \ - || defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__ + || defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__ \ + || defined __ARM_ARCH_6T2__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,5" : : "r" (0) : "memory") #elif defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \ - || defined __ARM_ARCH_7M__ || defined __ARM_ARCH_7R__ + || defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory") #elif __aarch64__ #define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb ish" : : : "memory") - #elif (__sparc || __sparc__) && !__sparcv8 + #elif (__sparc || __sparc__) && !(__sparc_v8__ || defined __sparcv8) #define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad" : : : "memory") #define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory") #define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore") @@ -922,6 +934,11 @@ typedef int ecb_bool; ecb_function_ ecb_const int ecb_ctz32 (uint32_t x) { +#if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM) + unsigned long r; + _BitScanForward (&r, x); + return (int)r; +#else int r = 0; x &= ~x + 1; /* this isolates the lowest bit */ @@ -941,14 +958,21 @@ typedef int ecb_bool; #endif return r; +#endif } ecb_function_ ecb_const int ecb_ctz64 (uint64_t x); ecb_function_ ecb_const int ecb_ctz64 (uint64_t x) { - int shift = x & 0xffffffffU ? 0 : 32; +#if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM) + unsigned long r; + _BitScanForward64 (&r, x); + return (int)r; +#else + int shift = x & 0xffffffff ? 0 : 32; return ecb_ctz32 (x >> shift) + shift; +#endif } ecb_function_ ecb_const int ecb_popcount32 (uint32_t x); @@ -966,6 +990,11 @@ typedef int ecb_bool; ecb_function_ ecb_const int ecb_ld32 (uint32_t x); ecb_function_ ecb_const int ecb_ld32 (uint32_t x) { +#if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM) + unsigned long r; + _BitScanReverse (&r, x); + return (int)r; +#else int r = 0; if (x >> 16) { x >>= 16; r += 16; } @@ -975,16 +1004,23 @@ typedef int ecb_bool; if (x >> 1) { r += 1; } return r; +#endif } ecb_function_ ecb_const int ecb_ld64 (uint64_t x); ecb_function_ ecb_const int ecb_ld64 (uint64_t x) { +#if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM) + unsigned long r; + _BitScanReverse64 (&r, x); + return (int)r; +#else int r = 0; if (x >> 32) { x >>= 32; r += 32; } return r + ecb_ld32 (x); +#endif } #endif @@ -1097,8 +1133,8 @@ ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { retu /* try to tell the compiler that some condition is definitely true */ #define ecb_assume(cond) if (!(cond)) ecb_unreachable (); else 0 -ecb_inline ecb_const unsigned char ecb_byteorder_helper (void); -ecb_inline ecb_const unsigned char +ecb_inline ecb_const uint32_t ecb_byteorder_helper (void); +ecb_inline ecb_const uint32_t ecb_byteorder_helper (void) { /* the union code still generates code under pressure in gcc, */ @@ -1107,26 +1143,28 @@ ecb_byteorder_helper (void) /* the reason why we have this horrible preprocessor mess */ /* is to avoid it in all cases, at least on common architectures */ /* or when using a recent enough gcc version (>= 4.6) */ -#if ((__i386 || __i386__) && !__VOS__) || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64 - return 0x44; -#elif __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - return 0x44; -#elif __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - return 0x11; +#if (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \ + || ((__i386 || __i386__ || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64) && !__VOS__) + #define ECB_LITTLE_ENDIAN 1 + return 0x44332211; +#elif (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) \ + || ((__AARCH64EB__ || __MIPSEB__ || __ARMEB__) && !__VOS__) + #define ECB_BIG_ENDIAN 1 + return 0x11223344; #else union { - uint32_t i; - uint8_t c; - } u = { 0x11223344 }; - return u.c; + uint8_t c[4]; + uint32_t u; + } u = { 0x11, 0x22, 0x33, 0x44 }; + return u.u; #endif } ecb_inline ecb_const ecb_bool ecb_big_endian (void); -ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11; } +ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11223344; } ecb_inline ecb_const ecb_bool ecb_little_endian (void); -ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44; } +ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44332211; } #if ECB_GCC_VERSION(3,0) || ECB_C99 #define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0)) @@ -1161,6 +1199,102 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he #define ecb_array_length(name) (sizeof (name) / sizeof (name [0])) #endif +ecb_function_ ecb_const uint32_t ecb_binary16_to_binary32 (uint32_t x); +ecb_function_ ecb_const uint32_t +ecb_binary16_to_binary32 (uint32_t x) +{ + unsigned int s = (x & 0x8000) << (31 - 15); + int e = (x >> 10) & 0x001f; + unsigned int m = x & 0x03ff; + + if (ecb_expect_false (e == 31)) + /* infinity or NaN */ + e = 255 - (127 - 15); + else if (ecb_expect_false (!e)) + { + if (ecb_expect_true (!m)) + /* zero, handled by code below by forcing e to 0 */ + e = 0 - (127 - 15); + else + { + /* subnormal, renormalise */ + unsigned int s = 10 - ecb_ld32 (m); + + m = (m << s) & 0x3ff; /* mask implicit bit */ + e -= s - 1; + } + } + + /* e and m now are normalised, or zero, (or inf or nan) */ + e += 127 - 15; + + return s | (e << 23) | (m << (23 - 10)); +} + +ecb_function_ ecb_const uint16_t ecb_binary32_to_binary16 (uint32_t x); +ecb_function_ ecb_const uint16_t +ecb_binary32_to_binary16 (uint32_t x) +{ + unsigned int s = (x >> 16) & 0x00008000; /* sign bit, the easy part */ + unsigned int e = ((x >> 23) & 0x000000ff) - (127 - 15); /* the desired exponent */ + unsigned int m = x & 0x007fffff; + + x &= 0x7fffffff; + + /* if it's within range of binary16 normals, use fast path */ + if (ecb_expect_true (0x38800000 <= x && x <= 0x477fefff)) + { + /* mantissa round-to-even */ + m += 0x00000fff + ((m >> (23 - 10)) & 1); + + /* handle overflow */ + if (ecb_expect_false (m >= 0x00800000)) + { + m >>= 1; + e += 1; + } + + return s | (e << 10) | (m >> (23 - 10)); + } + + /* handle large numbers and infinity */ + if (ecb_expect_true (0x477fefff < x && x <= 0x7f800000)) + return s | 0x7c00; + + /* handle zero, subnormals and small numbers */ + if (ecb_expect_true (x < 0x38800000)) + { + /* zero */ + if (ecb_expect_true (!x)) + return s; + + /* handle subnormals */ + + /* too small, will be zero */ + if (e < (14 - 24)) /* might not be sharp, but is good enough */ + return s; + + m |= 0x00800000; /* make implicit bit explicit */ + + /* very tricky - we need to round to the nearest e (+10) bit value */ + { + unsigned int bits = 14 - e; + unsigned int half = (1 << (bits - 1)) - 1; + unsigned int even = (m >> bits) & 1; + + /* if this overflows, we will end up with a normalised number */ + m = (m + half + even) >> bits; + } + + return s | m; + } + + /* handle NaNs, preserve leftmost nan bits, but make sure we don't turn them into infinities */ + m >>= 13; + + return s | 0x7c00 | m | !m; +} + /*******************************************************************************/ /* floating point stuff, can be disabled by defining ECB_NO_LIBM */ @@ -1212,23 +1346,6 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he #define ecb_frexpf(x,e) (float) frexp ((double) (x), (e)) #endif - /* converts an ieee half/binary16 to a float */ - ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x); - ecb_function_ ecb_const float - ecb_binary16_to_float (uint16_t x) - { - int e = (x >> 10) & 0x1f; - int m = x & 0x3ff; - float r; - - if (!e ) r = ecb_ldexpf (m , -24); - else if (e != 31) r = ecb_ldexpf (m + 0x400, e - 25); - else if (m ) r = ECB_NAN; - else r = ECB_INFINITY; - - return x & 0x8000 ? -r : r; - } - /* convert a float to ieee single/binary32 */ ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x); ecb_function_ ecb_const uint32_t @@ -1369,6 +1486,22 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he return r; } + /* convert a float to ieee half/binary16 */ + ecb_function_ ecb_const uint16_t ecb_float_to_binary16 (float x); + ecb_function_ ecb_const uint16_t + ecb_float_to_binary16 (float x) + { + return ecb_binary32_to_binary16 (ecb_float_to_binary32 (x)); + } + + /* convert an ieee half/binary16 to float */ + ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x); + ecb_function_ ecb_const float + ecb_binary16_to_float (uint16_t x) + { + return ecb_binary32_to_float (ecb_binary16_to_binary32 (x)); + } + #endif #endif @@ -1401,7 +1534,7 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he #if EV_FEATURE_CODE # define inline_speed ecb_inline #else -# define inline_speed static noinline +# define inline_speed noinline static #endif #define NUMPRI (EV_MAXPRI - EV_MINPRI + 1) @@ -1458,7 +1591,8 @@ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? #include /* a floor() replacement function, should be independent of ev_tstamp type */ -static ev_tstamp noinline +noinline +static ev_tstamp ev_floor (ev_tstamp v) { /* the choice of shift factor is not terribly important */ @@ -1500,7 +1634,8 @@ ev_floor (ev_tstamp v) # include #endif -static unsigned int noinline ecb_cold +noinline ecb_cold +static unsigned int ev_linux_version (void) { #ifdef __linux @@ -1539,7 +1674,8 @@ ev_linux_version (void) /*****************************************************************************/ #if EV_AVOID_STDIO -static void noinline ecb_cold +noinline ecb_cold +static void ev_printerr (const char *msg) { write (STDERR_FILENO, msg, strlen (msg)); @@ -1548,13 +1684,15 @@ ev_printerr (const char *msg) static void (*syserr_cb)(const char *msg) EV_THROW; -void ecb_cold +ecb_cold +void ev_set_syserr_cb (void (*cb)(const char *msg) EV_THROW) EV_THROW { syserr_cb = cb; } -static void noinline ecb_cold +noinline ecb_cold +static void ev_syserr (const char *msg) { if (!msg) @@ -1595,7 +1733,8 @@ ev_realloc_emul (void *ptr, long size) EV_THROW static void *(*alloc)(void *ptr, long size) EV_THROW = ev_realloc_emul; -void ecb_cold +ecb_cold +void ev_set_allocator (void *(*cb)(void *ptr, long size) EV_THROW) EV_THROW { alloc = cb; @@ -1814,7 +1953,8 @@ array_nextsize (int elem, int cur, int cnt) return ncur; } -static void * noinline ecb_cold +noinline ecb_cold +static void * array_realloc (int elem, void *base, int *cur, int cnt) { *cur = array_nextsize (elem, *cur, cnt); @@ -1827,7 +1967,7 @@ array_realloc (int elem, void *base, int *cur, int cnt) #define array_needsize(type,base,cur,cnt,init) \ if (expect_false ((cnt) > (cur))) \ { \ - int ecb_unused ocur_ = (cur); \ + ecb_unused int ocur_ = (cur); \ (base) = (type *)array_realloc \ (sizeof (type), (base), &(cur), (cnt)); \ init ((base) + (ocur_), (cur) - ocur_); \ @@ -1849,12 +1989,14 @@ array_realloc (int elem, void *base, int *cur, int cnt) /*****************************************************************************/ /* dummy callback for pending events */ -static void noinline +noinline +static void pendingcb (EV_P_ ev_prepare *w, int revents) { } -void noinline +noinline +void ev_feed_event (EV_P_ void *w, int revents) EV_THROW { W w_ = (W)w; @@ -1994,7 +2136,8 @@ fd_reify (EV_P) } /* something about the given fd changed */ -inline_size void +inline_size +void fd_change (EV_P_ int fd, int flags) { unsigned char reify = anfds [fd].reify; @@ -2009,7 +2152,7 @@ fd_change (EV_P_ int fd, int flags) } /* the given fd is invalid/unusable, so make sure it doesn't hurt us anymore */ -inline_speed void ecb_cold +inline_speed ecb_cold void fd_kill (EV_P_ int fd) { ev_io *w; @@ -2022,7 +2165,7 @@ fd_kill (EV_P_ int fd) } /* check whether the given fd is actually valid, for error recovery */ -inline_size int ecb_cold +inline_size ecb_cold int fd_valid (int fd) { #ifdef _WIN32 @@ -2033,7 +2176,8 @@ fd_valid (int fd) } /* called on EBADF to verify fds */ -static void noinline ecb_cold +noinline ecb_cold +static void fd_ebadf (EV_P) { int fd; @@ -2045,7 +2189,8 @@ fd_ebadf (EV_P) } /* called on ENOMEM in select/poll to kill some fds and retry */ -static void noinline ecb_cold +noinline ecb_cold +static void fd_enomem (EV_P) { int fd; @@ -2059,7 +2204,8 @@ fd_enomem (EV_P) } /* usually called after fork if backend needs to re-arm all fds from scratch */ -static void noinline +noinline +static void fd_rearm_all (EV_P) { int fd; @@ -2250,7 +2396,8 @@ static ANSIG signals [EV_NSIG - 1]; #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE -static void noinline ecb_cold +noinline ecb_cold +static void evpipe_init (EV_P) { if (!ev_is_active (&pipe_w)) @@ -2438,7 +2585,8 @@ ev_sighandler (int signum) ev_feed_signal (signum); } -void noinline +noinline +void ev_feed_signal_event (EV_P_ int signum) EV_THROW { WL w; @@ -2565,20 +2713,20 @@ childcb (EV_P_ ev_signal *sw, int revents) # include "ev_select.c" #endif -int ecb_cold +ecb_cold int ev_version_major (void) EV_THROW { return EV_VERSION_MAJOR; } -int ecb_cold +ecb_cold int ev_version_minor (void) EV_THROW { return EV_VERSION_MINOR; } /* return true if we are running with elevated privileges and should ignore env variables */ -int inline_size ecb_cold +inline_size ecb_cold int enable_secure (void) { #ifdef _WIN32 @@ -2589,7 +2737,8 @@ enable_secure (void) #endif } -unsigned int ecb_cold +ecb_cold +unsigned int ev_supported_backends (void) EV_THROW { unsigned int flags = 0; @@ -2603,7 +2752,8 @@ ev_supported_backends (void) EV_THROW return flags; } -unsigned int ecb_cold +ecb_cold +unsigned int ev_recommended_backends (void) EV_THROW { unsigned int flags = ev_supported_backends (); @@ -2625,7 +2775,8 @@ ev_recommended_backends (void) EV_THROW return flags; } -unsigned int ecb_cold +ecb_cold +unsigned int ev_embeddable_backends (void) EV_THROW { int flags = EVBACKEND_EPOLL | EVBACKEND_KQUEUE | EVBACKEND_PORT; @@ -2695,7 +2846,8 @@ ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_THROW, void (*acquire)(EV #endif /* initialise a loop structure, must be zero-initialised */ -static void noinline ecb_cold +noinline ecb_cold +static void loop_init (EV_P_ unsigned int flags) EV_THROW { if (!backend) @@ -2792,7 +2944,8 @@ loop_init (EV_P_ unsigned int flags) EV_THROW } /* free up a loop structure */ -void ecb_cold +ecb_cold +void ev_loop_destroy (EV_P) { int i; @@ -2923,7 +3076,7 @@ loop_fork (EV_P) #endif #if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE - if (ev_is_active (&pipe_w)) + if (ev_is_active (&pipe_w) && postfork != 2) { /* pipe_write_wanted must be false now, so modifying fd vars should be safe */ @@ -2944,7 +3097,8 @@ loop_fork (EV_P) #if EV_MULTIPLICITY -struct ev_loop * ecb_cold +ecb_cold +struct ev_loop * ev_loop_new (unsigned int flags) EV_THROW { EV_P = (struct ev_loop *)ev_malloc (sizeof (struct ev_loop)); @@ -2962,7 +3116,8 @@ ev_loop_new (unsigned int flags) EV_THROW #endif /* multiplicity */ #if EV_VERIFY -static void noinline ecb_cold +noinline ecb_cold +static void verify_watcher (EV_P_ W w) { assert (("libev: watcher has invalid priority", ABSPRI (w) >= 0 && ABSPRI (w) < NUMPRI)); @@ -2971,7 +3126,8 @@ verify_watcher (EV_P_ W w) assert (("libev: pending watcher not on pending queue", pendings [ABSPRI (w)][w->pending - 1].w == w)); } -static void noinline ecb_cold +noinline ecb_cold +static void verify_heap (EV_P_ ANHE *heap, int N) { int i; @@ -2986,7 +3142,8 @@ verify_heap (EV_P_ ANHE *heap, int N) } } -static void noinline ecb_cold +noinline ecb_cold +static void array_verify (EV_P_ W *ws, int cnt) { while (cnt--) @@ -3085,7 +3242,8 @@ ev_verify (EV_P) EV_THROW #endif #if EV_MULTIPLICITY -struct ev_loop * ecb_cold +ecb_cold +struct ev_loop * #else int #endif @@ -3143,7 +3301,8 @@ ev_pending_count (EV_P) EV_THROW return count; } -void noinline +noinline +void ev_invoke_pending (EV_P) { pendingpri = NUMPRI; @@ -3228,7 +3387,8 @@ timers_reify (EV_P) #if EV_PERIODIC_ENABLE -static void noinline +noinline +static void periodic_recalc (EV_P_ ev_periodic *w) { ev_tstamp interval = w->interval > MIN_INTERVAL ? w->interval : MIN_INTERVAL; @@ -3296,7 +3456,8 @@ periodics_reify (EV_P) /* simply recalculate all periodics */ /* TODO: maybe ensure that at least one event happens when jumping forward? */ -static void noinline ecb_cold +noinline ecb_cold +static void periodics_reschedule (EV_P) { int i; @@ -3319,7 +3480,8 @@ periodics_reschedule (EV_P) #endif /* adjust all timers by a given offset */ -static void noinline ecb_cold +noinline ecb_cold +static void timers_reschedule (EV_P_ ev_tstamp adjust) { int i; @@ -3784,7 +3946,8 @@ ev_stop (EV_P_ W w) /*****************************************************************************/ -void noinline +noinline +void ev_io_start (EV_P_ ev_io *w) EV_THROW { int fd = w->fd; @@ -3810,7 +3973,8 @@ ev_io_start (EV_P_ ev_io *w) EV_THROW EV_FREQUENT_CHECK; } -void noinline +noinline +void ev_io_stop (EV_P_ ev_io *w) EV_THROW { clear_pending (EV_A_ (W)w); @@ -3829,7 +3993,8 @@ ev_io_stop (EV_P_ ev_io *w) EV_THROW EV_FREQUENT_CHECK; } -void noinline +noinline +void ev_timer_start (EV_P_ ev_timer *w) EV_THROW { if (expect_false (ev_is_active (w))) @@ -3853,7 +4018,8 @@ ev_timer_start (EV_P_ ev_timer *w) EV_THROW /*assert (("libev: internal timer heap corruption", timers [ev_active (w)] == (WT)w));*/ } -void noinline +noinline +void ev_timer_stop (EV_P_ ev_timer *w) EV_THROW { clear_pending (EV_A_ (W)w); @@ -3883,7 +4049,8 @@ ev_timer_stop (EV_P_ ev_timer *w) EV_THROW EV_FREQUENT_CHECK; } -void noinline +noinline +void ev_timer_again (EV_P_ ev_timer *w) EV_THROW { EV_FREQUENT_CHECK; @@ -3917,7 +4084,8 @@ ev_timer_remaining (EV_P_ ev_timer *w) EV_THROW } #if EV_PERIODIC_ENABLE -void noinline +noinline +void ev_periodic_start (EV_P_ ev_periodic *w) EV_THROW { if (expect_false (ev_is_active (w))) @@ -3947,7 +4115,8 @@ ev_periodic_start (EV_P_ ev_periodic *w) EV_THROW /*assert (("libev: internal periodic heap corruption", ANHE_w (periodics [ev_active (w)]) == (WT)w));*/ } -void noinline +noinline +void ev_periodic_stop (EV_P_ ev_periodic *w) EV_THROW { clear_pending (EV_A_ (W)w); @@ -3975,7 +4144,8 @@ ev_periodic_stop (EV_P_ ev_periodic *w) EV_THROW EV_FREQUENT_CHECK; } -void noinline +noinline +void ev_periodic_again (EV_P_ ev_periodic *w) EV_THROW { /* TODO: use adjustheap and recalculation */ @@ -3990,7 +4160,8 @@ ev_periodic_again (EV_P_ ev_periodic *w) EV_THROW #if EV_SIGNAL_ENABLE -void noinline +noinline +void ev_signal_start (EV_P_ ev_signal *w) EV_THROW { if (expect_false (ev_is_active (w))) @@ -4072,7 +4243,8 @@ ev_signal_start (EV_P_ ev_signal *w) EV_THROW EV_FREQUENT_CHECK; } -void noinline +noinline +void ev_signal_stop (EV_P_ ev_signal *w) EV_THROW { clear_pending (EV_A_ (W)w); @@ -4158,14 +4330,15 @@ ev_child_stop (EV_P_ ev_child *w) EV_THROW #define NFS_STAT_INTERVAL 30.1074891 /* for filesystems potentially failing inotify */ #define MIN_STAT_INTERVAL 0.1074891 -static void noinline stat_timer_cb (EV_P_ ev_timer *w_, int revents); +noinline static void stat_timer_cb (EV_P_ ev_timer *w_, int revents); #if EV_USE_INOTIFY /* the * 2 is to allow for alignment padding, which for some reason is >> 8 */ # define EV_INOTIFY_BUFSIZE (sizeof (struct inotify_event) * 2 + NAME_MAX) -static void noinline +noinline +static void infy_add (EV_P_ ev_stat *w) { w->wd = inotify_add_watch (fs_fd, w->path, @@ -4239,7 +4412,8 @@ infy_add (EV_P_ ev_stat *w) if (ev_is_active (&w->timer)) ev_unref (EV_A); } -static void noinline +noinline +static void infy_del (EV_P_ ev_stat *w) { int slot; @@ -4256,7 +4430,8 @@ infy_del (EV_P_ ev_stat *w) inotify_rm_watch (fs_fd, wd); } -static void noinline +noinline +static void infy_wd (EV_P_ int slot, int wd, struct inotify_event *ev) { if (slot < 0) @@ -4302,7 +4477,8 @@ infy_cb (EV_P_ ev_io *w, int revents) } } -inline_size void ecb_cold +inline_size ecb_cold +void ev_check_2625 (EV_P) { /* kernels < 2.6.25 are borked @@ -4410,7 +4586,8 @@ ev_stat_stat (EV_P_ ev_stat *w) EV_THROW w->attr.st_nlink = 1; } -static void noinline +noinline +static void stat_timer_cb (EV_P_ ev_timer *w_, int revents) { ev_stat *w = (ev_stat *)(((char *)w_) - offsetof (ev_stat, timer)); @@ -4630,7 +4807,8 @@ ev_check_stop (EV_P_ ev_check *w) EV_THROW #endif #if EV_EMBED_ENABLE -void noinline +noinline +void ev_embed_sweep (EV_P_ ev_embed *w) EV_THROW { ev_run (w->other, EVRUN_NOWAIT); @@ -4937,7 +5115,8 @@ ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, vo /*****************************************************************************/ #if EV_WALK_ENABLE -void ecb_cold +ecb_cold +void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) EV_THROW { int i, j; @@ -5053,3 +5232,4 @@ ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) EV_THROW #if EV_MULTIPLICITY #include "ev_wrap.h" #endif + diff --git a/ext/libev/ev.h b/ext/libev/ev.h index 928b4af..db93777 100644 --- a/ext/libev/ev.h +++ b/ext/libev/ev.h @@ -211,7 +211,7 @@ struct ev_loop; /*****************************************************************************/ #define EV_VERSION_MAJOR 4 -#define EV_VERSION_MINOR 20 +#define EV_VERSION_MINOR 24 /* eventmask, revents, events... */ enum { @@ -515,10 +515,10 @@ enum { /* method bits to be ored together */ enum { - EVBACKEND_SELECT = 0x00000001U, /* about anywhere */ - EVBACKEND_POLL = 0x00000002U, /* !win */ + EVBACKEND_SELECT = 0x00000001U, /* available just about anywhere */ + EVBACKEND_POLL = 0x00000002U, /* !win, !aix, broken on osx */ EVBACKEND_EPOLL = 0x00000004U, /* linux */ - EVBACKEND_KQUEUE = 0x00000008U, /* bsd */ + EVBACKEND_KQUEUE = 0x00000008U, /* bsd, broken on osx */ EVBACKEND_DEVPOLL = 0x00000010U, /* solaris 8 */ /* NYI */ EVBACKEND_PORT = 0x00000020U, /* solaris 10 */ EVBACKEND_ALL = 0x0000003FU, /* all known backends */ @@ -851,3 +851,4 @@ EV_API_DECL void ev_async_send (EV_P_ ev_async *w) EV_THROW; EV_CPP(}) #endif + diff --git a/ext/libev/ev_epoll.c b/ext/libev/ev_epoll.c index 7472b60..df118a6 100644 --- a/ext/libev/ev_epoll.c +++ b/ext/libev/ev_epoll.c @@ -179,7 +179,7 @@ epoll_poll (EV_P_ ev_tstamp timeout) if (expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32))) { /* recreate kernel state */ - postfork = 1; + postfork |= 2; continue; } @@ -203,7 +203,7 @@ epoll_poll (EV_P_ ev_tstamp timeout) /* which is fortunately easy to do for us. */ if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev)) { - postfork = 1; /* an error occurred, recreate kernel state */ + postfork |= 2; /* an error occurred, recreate kernel state */ continue; } } @@ -235,7 +235,8 @@ epoll_poll (EV_P_ ev_tstamp timeout) } } -int inline_size +inline_size +int epoll_init (EV_P_ int flags) { #ifdef EPOLL_CLOEXEC @@ -260,14 +261,16 @@ epoll_init (EV_P_ int flags) return EVBACKEND_EPOLL; } -void inline_size +inline_size +void epoll_destroy (EV_P) { ev_free (epoll_events); array_free (epoll_eperm, EMPTY); } -void inline_size +inline_size +void epoll_fork (EV_P) { close (backend_fd); diff --git a/ext/libev/ev_kqueue.c b/ext/libev/ev_kqueue.c index 27def23..0c05ab9 100644 --- a/ext/libev/ev_kqueue.c +++ b/ext/libev/ev_kqueue.c @@ -43,7 +43,8 @@ #include #include -void inline_speed +inline_speed +void kqueue_change (EV_P_ int fd, int filter, int flags, int fflags) { ++kqueue_changecnt; @@ -152,7 +153,8 @@ kqueue_poll (EV_P_ ev_tstamp timeout) } } -int inline_size +inline_size +int kqueue_init (EV_P_ int flags) { /* initialize the kernel queue */ @@ -176,14 +178,16 @@ kqueue_init (EV_P_ int flags) return EVBACKEND_KQUEUE; } -void inline_size +inline_size +void kqueue_destroy (EV_P) { ev_free (kqueue_events); ev_free (kqueue_changes); } -void inline_size +inline_size +void kqueue_fork (EV_P) { /* some BSD kernels don't just destroy the kqueue itself, diff --git a/ext/libev/ev_poll.c b/ext/libev/ev_poll.c index 4832351..bd742b0 100644 --- a/ext/libev/ev_poll.c +++ b/ext/libev/ev_poll.c @@ -39,7 +39,8 @@ #include -void inline_size +inline_size +void pollidx_init (int *base, int count) { /* consider using memset (.., -1, ...), which is practically guaranteed @@ -126,7 +127,8 @@ poll_poll (EV_P_ ev_tstamp timeout) } } -int inline_size +inline_size +int poll_init (EV_P_ int flags) { backend_mintime = 1e-3; @@ -139,7 +141,8 @@ poll_init (EV_P_ int flags) return EVBACKEND_POLL; } -void inline_size +inline_size +void poll_destroy (EV_P) { ev_free (pollidxs); diff --git a/ext/libev/ev_port.c b/ext/libev/ev_port.c index 9368501..c7b0b70 100644 --- a/ext/libev/ev_port.c +++ b/ext/libev/ev_port.c @@ -55,7 +55,8 @@ #include #include -void inline_speed +inline_speed +void port_associate_and_check (EV_P_ int fd, int ev) { if (0 > @@ -136,7 +137,8 @@ port_poll (EV_P_ ev_tstamp timeout) } } -int inline_size +inline_size +int port_init (EV_P_ int flags) { /* Initialize the kernel queue */ @@ -163,13 +165,15 @@ port_init (EV_P_ int flags) return EVBACKEND_PORT; } -void inline_size +inline_size +void port_destroy (EV_P) { ev_free (port_events); } -void inline_size +inline_size +void port_fork (EV_P) { close (backend_fd); diff --git a/ext/libev/ev_select.c b/ext/libev/ev_select.c index 7050778..28cb1bf 100644 --- a/ext/libev/ev_select.c +++ b/ext/libev/ev_select.c @@ -319,7 +319,8 @@ select_poll (EV_P_ ev_tstamp timeout) #endif } -int inline_size +inline_size +int select_init (EV_P_ int flags) { backend_mintime = 1e-6; @@ -348,7 +349,8 @@ select_init (EV_P_ int flags) return EVBACKEND_SELECT; } -void inline_size +inline_size +void select_destroy (EV_P) { ev_free (vec_ri); diff --git a/ext/libev/ev_win32.c b/ext/libev/ev_win32.c index d65634c..fd67135 100644 --- a/ext/libev/ev_win32.c +++ b/ext/libev/ev_win32.c @@ -39,9 +39,6 @@ #ifdef _WIN32 -/* timeb.h is actually xsi legacy functionality */ -#include - /* note: the comment below could not be substantiated, but what would I care */ /* MSDN says this is required to handle SIGFPE */ /* my wild guess would be that using something floating-pointy is required */ @@ -91,6 +88,8 @@ ev_pipe (int filedes [2]) if (connect (sock [0], (struct sockaddr *)&addr, addr_size)) goto fail; + /* TODO: returns INVALID_SOCKET on winsock accept, not < 0. fix it */ + /* when convenient, probably by just removing error checking altogether? */ if ((sock [1] = accept (listener, 0, 0)) < 0) goto fail; diff --git a/ext/libev/ruby_gil.patch b/ext/libev/ruby_gil.patch deleted file mode 100644 index 9adaa2e..0000000 --- a/ext/libev/ruby_gil.patch +++ /dev/null @@ -1,97 +0,0 @@ -diff --git a/ext/libev/ev.c b/ext/libev/ev.c -index e5bd5ab..10f6ff2 100644 ---- a/ext/libev/ev.c -+++ b/ext/libev/ev.c -@@ -37,6 +37,10 @@ - * either the BSD or the GPL. - */ - -+/* ########## COOLIO PATCHERY HO! ########## */ -+#include "ruby.h" -+/* ######################################## */ -+ - /* this big block deduces configuration from config.h */ - #ifndef EV_STANDALONE - # ifdef EV_CONFIG_H -@@ -3237,9 +3241,27 @@ time_update (EV_P_ ev_tstamp max_block) - } - } - -+/* ########## COOLIO PATCHERY HO! ########## */ -+#if defined(HAVE_RB_THREAD_BLOCKING_REGION) -+static -+VALUE ev_backend_poll(void **args) -+{ -+ struct ev_loop *loop = (struct ev_loop *)args[0]; -+ ev_tstamp waittime = *(ev_tstamp *)args[1]; -+ backend_poll (EV_A_ waittime); -+} -+#endif -+/* ######################################## */ -+ - int - ev_run (EV_P_ int flags) - { -+/* ########## COOLIO PATCHERY HO! ########## */ -+#if defined(HAVE_RB_THREAD_BLOCKING_REGION) -+ void *poll_args[2]; -+#endif -+/* ######################################## */ -+ - #if EV_FEATURE_API - ++loop_depth; - #endif -@@ -3357,7 +3379,53 @@ ev_run (EV_P_ int flags) - ++loop_count; - #endif - assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */ -+ -+/* -+########################## COOLIO PATCHERY HO! ########################## -+ -+The original patch file is made by Tony Arcieri. -+https://github.com/celluloid/nio4r/blob/680143345726c5a64bb22376ca8fc3c6857019ae/ext/libev/ruby_gil.patch. -+ -+According to the grandwizards of Ruby, locking and unlocking of the global -+interpreter lock are apparently too powerful a concept for a mere mortal to -+wield (although redefining what + and - do to numbers is totally cool). -+And so it came to pass that the only acceptable way to release the global -+interpreter lock is through a convoluted callback system that thakes a -+function pointer. While the grandwizard of libev foresaw this sort of scenario, -+he too attempted to place an API with callbacks on it, one that runs before -+the system call, and one that runs immediately after. -+ -+And so it came to pass that trying to wrap everything up in callbacks created -+two incompatible APIs, Ruby's which releases the global interpreter lock and -+reacquires it when the callback returns, and libev's, which wants two -+callbacks, one which runs before the polling operation starts, and one which -+runs after it finishes. -+ -+These two systems are incompatible as they both want to use callbacks to -+solve the same problem, however libev wants to use before/after callbacks, -+and Ruby wants to use an "around" callback. This presents a significant -+problem as these two patterns of callbacks are diametrical opposites of each -+other and thus cannot be composed. -+ -+And thus we are left with no choice but to patch the internals of libev in -+order to release a mutex at just the precise moment. -+ -+Let this be a lesson to the all: CALLBACKS FUCKING BLOW -+ -+####################################################################### -+*/ -+ -+#if defined(HAVE_RB_THREAD_BLOCKING_REGION) -+ poll_args[0] = (void *)loop; -+ poll_args[1] = (void *)&waittime; -+ rb_thread_blocking_region(ev_backend_poll, (void *)&poll_args, RUBY_UBF_IO, 0); -+#else - backend_poll (EV_A_ waittime); -+#endif -+/* -+############################# END PATCHERY ############################ -+*/ -+ - assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */ - - pipe_write_wanted = 0; /* just an optimisation, no fence needed */ diff --git a/libev_ruby_gil.diff b/libev_ruby_gil.diff new file mode 100644 index 0000000..f18eb45 --- /dev/null +++ b/libev_ruby_gil.diff @@ -0,0 +1,175 @@ +diff --git a/ext/libev/ev.c b/ext/libev/ev.c +index 39b9faf..dae87f1 100644 +--- a/ext/libev/ev.c ++++ b/ext/libev/ev.c +@@ -37,6 +37,10 @@ + * either the BSD or the GPL. + */ + ++/* ########## COOLIO PATCHERY HO! ########## */ ++#include "ruby.h" ++/* ######################################## */ ++ + /* this big block deduces configuration from config.h */ + #ifndef EV_STANDALONE + # ifdef EV_CONFIG_H +@@ -107,7 +111,7 @@ + # undef EV_USE_POLL + # define EV_USE_POLL 0 + # endif +- ++ + # if HAVE_EPOLL_CTL && HAVE_SYS_EPOLL_H + # ifndef EV_USE_EPOLL + # define EV_USE_EPOLL EV_FEATURE_BACKENDS +@@ -116,7 +120,7 @@ + # undef EV_USE_EPOLL + # define EV_USE_EPOLL 0 + # endif +- ++ + # if HAVE_KQUEUE && HAVE_SYS_EVENT_H + # ifndef EV_USE_KQUEUE + # define EV_USE_KQUEUE EV_FEATURE_BACKENDS +@@ -125,7 +129,7 @@ + # undef EV_USE_KQUEUE + # define EV_USE_KQUEUE 0 + # endif +- ++ + # if HAVE_PORT_H && HAVE_PORT_CREATE + # ifndef EV_USE_PORT + # define EV_USE_PORT EV_FEATURE_BACKENDS +@@ -161,7 +165,7 @@ + # undef EV_USE_EVENTFD + # define EV_USE_EVENTFD 0 + # endif +- ++ + #endif + + #include +@@ -2174,7 +2178,7 @@ downheap (ANHE *heap, int N, int k) + + heap [k] = heap [c]; + ev_active (ANHE_w (heap [k])) = k; +- ++ + k = c; + } + +@@ -2594,7 +2598,7 @@ ev_supported_backends (void) EV_THROW + if (EV_USE_EPOLL ) flags |= EVBACKEND_EPOLL; + if (EV_USE_POLL ) flags |= EVBACKEND_POLL; + if (EV_USE_SELECT) flags |= EVBACKEND_SELECT; +- ++ + return flags; + } + +@@ -3398,9 +3402,33 @@ time_update (EV_P_ ev_tstamp max_block) + } + } + ++/* ########## COOLIO PATCHERY HO! ########## */ ++#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) ++struct ev_poll_args { ++ struct ev_loop *loop; ++ ev_tstamp waittime; ++}; ++ ++static ++VALUE ev_backend_poll(void *ptr) ++{ ++ struct ev_poll_args *args = (struct ev_poll_args *)ptr; ++ struct ev_loop *loop = args->loop; ++ backend_poll (EV_A_ args->waittime); ++ return Qnil; ++} ++#endif ++/* ######################################## */ ++ + int + ev_run (EV_P_ int flags) + { ++/* ########## COOLIO PATCHERY HO! ########## */ ++#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) ++ struct ev_poll_args poll_args; ++#endif ++/* ######################################## */ ++ + #if EV_FEATURE_API + ++loop_depth; + #endif +@@ -3518,7 +3546,70 @@ ev_run (EV_P_ int flags) + ++loop_count; + #endif + assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */ +- backend_poll (EV_A_ waittime); ++ ++/* ++########################## COOLIO PATCHERY HO! ########################## ++ ++According to the grandwizards of Ruby, locking and unlocking of the global ++interpreter lock are apparently too powerful a concept for a mere mortal to ++wield (although redefining what + and - do to numbers is totally cool). ++And so it came to pass that the only acceptable way to release the global ++interpreter lock is through a convoluted callback system that thakes a ++function pointer. While the grandwizard of libev foresaw this sort of scenario, ++he too attempted to place an API with callbacks on it, one that runs before ++the system call, and one that runs immediately after. ++ ++And so it came to pass that trying to wrap everything up in callbacks created ++two incompatible APIs, Ruby's which releases the global interpreter lock and ++reacquires it when the callback returns, and libev's, which wants two ++callbacks, one which runs before the polling operation starts, and one which ++runs after it finishes. ++ ++These two systems are incompatible as they both want to use callbacks to ++solve the same problem, however libev wants to use before/after callbacks, ++and Ruby wants to use an "around" callback. This presents a significant ++problem as these two patterns of callbacks are diametrical opposites of each ++other and thus cannot be composed. ++ ++And thus we are left with no choice but to patch the internals of libev in ++order to release a mutex at just the precise moment. ++ ++This is a great example of a situation where granular locking and unlocking ++of the GVL is practically required. The goal is to get as close to the ++system call as possible, and to keep the GVL unlocked for the shortest ++amount of time possible. ++ ++Perhaps Ruby could benefit from such an API, e.g: ++ ++rb_thread_unsafe_dangerous_crazy_blocking_region_begin(...); ++rb_thread_unsafe_dangerous_crazy_blocking_region_end(...); ++ ++####################################################################### ++*/ ++ ++/* ++ simulate to rb_thread_call_without_gvl using rb_theread_blocking_region. ++ https://github.com/brianmario/mysql2/blob/master/ext/mysql2/client.h#L8 ++*/ ++ ++#ifndef HAVE_RB_THREAD_CALL_WITHOUT_GVL ++#ifdef HAVE_RB_THREAD_BLOCKING_REGION ++#define rb_thread_call_without_gvl(func, data1, ubf, data2) \ ++ rb_thread_blocking_region((rb_blocking_function_t *)func, data1, ubf, data2) ++#endif ++#endif ++ ++#if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL) ++ poll_args.loop = loop; ++ poll_args.waittime = waittime; ++ rb_thread_call_without_gvl(ev_backend_poll, (void *)&poll_args, RUBY_UBF_IO, 0); ++#else ++ backend_poll (EV_A_ waittime); ++#endif ++/* ++############################# END PATCHERY ############################ ++*/ ++ + assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */ + + pipe_write_wanted = 0; /* just an optimisation, no fence needed */ diff --git a/ext/libev/win_select.patch b/libev_win_select.diff similarity index 78% rename from ext/libev/win_select.patch rename to libev_win_select.diff index 00dbe52..229f171 100644 --- a/ext/libev/win_select.patch +++ b/libev_win_select.diff @@ -1,8 +1,20 @@ +diff --git a/ext/libev/ev.c b/ext/libev/ev.c +index dae87f1..d15f6bd 100644 +--- a/ext/libev/ev.c ++++ b/ext/libev/ev.c +@@ -207,6 +207,7 @@ + #else + # include + # define WIN32_LEAN_AND_MEAN ++# define FD_SETSIZE 1024 + # include + # include + # ifndef EV_SELECT_IS_WINSOCKET diff --git a/ext/libev/ev_select.c b/ext/libev/ev_select.c -index f38d6ca..3a32642 100644 +index f38d6ca..7050778 100644 --- a/ext/libev/ev_select.c +++ b/ext/libev/ev_select.c -@@ -67,6 +67,53 @@ +@@ -67,6 +67,54 @@ #include @@ -45,6 +57,7 @@ index f38d6ca..3a32642 100644 +} while(0) +#define EV_WIN_FD_ZERO(set) (((fd_set *)(set))->fd_count=0) +#define EV_WIN_FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set *)(set)) ++#define EV_WIN_FD_COUNT(set) (((fd_set *)(set))->fd_count) +/* ######################################## */ +#else +#define EV_WIN_FD_CLR FD_CLR @@ -56,7 +69,7 @@ index f38d6ca..3a32642 100644 static void select_modify (EV_P_ int fd, int oev, int nev) { -@@ -91,17 +138,17 @@ select_modify (EV_P_ int fd, int oev, int nev) +@@ -91,17 +139,17 @@ select_modify (EV_P_ int fd, int oev, int nev) if ((oev ^ nev) & EV_READ) #endif if (nev & EV_READ) @@ -78,16 +91,18 @@ index f38d6ca..3a32642 100644 #else -@@ -136,6 +183,8 @@ select_modify (EV_P_ int fd, int oev, int nev) - } - } +@@ -197,8 +245,8 @@ select_poll (EV_P_ ev_tstamp timeout) + { + if (timeout) + { +- unsigned long ms = timeout * 1e3; +- Sleep (ms ? ms : 1); ++ unsigned long ms = (unsigned long)(timeout * 1e3); ++ SleepEx (ms ? ms : 1, TRUE); + } -+#undef socket -+ - static void - select_poll (EV_P_ ev_tstamp timeout) - { -@@ -230,10 +279,10 @@ select_poll (EV_P_ ev_tstamp timeout) + return; +@@ -230,10 +278,10 @@ select_poll (EV_P_ ev_tstamp timeout) int handle = fd; #endif @@ -101,7 +116,7 @@ index f38d6ca..3a32642 100644 #endif if (expect_true (events)) -@@ -279,9 +328,9 @@ select_init (EV_P_ int flags) +@@ -279,9 +327,9 @@ select_init (EV_P_ int flags) backend_poll = select_poll; #if EV_SELECT_USE_FD_SET