nio4r 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/.travis.yml +3 -0
- data/CHANGES.md +6 -0
- data/ext/libev/Changes +10 -0
- data/ext/libev/ev.c +171 -38
- data/ext/libev/ev.h +1 -1
- data/ext/libev/ev_epoll.c +2 -2
- data/ext/libev/ev_win32.c +2 -3
- data/ext/nio4r/monitor.c +38 -2
- data/ext/nio4r/org/nio4r/Nio4r.java +35 -0
- data/ext/nio4r/selector.c +5 -0
- data/lib/nio/monitor.rb +8 -0
- data/lib/nio/selector.rb +3 -4
- data/lib/nio/version.rb +1 -1
- data/spec/nio/monitor_spec.rb +48 -5
- data/spec/nio/selectables/tcp_socket_spec.rb +1 -1
- data/spec/nio/selector_spec.rb +6 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 339fc3cc040e41d266a9f83ab155d903294fcdc5
|
4
|
+
data.tar.gz: 8872185b3bfadc884b36b65ea1a17a2c082d7090
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73083b74bdcb581449b5b0534209fdd9b1c08059ee946eaf9f8155d72605030c127046a7819d4ed325e0bf3e525c4aec81a41c00b55077f9e5b4629dd147d931
|
7
|
+
data.tar.gz: 44eb8368129b34cfb8780b98334ff8a67029d1751fdfc756ee761cb19c975f55a95c5166a251dba88ea7f587a3441f19650dcb13d936d88c60f847bda9c20d1d
|
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
data/ext/libev/Changes
CHANGED
@@ -14,6 +14,16 @@ TODO: embed watchers need updating when fd changes
|
|
14
14
|
TODO: document portability requirements for atomic pointer access
|
15
15
|
TODO: document requirements for function pointers and calling conventions.
|
16
16
|
|
17
|
+
4.22 Sun Dec 20 22:11:50 CET 2015
|
18
|
+
- when epoll detects unremovable fds in the fd set, rebuild
|
19
|
+
only the epoll descriptor, not the signal pipe, to avoid
|
20
|
+
SIGPIPE in ev_async_send. This doesn't solve it on fork,
|
21
|
+
so document what needs to be done in ev_loop_fork
|
22
|
+
(analyzed by Benjamin Mahler).
|
23
|
+
- remove superfluous sys/timeb.h include on win32
|
24
|
+
(analyzed by Jason Madden).
|
25
|
+
- updated libecb.
|
26
|
+
|
17
27
|
4.20 Sat Jun 20 13:01:43 CEST 2015
|
18
28
|
- prefer noexcept over throw () with C++ 11.
|
19
29
|
- update ecb.h due to incompatibilities with c11.
|
data/ext/libev/ev.c
CHANGED
@@ -538,7 +538,7 @@ struct signalfd_siginfo
|
|
538
538
|
#define ECB_H
|
539
539
|
|
540
540
|
/* 16 bits major, 16 bits minor */
|
541
|
-
#define ECB_VERSION
|
541
|
+
#define ECB_VERSION 0x00010005
|
542
542
|
|
543
543
|
#ifdef _WIN32
|
544
544
|
typedef signed char int8_t;
|
@@ -565,7 +565,7 @@ struct signalfd_siginfo
|
|
565
565
|
#endif
|
566
566
|
#else
|
567
567
|
#include <inttypes.h>
|
568
|
-
#if
|
568
|
+
#if (defined INTPTR_MAX ? INTPTR_MAX : ULONG_MAX) > 0xffffffffU
|
569
569
|
#define ECB_PTRSIZE 8
|
570
570
|
#else
|
571
571
|
#define ECB_PTRSIZE 4
|
@@ -653,6 +653,10 @@ struct signalfd_siginfo
|
|
653
653
|
#include <builtins.h>
|
654
654
|
#endif
|
655
655
|
|
656
|
+
#if 1400 <= _MSC_VER
|
657
|
+
#include <intrin.h> /* fence functions _ReadBarrier, also bit search functions _BitScanReverse */
|
658
|
+
#endif
|
659
|
+
|
656
660
|
#ifndef ECB_MEMORY_FENCE
|
657
661
|
#if ECB_GCC_VERSION(2,5) || defined __INTEL_COMPILER || (__llvm__ && __GNUC__) || __SUNPRO_C >= 0x5110 || __SUNPRO_CC >= 0x5110
|
658
662
|
#if __i386 || __i386__
|
@@ -665,15 +669,23 @@ struct signalfd_siginfo
|
|
665
669
|
#define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("")
|
666
670
|
#elif __powerpc__ || __ppc__ || __powerpc64__ || __ppc64__
|
667
671
|
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("sync" : : : "memory")
|
672
|
+
#elif defined __ARM_ARCH_2__ \
|
673
|
+
|| defined __ARM_ARCH_3__ || defined __ARM_ARCH_3M__ \
|
674
|
+
|| defined __ARM_ARCH_4__ || defined __ARM_ARCH_4T__ \
|
675
|
+
|| defined __ARM_ARCH_5__ || defined __ARM_ARCH_5E__ \
|
676
|
+
|| defined __ARM_ARCH_5T__ || defined __ARM_ARCH_5TE__ \
|
677
|
+
|| defined __ARM_ARCH_5TEJ__
|
678
|
+
/* should not need any, unless running old code on newer cpu - arm doesn't support that */
|
668
679
|
#elif defined __ARM_ARCH_6__ || defined __ARM_ARCH_6J__ \
|
669
|
-
|| defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__
|
680
|
+
|| defined __ARM_ARCH_6K__ || defined __ARM_ARCH_6ZK__ \
|
681
|
+
|| defined __ARM_ARCH_6T2__
|
670
682
|
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("mcr p15,0,%0,c7,c10,5" : : "r" (0) : "memory")
|
671
683
|
#elif defined __ARM_ARCH_7__ || defined __ARM_ARCH_7A__ \
|
672
|
-
|| defined
|
684
|
+
|| defined __ARM_ARCH_7R__ || defined __ARM_ARCH_7M__
|
673
685
|
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb" : : : "memory")
|
674
686
|
#elif __aarch64__
|
675
687
|
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("dmb ish" : : : "memory")
|
676
|
-
#elif (__sparc || __sparc__) && !__sparcv8
|
688
|
+
#elif (__sparc || __sparc__) && !(__sparc_v8__ || defined __sparcv8)
|
677
689
|
#define ECB_MEMORY_FENCE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad | #StoreStore | #StoreLoad" : : : "memory")
|
678
690
|
#define ECB_MEMORY_FENCE_ACQUIRE __asm__ __volatile__ ("membar #LoadStore | #LoadLoad" : : : "memory")
|
679
691
|
#define ECB_MEMORY_FENCE_RELEASE __asm__ __volatile__ ("membar #LoadStore | #StoreStore")
|
@@ -921,6 +933,11 @@ typedef int ecb_bool;
|
|
921
933
|
ecb_function_ ecb_const int
|
922
934
|
ecb_ctz32 (uint32_t x)
|
923
935
|
{
|
936
|
+
#if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM)
|
937
|
+
unsigned long r;
|
938
|
+
_BitScanForward (&r, x);
|
939
|
+
return (int)r;
|
940
|
+
#else
|
924
941
|
int r = 0;
|
925
942
|
|
926
943
|
x &= ~x + 1; /* this isolates the lowest bit */
|
@@ -940,14 +957,21 @@ typedef int ecb_bool;
|
|
940
957
|
#endif
|
941
958
|
|
942
959
|
return r;
|
960
|
+
#endif
|
943
961
|
}
|
944
962
|
|
945
963
|
ecb_function_ ecb_const int ecb_ctz64 (uint64_t x);
|
946
964
|
ecb_function_ ecb_const int
|
947
965
|
ecb_ctz64 (uint64_t x)
|
948
966
|
{
|
949
|
-
|
967
|
+
#if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM)
|
968
|
+
unsigned long r;
|
969
|
+
_BitScanForward64 (&r, x);
|
970
|
+
return (int)r;
|
971
|
+
#else
|
972
|
+
int shift = x & 0xffffffff ? 0 : 32;
|
950
973
|
return ecb_ctz32 (x >> shift) + shift;
|
974
|
+
#endif
|
951
975
|
}
|
952
976
|
|
953
977
|
ecb_function_ ecb_const int ecb_popcount32 (uint32_t x);
|
@@ -965,6 +989,11 @@ typedef int ecb_bool;
|
|
965
989
|
ecb_function_ ecb_const int ecb_ld32 (uint32_t x);
|
966
990
|
ecb_function_ ecb_const int ecb_ld32 (uint32_t x)
|
967
991
|
{
|
992
|
+
#if 1400 <= _MSC_VER && (_M_IX86 || _M_X64 || _M_IA64 || _M_ARM)
|
993
|
+
unsigned long r;
|
994
|
+
_BitScanReverse (&r, x);
|
995
|
+
return (int)r;
|
996
|
+
#else
|
968
997
|
int r = 0;
|
969
998
|
|
970
999
|
if (x >> 16) { x >>= 16; r += 16; }
|
@@ -974,16 +1003,23 @@ typedef int ecb_bool;
|
|
974
1003
|
if (x >> 1) { r += 1; }
|
975
1004
|
|
976
1005
|
return r;
|
1006
|
+
#endif
|
977
1007
|
}
|
978
1008
|
|
979
1009
|
ecb_function_ ecb_const int ecb_ld64 (uint64_t x);
|
980
1010
|
ecb_function_ ecb_const int ecb_ld64 (uint64_t x)
|
981
1011
|
{
|
1012
|
+
#if 1400 <= _MSC_VER && (_M_X64 || _M_IA64 || _M_ARM)
|
1013
|
+
unsigned long r;
|
1014
|
+
_BitScanReverse64 (&r, x);
|
1015
|
+
return (int)r;
|
1016
|
+
#else
|
982
1017
|
int r = 0;
|
983
1018
|
|
984
1019
|
if (x >> 32) { x >>= 32; r += 32; }
|
985
1020
|
|
986
1021
|
return r + ecb_ld32 (x);
|
1022
|
+
#endif
|
987
1023
|
}
|
988
1024
|
#endif
|
989
1025
|
|
@@ -1096,8 +1132,8 @@ ecb_inline ecb_const uint64_t ecb_rotr64 (uint64_t x, unsigned int count) { retu
|
|
1096
1132
|
/* try to tell the compiler that some condition is definitely true */
|
1097
1133
|
#define ecb_assume(cond) if (!(cond)) ecb_unreachable (); else 0
|
1098
1134
|
|
1099
|
-
ecb_inline ecb_const
|
1100
|
-
ecb_inline ecb_const
|
1135
|
+
ecb_inline ecb_const uint32_t ecb_byteorder_helper (void);
|
1136
|
+
ecb_inline ecb_const uint32_t
|
1101
1137
|
ecb_byteorder_helper (void)
|
1102
1138
|
{
|
1103
1139
|
/* the union code still generates code under pressure in gcc, */
|
@@ -1106,26 +1142,28 @@ ecb_byteorder_helper (void)
|
|
1106
1142
|
/* the reason why we have this horrible preprocessor mess */
|
1107
1143
|
/* is to avoid it in all cases, at least on common architectures */
|
1108
1144
|
/* or when using a recent enough gcc version (>= 4.6) */
|
1109
|
-
#if (
|
1110
|
-
|
1111
|
-
#
|
1112
|
-
return
|
1113
|
-
#elif __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
1114
|
-
|
1145
|
+
#if (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
|
1146
|
+
|| ((__i386 || __i386__ || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64) && !__VOS__)
|
1147
|
+
#define ECB_LITTLE_ENDIAN 1
|
1148
|
+
return 0x44332211;
|
1149
|
+
#elif (defined __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) \
|
1150
|
+
|| ((__AARCH64EB__ || __MIPSEB__ || __ARMEB__) && !__VOS__)
|
1151
|
+
#define ECB_BIG_ENDIAN 1
|
1152
|
+
return 0x11223344;
|
1115
1153
|
#else
|
1116
1154
|
union
|
1117
1155
|
{
|
1118
|
-
|
1119
|
-
|
1120
|
-
} u = {
|
1121
|
-
return u.
|
1156
|
+
uint8_t c[4];
|
1157
|
+
uint32_t u;
|
1158
|
+
} u = { 0x11, 0x22, 0x33, 0x44 };
|
1159
|
+
return u.u;
|
1122
1160
|
#endif
|
1123
1161
|
}
|
1124
1162
|
|
1125
1163
|
ecb_inline ecb_const ecb_bool ecb_big_endian (void);
|
1126
|
-
ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () ==
|
1164
|
+
ecb_inline ecb_const ecb_bool ecb_big_endian (void) { return ecb_byteorder_helper () == 0x11223344; }
|
1127
1165
|
ecb_inline ecb_const ecb_bool ecb_little_endian (void);
|
1128
|
-
ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () ==
|
1166
|
+
ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_helper () == 0x44332211; }
|
1129
1167
|
|
1130
1168
|
#if ECB_GCC_VERSION(3,0) || ECB_C99
|
1131
1169
|
#define ecb_mod(m,n) ((m) % (n) + ((m) % (n) < 0 ? (n) : 0))
|
@@ -1160,6 +1198,102 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he
|
|
1160
1198
|
#define ecb_array_length(name) (sizeof (name) / sizeof (name [0]))
|
1161
1199
|
#endif
|
1162
1200
|
|
1201
|
+
ecb_function_ ecb_const uint32_t ecb_binary16_to_binary32 (uint32_t x);
|
1202
|
+
ecb_function_ ecb_const uint32_t
|
1203
|
+
ecb_binary16_to_binary32 (uint32_t x)
|
1204
|
+
{
|
1205
|
+
unsigned int s = (x & 0x8000) << (31 - 15);
|
1206
|
+
int e = (x >> 10) & 0x001f;
|
1207
|
+
unsigned int m = x & 0x03ff;
|
1208
|
+
|
1209
|
+
if (ecb_expect_false (e == 31))
|
1210
|
+
/* infinity or NaN */
|
1211
|
+
e = 255 - (127 - 15);
|
1212
|
+
else if (ecb_expect_false (!e))
|
1213
|
+
{
|
1214
|
+
if (ecb_expect_true (!m))
|
1215
|
+
/* zero, handled by code below by forcing e to 0 */
|
1216
|
+
e = 0 - (127 - 15);
|
1217
|
+
else
|
1218
|
+
{
|
1219
|
+
/* subnormal, renormalise */
|
1220
|
+
unsigned int s = 10 - ecb_ld32 (m);
|
1221
|
+
|
1222
|
+
m = (m << s) & 0x3ff; /* mask implicit bit */
|
1223
|
+
e -= s - 1;
|
1224
|
+
}
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
/* e and m now are normalised, or zero, (or inf or nan) */
|
1228
|
+
e += 127 - 15;
|
1229
|
+
|
1230
|
+
return s | (e << 23) | (m << (23 - 10));
|
1231
|
+
}
|
1232
|
+
|
1233
|
+
ecb_function_ ecb_const uint16_t ecb_binary32_to_binary16 (uint32_t x);
|
1234
|
+
ecb_function_ ecb_const uint16_t
|
1235
|
+
ecb_binary32_to_binary16 (uint32_t x)
|
1236
|
+
{
|
1237
|
+
unsigned int s = (x >> 16) & 0x00008000; /* sign bit, the easy part */
|
1238
|
+
unsigned int e = ((x >> 23) & 0x000000ff) - (127 - 15); /* the desired exponent */
|
1239
|
+
unsigned int m = x & 0x007fffff;
|
1240
|
+
|
1241
|
+
x &= 0x7fffffff;
|
1242
|
+
|
1243
|
+
/* if it's within range of binary16 normals, use fast path */
|
1244
|
+
if (ecb_expect_true (0x38800000 <= x && x <= 0x477fefff))
|
1245
|
+
{
|
1246
|
+
/* mantissa round-to-even */
|
1247
|
+
m += 0x00000fff + ((m >> (23 - 10)) & 1);
|
1248
|
+
|
1249
|
+
/* handle overflow */
|
1250
|
+
if (ecb_expect_false (m >= 0x00800000))
|
1251
|
+
{
|
1252
|
+
m >>= 1;
|
1253
|
+
e += 1;
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
return s | (e << 10) | (m >> (23 - 10));
|
1257
|
+
}
|
1258
|
+
|
1259
|
+
/* handle large numbers and infinity */
|
1260
|
+
if (ecb_expect_true (0x477fefff < x && x <= 0x7f800000))
|
1261
|
+
return s | 0x7c00;
|
1262
|
+
|
1263
|
+
/* handle zero, subnormals and small numbers */
|
1264
|
+
if (ecb_expect_true (x < 0x38800000))
|
1265
|
+
{
|
1266
|
+
/* zero */
|
1267
|
+
if (ecb_expect_true (!x))
|
1268
|
+
return s;
|
1269
|
+
|
1270
|
+
/* handle subnormals */
|
1271
|
+
|
1272
|
+
/* too small, will be zero */
|
1273
|
+
if (e < (14 - 24)) /* might not be sharp, but is good enough */
|
1274
|
+
return s;
|
1275
|
+
|
1276
|
+
m |= 0x00800000; /* make implicit bit explicit */
|
1277
|
+
|
1278
|
+
/* very tricky - we need to round to the nearest e (+10) bit value */
|
1279
|
+
{
|
1280
|
+
unsigned int bits = 14 - e;
|
1281
|
+
unsigned int half = (1 << (bits - 1)) - 1;
|
1282
|
+
unsigned int even = (m >> bits) & 1;
|
1283
|
+
|
1284
|
+
/* if this overflows, we will end up with a normalised number */
|
1285
|
+
m = (m + half + even) >> bits;
|
1286
|
+
}
|
1287
|
+
|
1288
|
+
return s | m;
|
1289
|
+
}
|
1290
|
+
|
1291
|
+
/* handle NaNs, preserve leftmost nan bits, but make sure we don't turn them into infinities */
|
1292
|
+
m >>= 13;
|
1293
|
+
|
1294
|
+
return s | 0x7c00 | m | !m;
|
1295
|
+
}
|
1296
|
+
|
1163
1297
|
/*******************************************************************************/
|
1164
1298
|
/* floating point stuff, can be disabled by defining ECB_NO_LIBM */
|
1165
1299
|
|
@@ -1211,23 +1345,6 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he
|
|
1211
1345
|
#define ecb_frexpf(x,e) (float) frexp ((double) (x), (e))
|
1212
1346
|
#endif
|
1213
1347
|
|
1214
|
-
/* converts an ieee half/binary16 to a float */
|
1215
|
-
ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x);
|
1216
|
-
ecb_function_ ecb_const float
|
1217
|
-
ecb_binary16_to_float (uint16_t x)
|
1218
|
-
{
|
1219
|
-
int e = (x >> 10) & 0x1f;
|
1220
|
-
int m = x & 0x3ff;
|
1221
|
-
float r;
|
1222
|
-
|
1223
|
-
if (!e ) r = ecb_ldexpf (m , -24);
|
1224
|
-
else if (e != 31) r = ecb_ldexpf (m + 0x400, e - 25);
|
1225
|
-
else if (m ) r = ECB_NAN;
|
1226
|
-
else r = ECB_INFINITY;
|
1227
|
-
|
1228
|
-
return x & 0x8000 ? -r : r;
|
1229
|
-
}
|
1230
|
-
|
1231
1348
|
/* convert a float to ieee single/binary32 */
|
1232
1349
|
ecb_function_ ecb_const uint32_t ecb_float_to_binary32 (float x);
|
1233
1350
|
ecb_function_ ecb_const uint32_t
|
@@ -1368,6 +1485,22 @@ ecb_inline ecb_const ecb_bool ecb_little_endian (void) { return ecb_byteorder_he
|
|
1368
1485
|
return r;
|
1369
1486
|
}
|
1370
1487
|
|
1488
|
+
/* convert a float to ieee half/binary16 */
|
1489
|
+
ecb_function_ ecb_const uint16_t ecb_float_to_binary16 (float x);
|
1490
|
+
ecb_function_ ecb_const uint16_t
|
1491
|
+
ecb_float_to_binary16 (float x)
|
1492
|
+
{
|
1493
|
+
return ecb_binary32_to_binary16 (ecb_float_to_binary32 (x));
|
1494
|
+
}
|
1495
|
+
|
1496
|
+
/* convert an ieee half/binary16 to float */
|
1497
|
+
ecb_function_ ecb_const float ecb_binary16_to_float (uint16_t x);
|
1498
|
+
ecb_function_ ecb_const float
|
1499
|
+
ecb_binary16_to_float (uint16_t x)
|
1500
|
+
{
|
1501
|
+
return ecb_binary32_to_float (ecb_binary16_to_binary32 (x));
|
1502
|
+
}
|
1503
|
+
|
1371
1504
|
#endif
|
1372
1505
|
|
1373
1506
|
#endif
|
@@ -2922,7 +3055,7 @@ loop_fork (EV_P)
|
|
2922
3055
|
#endif
|
2923
3056
|
|
2924
3057
|
#if EV_SIGNAL_ENABLE || EV_ASYNC_ENABLE
|
2925
|
-
if (ev_is_active (&pipe_w))
|
3058
|
+
if (ev_is_active (&pipe_w) && postfork != 2)
|
2926
3059
|
{
|
2927
3060
|
/* pipe_write_wanted must be false now, so modifying fd vars should be safe */
|
2928
3061
|
|
data/ext/libev/ev.h
CHANGED
@@ -211,7 +211,7 @@ struct ev_loop;
|
|
211
211
|
/*****************************************************************************/
|
212
212
|
|
213
213
|
#define EV_VERSION_MAJOR 4
|
214
|
-
#define EV_VERSION_MINOR
|
214
|
+
#define EV_VERSION_MINOR 22
|
215
215
|
|
216
216
|
/* eventmask, revents, events... */
|
217
217
|
enum {
|
data/ext/libev/ev_epoll.c
CHANGED
@@ -179,7 +179,7 @@ epoll_poll (EV_P_ ev_tstamp timeout)
|
|
179
179
|
if (expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32)))
|
180
180
|
{
|
181
181
|
/* recreate kernel state */
|
182
|
-
postfork
|
182
|
+
postfork |= 2;
|
183
183
|
continue;
|
184
184
|
}
|
185
185
|
|
@@ -203,7 +203,7 @@ epoll_poll (EV_P_ ev_tstamp timeout)
|
|
203
203
|
/* which is fortunately easy to do for us. */
|
204
204
|
if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev))
|
205
205
|
{
|
206
|
-
postfork
|
206
|
+
postfork |= 2; /* an error occurred, recreate kernel state */
|
207
207
|
continue;
|
208
208
|
}
|
209
209
|
}
|
data/ext/libev/ev_win32.c
CHANGED
@@ -39,9 +39,6 @@
|
|
39
39
|
|
40
40
|
#ifdef _WIN32
|
41
41
|
|
42
|
-
/* timeb.h is actually xsi legacy functionality */
|
43
|
-
#include <sys/timeb.h>
|
44
|
-
|
45
42
|
/* note: the comment below could not be substantiated, but what would I care */
|
46
43
|
/* MSDN says this is required to handle SIGFPE */
|
47
44
|
/* my wild guess would be that using something floating-pointy is required */
|
@@ -91,6 +88,8 @@ ev_pipe (int filedes [2])
|
|
91
88
|
if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
|
92
89
|
goto fail;
|
93
90
|
|
91
|
+
/* TODO: returns INVALID_SOCKET on winsock accept, not < 0. fix it */
|
92
|
+
/* when convenient, probably by just removing error checking altogether? */
|
94
93
|
if ((sock [1] = accept (listener, 0, 0)) < 0)
|
95
94
|
goto fail;
|
96
95
|
|
data/ext/nio4r/monitor.c
CHANGED
@@ -15,6 +15,8 @@ static void NIO_Monitor_free(struct NIO_Monitor *monitor);
|
|
15
15
|
|
16
16
|
/* Methods */
|
17
17
|
static VALUE NIO_Monitor_initialize(VALUE self, VALUE selector, VALUE io, VALUE interests);
|
18
|
+
static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests);
|
19
|
+
|
18
20
|
static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self);
|
19
21
|
static VALUE NIO_Monitor_is_closed(VALUE self);
|
20
22
|
static VALUE NIO_Monitor_io(VALUE self);
|
@@ -40,6 +42,7 @@ void Init_NIO_Monitor()
|
|
40
42
|
rb_define_alloc_func(cNIO_Monitor, NIO_Monitor_allocate);
|
41
43
|
|
42
44
|
rb_define_method(cNIO_Monitor, "initialize", NIO_Monitor_initialize, 3);
|
45
|
+
rb_define_method(cNIO_Monitor, "interests=", NIO_Monitor_set_interests, 1);
|
43
46
|
rb_define_method(cNIO_Monitor, "close", NIO_Monitor_close, -1);
|
44
47
|
rb_define_method(cNIO_Monitor, "closed?", NIO_Monitor_is_closed, 0);
|
45
48
|
rb_define_method(cNIO_Monitor, "io", NIO_Monitor_io, 0);
|
@@ -117,6 +120,38 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
|
|
117
120
|
return Qnil;
|
118
121
|
}
|
119
122
|
|
123
|
+
static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
|
124
|
+
{
|
125
|
+
struct NIO_Monitor *monitor;
|
126
|
+
ID interests_id;
|
127
|
+
|
128
|
+
if(NIO_Monitor_is_closed(self) == Qtrue) {
|
129
|
+
rb_raise(rb_eTypeError, "monitor is already closed");
|
130
|
+
}
|
131
|
+
|
132
|
+
interests_id = SYM2ID(interests);
|
133
|
+
Data_Get_Struct(self, struct NIO_Monitor, monitor);
|
134
|
+
|
135
|
+
if(interests_id == rb_intern("r")) {
|
136
|
+
monitor->interests = EV_READ;
|
137
|
+
} else if(interests_id == rb_intern("w")) {
|
138
|
+
monitor->interests = EV_WRITE;
|
139
|
+
} else if(interests_id == rb_intern("rw")) {
|
140
|
+
monitor->interests = EV_READ | EV_WRITE;
|
141
|
+
} else {
|
142
|
+
rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
|
143
|
+
RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0, 0)));
|
144
|
+
}
|
145
|
+
|
146
|
+
ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
|
147
|
+
ev_io_set(&monitor->ev_io, monitor->ev_io.fd, monitor->interests);
|
148
|
+
ev_io_start(monitor->selector->ev_loop, &monitor->ev_io);
|
149
|
+
|
150
|
+
rb_ivar_set(self, rb_intern("interests"), interests);
|
151
|
+
|
152
|
+
return interests;
|
153
|
+
}
|
154
|
+
|
120
155
|
static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
|
121
156
|
{
|
122
157
|
VALUE deregister, selector;
|
@@ -127,10 +162,11 @@ static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
|
|
127
162
|
selector = rb_ivar_get(self, rb_intern("selector"));
|
128
163
|
|
129
164
|
if(selector != Qnil) {
|
130
|
-
/* if ev_loop is 0, it means that the loop has been stopped already (see NIO_Selector_shutdown)*/
|
165
|
+
/* if ev_loop is 0, it means that the loop has been stopped already (see NIO_Selector_shutdown) */
|
131
166
|
if(monitor->selector->ev_loop != 0) {
|
132
167
|
ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
|
133
168
|
}
|
169
|
+
|
134
170
|
monitor->selector = 0;
|
135
171
|
rb_ivar_set(self, rb_intern("selector"), Qnil);
|
136
172
|
|
@@ -148,7 +184,7 @@ static VALUE NIO_Monitor_is_closed(VALUE self)
|
|
148
184
|
struct NIO_Monitor *monitor;
|
149
185
|
Data_Get_Struct(self, struct NIO_Monitor, monitor);
|
150
186
|
|
151
|
-
return
|
187
|
+
return monitor->selector == 0 ? Qtrue : Qfalse;
|
152
188
|
}
|
153
189
|
|
154
190
|
static VALUE NIO_Monitor_io(VALUE self)
|
@@ -235,6 +235,11 @@ public class Nio4r implements Library {
|
|
235
235
|
@JRubyMethod
|
236
236
|
public synchronized IRubyObject select(ThreadContext context, IRubyObject timeout, Block block) {
|
237
237
|
Ruby runtime = context.getRuntime();
|
238
|
+
|
239
|
+
if(!this.selector.isOpen()) {
|
240
|
+
throw context.getRuntime().newIOError("selector is closed");
|
241
|
+
}
|
242
|
+
|
238
243
|
int ready = doSelect(runtime, context, timeout);
|
239
244
|
|
240
245
|
/* Timeout or wakeup */
|
@@ -353,6 +358,36 @@ public class Nio4r implements Library {
|
|
353
358
|
key.attach(this);
|
354
359
|
}
|
355
360
|
|
361
|
+
@JRubyMethod(name = "interests=")
|
362
|
+
public IRubyObject setInterests(ThreadContext context, IRubyObject interests) {
|
363
|
+
if(this.closed == context.getRuntime().getTrue()) {
|
364
|
+
throw context.getRuntime().newTypeError("monitor is already closed");
|
365
|
+
}
|
366
|
+
|
367
|
+
int interestOps = 0;
|
368
|
+
Ruby runtime = context.getRuntime();
|
369
|
+
Channel rawChannel = io.getChannel();
|
370
|
+
SelectableChannel channel = (SelectableChannel)rawChannel;
|
371
|
+
|
372
|
+
this.interests = interests;
|
373
|
+
|
374
|
+
if(interests == ruby.newSymbol("r")) {
|
375
|
+
interestOps = SelectionKey.OP_READ;
|
376
|
+
} else if(interests == ruby.newSymbol("w")) {
|
377
|
+
interestOps = SelectionKey.OP_WRITE;
|
378
|
+
} else if(interests == ruby.newSymbol("rw")) {
|
379
|
+
interestOps = SelectionKey.OP_READ|SelectionKey.OP_WRITE;
|
380
|
+
}
|
381
|
+
|
382
|
+
if((interestOps & ~(channel.validOps())) == 0) {
|
383
|
+
key.interestOps(interestOps);
|
384
|
+
} else {
|
385
|
+
throw context.getRuntime().newArgumentError("given interests not supported for this IO object");
|
386
|
+
}
|
387
|
+
|
388
|
+
return this.interests;
|
389
|
+
}
|
390
|
+
|
356
391
|
@JRubyMethod
|
357
392
|
public IRubyObject io(ThreadContext context) {
|
358
393
|
return io;
|
data/ext/nio4r/selector.c
CHANGED
@@ -297,6 +297,11 @@ static VALUE NIO_Selector_select_synchronized(VALUE *args)
|
|
297
297
|
struct NIO_Selector *selector;
|
298
298
|
|
299
299
|
Data_Get_Struct(args[0], struct NIO_Selector, selector);
|
300
|
+
|
301
|
+
if(selector->closed) {
|
302
|
+
rb_raise(rb_eIOError, "selector is closed");
|
303
|
+
}
|
304
|
+
|
300
305
|
if(!rb_block_given_p()) {
|
301
306
|
selector->ready_array = rb_ary_new();
|
302
307
|
}
|
data/lib/nio/monitor.rb
CHANGED
@@ -22,6 +22,14 @@ module NIO
|
|
22
22
|
@closed = false
|
23
23
|
end
|
24
24
|
|
25
|
+
# set the interests set
|
26
|
+
def interests=(interests)
|
27
|
+
fail TypeError, "monitor is already closed" if closed?
|
28
|
+
fail ArgumentError, "bad interests: #{interests}" unless [:r, :w, :rw].include?(interests)
|
29
|
+
|
30
|
+
@interests = interests
|
31
|
+
end
|
32
|
+
|
25
33
|
# Is the IO object readable?
|
26
34
|
def readable?
|
27
35
|
readiness == :r || readiness == :rw
|
data/lib/nio/selector.rb
CHANGED
@@ -78,11 +78,10 @@ module NIO
|
|
78
78
|
|
79
79
|
ready_writers.each do |io|
|
80
80
|
monitor = @selectables[io]
|
81
|
-
monitor.readiness
|
82
|
-
|
83
|
-
:rw
|
81
|
+
if monitor.readiness == :r
|
82
|
+
monitor.readiness = :rw
|
84
83
|
else
|
85
|
-
:w
|
84
|
+
monitor.readiness = :w
|
86
85
|
end
|
87
86
|
selected_monitors << monitor
|
88
87
|
end
|
data/lib/nio/version.rb
CHANGED
data/spec/nio/monitor_spec.rb
CHANGED
@@ -1,20 +1,49 @@
|
|
1
1
|
require "spec_helper"
|
2
|
+
require "socket"
|
2
3
|
|
3
4
|
RSpec.describe NIO::Monitor do
|
4
|
-
let(:
|
5
|
-
|
6
|
-
|
5
|
+
let(:example_peers) do
|
6
|
+
address = "127.0.0.1"
|
7
|
+
base_port = 12_345
|
8
|
+
tries = 10
|
9
|
+
|
10
|
+
server = tries.times do |n|
|
11
|
+
begin
|
12
|
+
break TCPServer.new(address, base_port + n)
|
13
|
+
rescue Errno::EADDRINUSE
|
14
|
+
retry
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
fail Errno::EADDRINUSE, "couldn't find an open port" unless server
|
19
|
+
client = TCPSocket.new(address, server.addr[1])
|
20
|
+
[server, client]
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:reader) { example_peers.first }
|
24
|
+
let(:writer) { example_peers.last }
|
25
|
+
|
7
26
|
let(:selector) { NIO::Selector.new }
|
8
27
|
|
9
28
|
subject { selector.register(reader, :r) }
|
10
29
|
let(:peer) { selector.register(writer, :rw) }
|
11
30
|
after { selector.close }
|
12
31
|
|
32
|
+
before { example_peers } # open server and client automatically
|
33
|
+
after { reader.close }
|
34
|
+
after { writer.close }
|
35
|
+
|
13
36
|
it "knows its interests" do
|
14
37
|
expect(subject.interests).to eq(:r)
|
15
38
|
expect(peer.interests).to eq(:rw)
|
16
39
|
end
|
17
40
|
|
41
|
+
it "changes the interest set" do
|
42
|
+
expect(peer.interests).not_to eq(:w)
|
43
|
+
peer.interests = :w
|
44
|
+
expect(peer.interests).to eq(:w)
|
45
|
+
end
|
46
|
+
|
18
47
|
it "knows its IO object" do
|
19
48
|
expect(subject.io).to eq(reader)
|
20
49
|
end
|
@@ -34,14 +63,13 @@ RSpec.describe NIO::Monitor do
|
|
34
63
|
writer_monitor = peer
|
35
64
|
|
36
65
|
selected = selector.select(0)
|
37
|
-
expect(selected).not_to include(reader_monitor)
|
38
66
|
expect(selected).to include(writer_monitor)
|
39
67
|
|
40
68
|
expect(writer_monitor.readiness).to eq(:w)
|
41
69
|
expect(writer_monitor).not_to be_readable
|
42
70
|
expect(writer_monitor).to be_writable
|
43
71
|
|
44
|
-
writer << "
|
72
|
+
writer << "testing 1 2 3"
|
45
73
|
|
46
74
|
selected = selector.select(0)
|
47
75
|
expect(selected).to include(reader_monitor)
|
@@ -51,6 +79,14 @@ RSpec.describe NIO::Monitor do
|
|
51
79
|
expect(reader_monitor).not_to be_writable
|
52
80
|
end
|
53
81
|
|
82
|
+
it "changes current interests with #interests=" do
|
83
|
+
client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
84
|
+
monitor = selector.register(client, :r)
|
85
|
+
expect(monitor.interests).to eq(:r)
|
86
|
+
monitor.interests = :w
|
87
|
+
expect(monitor.interests).to eq(:w)
|
88
|
+
end
|
89
|
+
|
54
90
|
it "closes" do
|
55
91
|
expect(subject).not_to be_closed
|
56
92
|
expect(selector.registered?(reader)).to be_truthy
|
@@ -67,4 +103,11 @@ RSpec.describe NIO::Monitor do
|
|
67
103
|
subject.close
|
68
104
|
expect(subject).to be_closed
|
69
105
|
end
|
106
|
+
|
107
|
+
it "changes the interest set after monitor closed" do
|
108
|
+
# check for changing the interests on the go after closed expected to fail
|
109
|
+
expect(subject.interests).not_to eq(:rw)
|
110
|
+
subject.close # forced shutdown
|
111
|
+
expect { subject.interests = :rw }.to raise_error(TypeError)
|
112
|
+
end
|
70
113
|
end
|
@@ -80,7 +80,7 @@ RSpec.describe TCPSocket do
|
|
80
80
|
client.connect_nonblock Socket.sockaddr_in(tcp_port, "127.0.0.1")
|
81
81
|
end.to raise_exception Errno::EINPROGRESS
|
82
82
|
|
83
|
-
expect(selector.select(0)).to include monitor
|
83
|
+
expect(selector.select(0.001)).to include monitor
|
84
84
|
result = client.getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_ERROR)
|
85
85
|
expect(result.unpack("i").first).to be_zero
|
86
86
|
end
|
data/spec/nio/selector_spec.rb
CHANGED
@@ -161,6 +161,12 @@ RSpec.describe NIO::Selector do
|
|
161
161
|
expect(readables).to include monitor2
|
162
162
|
expect(readables).not_to include monitor3
|
163
163
|
end
|
164
|
+
|
165
|
+
it "raises IOError if asked to select on a closed selector" do
|
166
|
+
subject.close
|
167
|
+
|
168
|
+
expect { subject.select(0) }.to raise_exception IOError
|
169
|
+
end
|
164
170
|
end
|
165
171
|
|
166
172
|
it "closes" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nio4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
145
|
version: '0'
|
146
146
|
requirements: []
|
147
147
|
rubyforge_project:
|
148
|
-
rubygems_version: 2.4.
|
148
|
+
rubygems_version: 2.4.8
|
149
149
|
signing_key:
|
150
150
|
specification_version: 4
|
151
151
|
summary: NIO provides a high performance selector API for monitoring IO objects
|