nio4r 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|