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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7b58cda1a26e30cb81ff1b0f6febb43413a4c11f
4
- data.tar.gz: 319495e598529456785aa74289742cb87d7d2470
3
+ metadata.gz: 339fc3cc040e41d266a9f83ab155d903294fcdc5
4
+ data.tar.gz: 8872185b3bfadc884b36b65ea1a17a2c082d7090
5
5
  SHA512:
6
- metadata.gz: de267fdf599880196fa3a3431cd20a1ce2d4e6dcec16f57f4161b7b6d05d9f8e2c97651a1a959e16f2cea6de965e30b60842635aa954685666a4a4d5c99402fc
7
- data.tar.gz: a580ce6b7edf0e7923f0725e5ae9ebe5a194cbd235fa320b2b04a1c8f794ada1e93200a2fb8c9dedbee1961d73e3767e39ec1bdc6b727939281e5ac687e1ec8a
6
+ metadata.gz: 73083b74bdcb581449b5b0534209fdd9b1c08059ee946eaf9f8155d72605030c127046a7819d4ed325e0bf3e525c4aec81a41c00b55077f9e5b4629dd147d931
7
+ data.tar.gz: 44eb8368129b34cfb8780b98334ff8a67029d1751fdfc756ee761cb19c975f55a95c5166a251dba88ea7f587a3441f19650dcb13d936d88c60f847bda9c20d1d
@@ -24,6 +24,9 @@ Metrics/CyclomaticComplexity:
24
24
  Style/GlobalVars:
25
25
  Enabled: false
26
26
 
27
+ Style/TrivialAccessors:
28
+ Enabled: false
29
+
27
30
  #
28
31
  # Auto-generated overrides
29
32
  #
@@ -1,3 +1,6 @@
1
+ language: ruby
2
+ sudo: false
3
+
1
4
  rvm:
2
5
  - 2.0.0
3
6
  - 2.1.1
data/CHANGES.md CHANGED
@@ -1,3 +1,9 @@
1
+ 1.2.0 (2015-12-22)
2
+ ------------------
3
+ * Add NIO::Monitor#interests= API for changing interests. Contributed by
4
+ @UpeksheJay as a Google Summer of Code project.
5
+ * Update to libev 4.22
6
+
1
7
  1.1.1 (2015-07-17)
2
8
  ------------------
3
9
  * Update to libev 4.20
@@ -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.
@@ -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 0x00010004
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 UINTMAX_MAX > 0xffffffffU
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 __ARM_ARCH_7M__ || defined __ARM_ARCH_7R__
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
- int shift = x & 0xffffffffU ? 0 : 32;
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 unsigned char ecb_byteorder_helper (void);
1100
- ecb_inline ecb_const unsigned char
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 ((__i386 || __i386__) && !__VOS__) || _M_IX86 || ECB_GCC_AMD64 || ECB_MSVC_AMD64
1110
- return 0x44;
1111
- #elif __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
1112
- return 0x44;
1113
- #elif __BYTE_ORDER__ && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1114
- return 0x11;
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
- uint32_t i;
1119
- uint8_t c;
1120
- } u = { 0x11223344 };
1121
- return u.c;
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 () == 0x11; }
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 () == 0x44; }
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
 
@@ -211,7 +211,7 @@ struct ev_loop;
211
211
  /*****************************************************************************/
212
212
 
213
213
  #define EV_VERSION_MAJOR 4
214
- #define EV_VERSION_MINOR 20
214
+ #define EV_VERSION_MINOR 22
215
215
 
216
216
  /* eventmask, revents, events... */
217
217
  enum {
@@ -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 = 1;
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 = 1; /* an error occurred, recreate kernel state */
206
+ postfork |= 2; /* an error occurred, recreate kernel state */
207
207
  continue;
208
208
  }
209
209
  }
@@ -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
 
@@ -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 !monitor->selector;
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;
@@ -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
  }
@@ -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
@@ -78,11 +78,10 @@ module NIO
78
78
 
79
79
  ready_writers.each do |io|
80
80
  monitor = @selectables[io]
81
- monitor.readiness = case monitor.readiness
82
- when :r
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
@@ -1,3 +1,3 @@
1
1
  module NIO
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -1,20 +1,49 @@
1
1
  require "spec_helper"
2
+ require "socket"
2
3
 
3
4
  RSpec.describe NIO::Monitor do
4
- let(:pipes) { IO.pipe }
5
- let(:reader) { pipes.first }
6
- let(:writer) { pipes.last }
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 << "loldata"
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
@@ -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.1.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-07-18 00:00:00.000000000 Z
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.6
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