nio4r 2.5.2 → 2.7.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/.github/workflows/workflow.yml +61 -0
- data/.mailmap +16 -0
- data/.rubocop.yml +30 -11
- data/Gemfile +6 -6
- data/{CHANGES.md → changes.md} +78 -1
- data/examples/echo_server.rb +9 -2
- data/ext/libev/Changes +71 -2
- data/ext/libev/ev.c +611 -198
- data/ext/libev/ev.h +25 -22
- data/ext/libev/ev_epoll.c +16 -14
- data/ext/libev/ev_iouring.c +694 -0
- data/ext/libev/ev_kqueue.c +4 -4
- data/ext/libev/ev_linuxaio.c +78 -100
- data/ext/libev/ev_poll.c +6 -6
- data/ext/libev/ev_port.c +3 -3
- data/ext/libev/ev_select.c +6 -6
- data/ext/libev/ev_vars.h +34 -0
- data/ext/libev/ev_win32.c +2 -2
- data/ext/libev/ev_wrap.h +56 -0
- data/ext/nio4r/.clang-format +16 -0
- data/ext/nio4r/bytebuffer.c +101 -65
- data/ext/nio4r/extconf.rb +26 -0
- data/ext/nio4r/libev.h +1 -3
- data/ext/nio4r/monitor.c +81 -53
- data/ext/nio4r/nio4r.h +6 -15
- data/ext/nio4r/nio4r_ext.c +1 -1
- data/ext/nio4r/org/nio4r/ByteBuffer.java +2 -0
- data/ext/nio4r/org/nio4r/Monitor.java +1 -0
- data/ext/nio4r/org/nio4r/Selector.java +8 -10
- data/ext/nio4r/selector.c +132 -93
- data/lib/nio/bytebuffer.rb +10 -0
- data/lib/nio/monitor.rb +8 -1
- data/lib/nio/selector.rb +27 -10
- data/lib/nio/version.rb +6 -1
- data/lib/nio.rb +29 -1
- data/lib/nio4r.rb +5 -0
- data/license.md +77 -0
- data/nio4r.gemspec +6 -5
- data/rakelib/extension.rake +1 -2
- data/readme.md +91 -0
- data/spec/nio/acceptables_spec.rb +4 -0
- data/spec/nio/bytebuffer_spec.rb +6 -1
- data/spec/nio/monitor_spec.rb +7 -0
- data/spec/nio/selectables/pipe_spec.rb +6 -0
- data/spec/nio/selectables/ssl_socket_spec.rb +7 -0
- data/spec/nio/selectables/tcp_socket_spec.rb +7 -0
- data/spec/nio/selectables/udp_socket_spec.rb +9 -2
- data/spec/nio/selector_spec.rb +16 -1
- data/spec/spec_helper.rb +7 -2
- data/spec/support/selectable_examples.rb +8 -0
- metadata +20 -16
- data/.travis.yml +0 -44
- data/Guardfile +0 -10
- data/README.md +0 -150
- data/appveyor.yml +0 -40
data/ext/nio4r/selector.c
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
#include "nio4r.h"
|
7
7
|
#ifdef HAVE_RUBYSIG_H
|
8
|
-
#
|
8
|
+
#include "rubysig.h"
|
9
9
|
#endif
|
10
10
|
|
11
11
|
#ifdef HAVE_UNISTD_H
|
@@ -14,18 +14,19 @@
|
|
14
14
|
#include <io.h>
|
15
15
|
#endif
|
16
16
|
|
17
|
-
#include <fcntl.h>
|
18
17
|
#include <assert.h>
|
18
|
+
#include <fcntl.h>
|
19
19
|
|
20
20
|
static VALUE mNIO = Qnil;
|
21
|
-
static VALUE cNIO_Monitor
|
21
|
+
static VALUE cNIO_Monitor = Qnil;
|
22
22
|
static VALUE cNIO_Selector = Qnil;
|
23
23
|
|
24
24
|
/* Allocator/deallocator */
|
25
25
|
static VALUE NIO_Selector_allocate(VALUE klass);
|
26
|
-
static void NIO_Selector_mark(
|
26
|
+
static void NIO_Selector_mark(void *data);
|
27
27
|
static void NIO_Selector_shutdown(struct NIO_Selector *selector);
|
28
|
-
static void NIO_Selector_free(
|
28
|
+
static void NIO_Selector_free(void *data);
|
29
|
+
static size_t NIO_Selector_memsize(const void *data);
|
29
30
|
|
30
31
|
/* Class methods */
|
31
32
|
static VALUE NIO_Selector_supported_backends(VALUE klass);
|
@@ -43,13 +44,13 @@ static VALUE NIO_Selector_closed(VALUE self);
|
|
43
44
|
static VALUE NIO_Selector_is_empty(VALUE self);
|
44
45
|
|
45
46
|
/* Internal functions */
|
46
|
-
static VALUE NIO_Selector_synchronize(VALUE self, VALUE (*func)(VALUE
|
47
|
+
static VALUE NIO_Selector_synchronize(VALUE self, VALUE (*func)(VALUE arg), VALUE arg);
|
47
48
|
static VALUE NIO_Selector_unlock(VALUE lock);
|
48
|
-
static VALUE NIO_Selector_register_synchronized(VALUE
|
49
|
-
static VALUE NIO_Selector_deregister_synchronized(VALUE
|
50
|
-
static VALUE NIO_Selector_select_synchronized(VALUE
|
51
|
-
static VALUE NIO_Selector_close_synchronized(VALUE
|
52
|
-
static VALUE NIO_Selector_closed_synchronized(VALUE
|
49
|
+
static VALUE NIO_Selector_register_synchronized(VALUE arg);
|
50
|
+
static VALUE NIO_Selector_deregister_synchronized(VALUE arg);
|
51
|
+
static VALUE NIO_Selector_select_synchronized(VALUE arg);
|
52
|
+
static VALUE NIO_Selector_close_synchronized(VALUE arg);
|
53
|
+
static VALUE NIO_Selector_closed_synchronized(VALUE arg);
|
53
54
|
|
54
55
|
static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout);
|
55
56
|
static void NIO_Selector_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents);
|
@@ -62,7 +63,7 @@ static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *
|
|
62
63
|
#define BUSYWAIT_INTERVAL 0.01
|
63
64
|
|
64
65
|
/* Selectors wait for events */
|
65
|
-
void Init_NIO_Selector()
|
66
|
+
void Init_NIO_Selector(void)
|
66
67
|
{
|
67
68
|
mNIO = rb_define_module("NIO");
|
68
69
|
cNIO_Selector = rb_define_class_under(mNIO, "Selector", rb_cObject);
|
@@ -80,9 +81,21 @@ void Init_NIO_Selector()
|
|
80
81
|
rb_define_method(cNIO_Selector, "closed?", NIO_Selector_closed, 0);
|
81
82
|
rb_define_method(cNIO_Selector, "empty?", NIO_Selector_is_empty, 0);
|
82
83
|
|
83
|
-
cNIO_Monitor = rb_define_class_under(mNIO, "Monitor",
|
84
|
+
cNIO_Monitor = rb_define_class_under(mNIO, "Monitor", rb_cObject);
|
84
85
|
}
|
85
86
|
|
87
|
+
static const rb_data_type_t NIO_Selector_type = {
|
88
|
+
"NIO::Selector",
|
89
|
+
{
|
90
|
+
NIO_Selector_mark,
|
91
|
+
NIO_Selector_free,
|
92
|
+
NIO_Selector_memsize,
|
93
|
+
},
|
94
|
+
0,
|
95
|
+
0,
|
96
|
+
RUBY_TYPED_WB_PROTECTED // Don't free immediately because of shutdown
|
97
|
+
};
|
98
|
+
|
86
99
|
/* Create the libev event loop and incoming event buffer */
|
87
100
|
static VALUE NIO_Selector_allocate(VALUE klass)
|
88
101
|
{
|
@@ -95,18 +108,16 @@ static VALUE NIO_Selector_allocate(VALUE klass)
|
|
95
108
|
safety. Pipes are nice and safe to use between threads.
|
96
109
|
|
97
110
|
Note that Java NIO uses this same mechanism */
|
98
|
-
if(pipe(fds) < 0) {
|
111
|
+
if (pipe(fds) < 0) {
|
99
112
|
rb_sys_fail("pipe");
|
100
113
|
}
|
101
114
|
|
102
115
|
/* Use non-blocking reads/writes during wakeup, in case the buffer is full */
|
103
|
-
if(fcntl(fds[0], F_SETFL, O_NONBLOCK) < 0 ||
|
104
|
-
fcntl(fds[1], F_SETFL, O_NONBLOCK) < 0) {
|
116
|
+
if (fcntl(fds[0], F_SETFL, O_NONBLOCK) < 0 || fcntl(fds[1], F_SETFL, O_NONBLOCK) < 0) {
|
105
117
|
rb_sys_fail("fcntl");
|
106
118
|
}
|
107
119
|
|
108
|
-
|
109
|
-
|
120
|
+
VALUE obj = TypedData_Make_Struct(klass, struct NIO_Selector, &NIO_Selector_type, selector);
|
110
121
|
/* Defer initializing the loop to #initialize */
|
111
122
|
selector->ev_loop = 0;
|
112
123
|
|
@@ -119,15 +130,22 @@ static VALUE NIO_Selector_allocate(VALUE klass)
|
|
119
130
|
selector->wakeup.data = (void *)selector;
|
120
131
|
|
121
132
|
selector->closed = selector->selecting = selector->wakeup_fired = selector->ready_count = 0;
|
122
|
-
selector->ready_array
|
133
|
+
RB_OBJ_WRITE(obj, &selector->ready_array, Qnil);
|
134
|
+
return obj;
|
135
|
+
}
|
123
136
|
|
124
|
-
|
137
|
+
struct NIO_Selector *NIO_Selector_unwrap(VALUE self)
|
138
|
+
{
|
139
|
+
struct NIO_Selector *selector;
|
140
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
141
|
+
return selector;
|
125
142
|
}
|
126
143
|
|
127
144
|
/* NIO selectors store all Ruby objects in instance variables so mark is a stub */
|
128
|
-
static void NIO_Selector_mark(
|
145
|
+
static void NIO_Selector_mark(void *data)
|
129
146
|
{
|
130
|
-
|
147
|
+
struct NIO_Selector *selector = (struct NIO_Selector *)data;
|
148
|
+
if (selector->ready_array != Qnil) {
|
131
149
|
rb_gc_mark(selector->ready_array);
|
132
150
|
}
|
133
151
|
}
|
@@ -136,14 +154,14 @@ static void NIO_Selector_mark(struct NIO_Selector *selector)
|
|
136
154
|
Called by both NIO::Selector#close and the finalizer below */
|
137
155
|
static void NIO_Selector_shutdown(struct NIO_Selector *selector)
|
138
156
|
{
|
139
|
-
if(selector->closed) {
|
157
|
+
if (selector->closed) {
|
140
158
|
return;
|
141
159
|
}
|
142
160
|
|
143
161
|
close(selector->wakeup_reader);
|
144
162
|
close(selector->wakeup_writer);
|
145
163
|
|
146
|
-
if(selector->ev_loop) {
|
164
|
+
if (selector->ev_loop) {
|
147
165
|
ev_loop_destroy(selector->ev_loop);
|
148
166
|
selector->ev_loop = 0;
|
149
167
|
}
|
@@ -152,37 +170,52 @@ static void NIO_Selector_shutdown(struct NIO_Selector *selector)
|
|
152
170
|
}
|
153
171
|
|
154
172
|
/* Ruby finalizer for selector objects */
|
155
|
-
static void NIO_Selector_free(
|
173
|
+
static void NIO_Selector_free(void *data)
|
156
174
|
{
|
175
|
+
struct NIO_Selector *selector = (struct NIO_Selector *)data;
|
157
176
|
NIO_Selector_shutdown(selector);
|
158
177
|
xfree(selector);
|
159
178
|
}
|
160
179
|
|
180
|
+
static size_t NIO_Selector_memsize(const void *data)
|
181
|
+
{
|
182
|
+
return sizeof(struct NIO_Selector);
|
183
|
+
}
|
184
|
+
|
161
185
|
/* Return an array of symbols for supported backends */
|
162
|
-
static VALUE NIO_Selector_supported_backends(VALUE klass)
|
186
|
+
static VALUE NIO_Selector_supported_backends(VALUE klass)
|
187
|
+
{
|
163
188
|
unsigned int backends = ev_supported_backends();
|
164
189
|
VALUE result = rb_ary_new();
|
165
190
|
|
166
|
-
if(backends & EVBACKEND_EPOLL) {
|
191
|
+
if (backends & EVBACKEND_EPOLL) {
|
167
192
|
rb_ary_push(result, ID2SYM(rb_intern("epoll")));
|
168
193
|
}
|
169
194
|
|
170
|
-
if(backends & EVBACKEND_POLL) {
|
195
|
+
if (backends & EVBACKEND_POLL) {
|
171
196
|
rb_ary_push(result, ID2SYM(rb_intern("poll")));
|
172
197
|
}
|
173
198
|
|
174
|
-
if(backends & EVBACKEND_KQUEUE) {
|
199
|
+
if (backends & EVBACKEND_KQUEUE) {
|
175
200
|
rb_ary_push(result, ID2SYM(rb_intern("kqueue")));
|
176
201
|
}
|
177
202
|
|
178
|
-
if(backends & EVBACKEND_SELECT) {
|
203
|
+
if (backends & EVBACKEND_SELECT) {
|
179
204
|
rb_ary_push(result, ID2SYM(rb_intern("select")));
|
180
205
|
}
|
181
206
|
|
182
|
-
if(backends & EVBACKEND_PORT) {
|
207
|
+
if (backends & EVBACKEND_PORT) {
|
183
208
|
rb_ary_push(result, ID2SYM(rb_intern("port")));
|
184
209
|
}
|
185
210
|
|
211
|
+
if (backends & EVBACKEND_LINUXAIO) {
|
212
|
+
rb_ary_push(result, ID2SYM(rb_intern("linuxaio")));
|
213
|
+
}
|
214
|
+
|
215
|
+
if (backends & EVBACKEND_IOURING) {
|
216
|
+
rb_ary_push(result, ID2SYM(rb_intern("io_uring")));
|
217
|
+
}
|
218
|
+
|
186
219
|
return result;
|
187
220
|
}
|
188
221
|
|
@@ -197,31 +230,33 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
|
|
197
230
|
struct NIO_Selector *selector;
|
198
231
|
unsigned int flags = 0;
|
199
232
|
|
200
|
-
|
233
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
201
234
|
|
202
235
|
rb_scan_args(argc, argv, "01", &backend);
|
203
236
|
|
204
|
-
if(backend != Qnil) {
|
205
|
-
if(!rb_ary_includes(NIO_Selector_supported_backends(CLASS_OF(self)), backend)) {
|
206
|
-
rb_raise(rb_eArgError, "unsupported backend: %s",
|
207
|
-
RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
|
237
|
+
if (backend != Qnil) {
|
238
|
+
if (!rb_ary_includes(NIO_Selector_supported_backends(CLASS_OF(self)), backend)) {
|
239
|
+
rb_raise(rb_eArgError, "unsupported backend: %s", RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
|
208
240
|
}
|
209
241
|
|
210
242
|
backend_id = SYM2ID(backend);
|
211
243
|
|
212
|
-
if(backend_id == rb_intern("epoll")) {
|
244
|
+
if (backend_id == rb_intern("epoll")) {
|
213
245
|
flags = EVBACKEND_EPOLL;
|
214
|
-
} else if(backend_id == rb_intern("poll")) {
|
246
|
+
} else if (backend_id == rb_intern("poll")) {
|
215
247
|
flags = EVBACKEND_POLL;
|
216
|
-
} else if(backend_id == rb_intern("kqueue")) {
|
248
|
+
} else if (backend_id == rb_intern("kqueue")) {
|
217
249
|
flags = EVBACKEND_KQUEUE;
|
218
|
-
} else if(backend_id == rb_intern("select")) {
|
250
|
+
} else if (backend_id == rb_intern("select")) {
|
219
251
|
flags = EVBACKEND_SELECT;
|
220
|
-
} else if(backend_id == rb_intern("port")) {
|
252
|
+
} else if (backend_id == rb_intern("port")) {
|
221
253
|
flags = EVBACKEND_PORT;
|
254
|
+
} else if (backend_id == rb_intern("linuxaio")) {
|
255
|
+
flags = EVBACKEND_LINUXAIO;
|
256
|
+
} else if (backend_id == rb_intern("io_uring")) {
|
257
|
+
flags = EVBACKEND_IOURING;
|
222
258
|
} else {
|
223
|
-
rb_raise(rb_eArgError, "unsupported backend: %s",
|
224
|
-
RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
|
259
|
+
rb_raise(rb_eArgError, "unsupported backend: %s", RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
|
225
260
|
}
|
226
261
|
}
|
227
262
|
|
@@ -229,7 +264,7 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
|
|
229
264
|
assert(!selector->ev_loop);
|
230
265
|
|
231
266
|
selector->ev_loop = ev_loop_new(flags);
|
232
|
-
if(!selector->ev_loop) {
|
267
|
+
if (!selector->ev_loop) {
|
233
268
|
rb_raise(rb_eIOError, "error initializing event loop");
|
234
269
|
}
|
235
270
|
|
@@ -245,11 +280,12 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
|
|
245
280
|
return Qnil;
|
246
281
|
}
|
247
282
|
|
248
|
-
static VALUE NIO_Selector_backend(VALUE self)
|
283
|
+
static VALUE NIO_Selector_backend(VALUE self)
|
284
|
+
{
|
249
285
|
struct NIO_Selector *selector;
|
250
286
|
|
251
|
-
|
252
|
-
if(selector->closed) {
|
287
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
288
|
+
if (selector->closed) {
|
253
289
|
rb_raise(rb_eIOError, "selector is closed");
|
254
290
|
}
|
255
291
|
|
@@ -264,29 +300,33 @@ static VALUE NIO_Selector_backend(VALUE self) {
|
|
264
300
|
return ID2SYM(rb_intern("select"));
|
265
301
|
case EVBACKEND_PORT:
|
266
302
|
return ID2SYM(rb_intern("port"));
|
303
|
+
case EVBACKEND_LINUXAIO:
|
304
|
+
return ID2SYM(rb_intern("linuxaio"));
|
305
|
+
case EVBACKEND_IOURING:
|
306
|
+
return ID2SYM(rb_intern("io_uring"));
|
267
307
|
}
|
268
308
|
|
269
309
|
return ID2SYM(rb_intern("unknown"));
|
270
310
|
}
|
271
311
|
|
272
312
|
/* Synchronize around a reentrant selector lock */
|
273
|
-
static VALUE NIO_Selector_synchronize(VALUE self, VALUE (*func)(VALUE
|
313
|
+
static VALUE NIO_Selector_synchronize(VALUE self, VALUE (*func)(VALUE arg), VALUE arg)
|
274
314
|
{
|
275
315
|
VALUE current_thread, lock_holder, lock;
|
276
316
|
|
277
317
|
current_thread = rb_thread_current();
|
278
318
|
lock_holder = rb_ivar_get(self, rb_intern("lock_holder"));
|
279
319
|
|
280
|
-
if(lock_holder != current_thread) {
|
320
|
+
if (lock_holder != current_thread) {
|
281
321
|
lock = rb_ivar_get(self, rb_intern("lock"));
|
282
322
|
rb_funcall(lock, rb_intern("lock"), 0);
|
283
323
|
rb_ivar_set(self, rb_intern("lock_holder"), current_thread);
|
284
324
|
|
285
325
|
/* We've acquired the lock, so ensure we unlock it */
|
286
|
-
return rb_ensure(func, (VALUE)
|
326
|
+
return rb_ensure(func, (VALUE)arg, NIO_Selector_unlock, self);
|
287
327
|
} else {
|
288
328
|
/* We already hold the selector lock, so no need to unlock it */
|
289
|
-
return func(
|
329
|
+
return func(arg);
|
290
330
|
}
|
291
331
|
}
|
292
332
|
|
@@ -307,29 +347,30 @@ static VALUE NIO_Selector_unlock(VALUE self)
|
|
307
347
|
static VALUE NIO_Selector_register(VALUE self, VALUE io, VALUE interests)
|
308
348
|
{
|
309
349
|
VALUE args[3] = {self, io, interests};
|
310
|
-
return NIO_Selector_synchronize(self, NIO_Selector_register_synchronized, args);
|
350
|
+
return NIO_Selector_synchronize(self, NIO_Selector_register_synchronized, (VALUE)args);
|
311
351
|
}
|
312
352
|
|
313
353
|
/* Internal implementation of register after acquiring mutex */
|
314
|
-
static VALUE NIO_Selector_register_synchronized(VALUE
|
354
|
+
static VALUE NIO_Selector_register_synchronized(VALUE _args)
|
315
355
|
{
|
316
356
|
VALUE self, io, interests, selectables, monitor;
|
317
357
|
VALUE monitor_args[3];
|
318
358
|
struct NIO_Selector *selector;
|
319
359
|
|
360
|
+
VALUE *args = (VALUE *)_args;
|
320
361
|
self = args[0];
|
321
362
|
io = args[1];
|
322
363
|
interests = args[2];
|
323
364
|
|
324
|
-
|
325
|
-
if(selector->closed) {
|
365
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
366
|
+
if (selector->closed) {
|
326
367
|
rb_raise(rb_eIOError, "selector is closed");
|
327
368
|
}
|
328
369
|
|
329
370
|
selectables = rb_ivar_get(self, rb_intern("selectables"));
|
330
371
|
monitor = rb_hash_lookup(selectables, io);
|
331
372
|
|
332
|
-
if(monitor != Qnil)
|
373
|
+
if (monitor != Qnil)
|
333
374
|
rb_raise(rb_eArgError, "this IO is already registered with selector");
|
334
375
|
|
335
376
|
/* Create a new NIO::Monitor */
|
@@ -347,21 +388,22 @@ static VALUE NIO_Selector_register_synchronized(VALUE *args)
|
|
347
388
|
static VALUE NIO_Selector_deregister(VALUE self, VALUE io)
|
348
389
|
{
|
349
390
|
VALUE args[2] = {self, io};
|
350
|
-
return NIO_Selector_synchronize(self, NIO_Selector_deregister_synchronized, args);
|
391
|
+
return NIO_Selector_synchronize(self, NIO_Selector_deregister_synchronized, (VALUE)args);
|
351
392
|
}
|
352
393
|
|
353
394
|
/* Internal implementation of register after acquiring mutex */
|
354
|
-
static VALUE NIO_Selector_deregister_synchronized(VALUE
|
395
|
+
static VALUE NIO_Selector_deregister_synchronized(VALUE _args)
|
355
396
|
{
|
356
397
|
VALUE self, io, selectables, monitor;
|
357
398
|
|
399
|
+
VALUE *args = (VALUE *)_args;
|
358
400
|
self = args[0];
|
359
401
|
io = args[1];
|
360
402
|
|
361
403
|
selectables = rb_ivar_get(self, rb_intern("selectables"));
|
362
404
|
monitor = rb_hash_delete(selectables, io);
|
363
405
|
|
364
|
-
if(monitor != Qnil) {
|
406
|
+
if (monitor != Qnil) {
|
365
407
|
rb_funcall(monitor, rb_intern("close"), 1, Qfalse);
|
366
408
|
}
|
367
409
|
|
@@ -381,53 +423,52 @@ static VALUE NIO_Selector_is_registered(VALUE self, VALUE io)
|
|
381
423
|
static VALUE NIO_Selector_select(int argc, VALUE *argv, VALUE self)
|
382
424
|
{
|
383
425
|
VALUE timeout;
|
384
|
-
VALUE args[2];
|
385
426
|
|
386
427
|
rb_scan_args(argc, argv, "01", &timeout);
|
387
428
|
|
388
|
-
if(timeout != Qnil && NUM2DBL(timeout) < 0) {
|
429
|
+
if (timeout != Qnil && NUM2DBL(timeout) < 0) {
|
389
430
|
rb_raise(rb_eArgError, "time interval must be positive");
|
390
431
|
}
|
391
432
|
|
392
|
-
args[
|
393
|
-
|
394
|
-
|
395
|
-
return NIO_Selector_synchronize(self, NIO_Selector_select_synchronized, args);
|
433
|
+
VALUE args[2] = {self, timeout};
|
434
|
+
return NIO_Selector_synchronize(self, NIO_Selector_select_synchronized, (VALUE)args);
|
396
435
|
}
|
397
436
|
|
398
437
|
/* Internal implementation of select with the selector lock held */
|
399
|
-
static VALUE NIO_Selector_select_synchronized(VALUE
|
438
|
+
static VALUE NIO_Selector_select_synchronized(VALUE _args)
|
400
439
|
{
|
401
440
|
int ready;
|
402
441
|
VALUE ready_array;
|
403
442
|
struct NIO_Selector *selector;
|
404
443
|
|
405
|
-
|
444
|
+
VALUE *args = (VALUE *)_args;
|
445
|
+
|
446
|
+
TypedData_Get_Struct(args[0], struct NIO_Selector, &NIO_Selector_type, selector);
|
406
447
|
|
407
|
-
if(selector->closed) {
|
448
|
+
if (selector->closed) {
|
408
449
|
rb_raise(rb_eIOError, "selector is closed");
|
409
450
|
}
|
410
451
|
|
411
|
-
if(!rb_block_given_p()) {
|
412
|
-
selector->ready_array
|
452
|
+
if (!rb_block_given_p()) {
|
453
|
+
RB_OBJ_WRITE(args[0], &selector->ready_array, rb_ary_new());
|
413
454
|
}
|
414
455
|
|
415
456
|
ready = NIO_Selector_run(selector, args[1]);
|
416
457
|
|
417
458
|
/* Timeout */
|
418
|
-
if(ready < 0) {
|
419
|
-
if(!rb_block_given_p()) {
|
420
|
-
selector->ready_array
|
459
|
+
if (ready < 0) {
|
460
|
+
if (!rb_block_given_p()) {
|
461
|
+
RB_OBJ_WRITE(args[0], &selector->ready_array, Qnil);
|
421
462
|
}
|
422
463
|
|
423
464
|
return Qnil;
|
424
465
|
}
|
425
466
|
|
426
|
-
if(rb_block_given_p()) {
|
467
|
+
if (rb_block_given_p()) {
|
427
468
|
return INT2NUM(ready);
|
428
469
|
} else {
|
429
470
|
ready_array = selector->ready_array;
|
430
|
-
selector->ready_array
|
471
|
+
RB_OBJ_WRITE(args[0], &selector->ready_array, Qnil);
|
431
472
|
return ready_array;
|
432
473
|
}
|
433
474
|
}
|
@@ -441,12 +482,12 @@ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
|
|
441
482
|
selector->selecting = 1;
|
442
483
|
selector->wakeup_fired = 0;
|
443
484
|
|
444
|
-
if(timeout == Qnil) {
|
485
|
+
if (timeout == Qnil) {
|
445
486
|
/* Don't fire a wakeup timeout if we weren't passed one */
|
446
487
|
ev_timer_stop(selector->ev_loop, &selector->timer);
|
447
488
|
} else {
|
448
489
|
timeout_val = NUM2DBL(timeout);
|
449
|
-
if(timeout_val == 0) {
|
490
|
+
if (timeout_val == 0) {
|
450
491
|
/* If we've been given an explicit timeout of 0, perform a non-blocking
|
451
492
|
select operation */
|
452
493
|
ev_run_flags = EVRUN_NOWAIT;
|
@@ -462,7 +503,7 @@ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
|
|
462
503
|
result = selector->ready_count;
|
463
504
|
selector->selecting = selector->ready_count = 0;
|
464
505
|
|
465
|
-
if(result > 0 || selector->wakeup_fired) {
|
506
|
+
if (result > 0 || selector->wakeup_fired) {
|
466
507
|
selector->wakeup_fired = 0;
|
467
508
|
return result;
|
468
509
|
} else {
|
@@ -474,9 +515,9 @@ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
|
|
474
515
|
static VALUE NIO_Selector_wakeup(VALUE self)
|
475
516
|
{
|
476
517
|
struct NIO_Selector *selector;
|
477
|
-
|
518
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
478
519
|
|
479
|
-
if(selector->closed) {
|
520
|
+
if (selector->closed) {
|
480
521
|
rb_raise(rb_eIOError, "selector is closed");
|
481
522
|
}
|
482
523
|
|
@@ -489,15 +530,14 @@ static VALUE NIO_Selector_wakeup(VALUE self)
|
|
489
530
|
/* Close the selector and free system resources */
|
490
531
|
static VALUE NIO_Selector_close(VALUE self)
|
491
532
|
{
|
492
|
-
|
493
|
-
return NIO_Selector_synchronize(self, NIO_Selector_close_synchronized, args);
|
533
|
+
return NIO_Selector_synchronize(self, NIO_Selector_close_synchronized, self);
|
494
534
|
}
|
495
535
|
|
496
|
-
static VALUE NIO_Selector_close_synchronized(VALUE
|
536
|
+
static VALUE NIO_Selector_close_synchronized(VALUE self)
|
497
537
|
{
|
498
538
|
struct NIO_Selector *selector;
|
499
|
-
|
500
|
-
|
539
|
+
|
540
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
501
541
|
|
502
542
|
NIO_Selector_shutdown(selector);
|
503
543
|
|
@@ -507,15 +547,14 @@ static VALUE NIO_Selector_close_synchronized(VALUE *args)
|
|
507
547
|
/* Is the selector closed? */
|
508
548
|
static VALUE NIO_Selector_closed(VALUE self)
|
509
549
|
{
|
510
|
-
|
511
|
-
return NIO_Selector_synchronize(self, NIO_Selector_closed_synchronized, args);
|
550
|
+
return NIO_Selector_synchronize(self, NIO_Selector_closed_synchronized, self);
|
512
551
|
}
|
513
552
|
|
514
|
-
static VALUE NIO_Selector_closed_synchronized(VALUE
|
553
|
+
static VALUE NIO_Selector_closed_synchronized(VALUE self)
|
515
554
|
{
|
516
555
|
struct NIO_Selector *selector;
|
517
|
-
|
518
|
-
|
556
|
+
|
557
|
+
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
|
519
558
|
|
520
559
|
return selector->closed ? Qtrue : Qfalse;
|
521
560
|
}
|
@@ -528,7 +567,6 @@ static VALUE NIO_Selector_is_empty(VALUE self)
|
|
528
567
|
return rb_funcall(selectables, rb_intern("empty?"), 0) == Qtrue ? Qtrue : Qfalse;
|
529
568
|
}
|
530
569
|
|
531
|
-
|
532
570
|
/* Called whenever a timeout fires on the event loop */
|
533
571
|
static void NIO_Selector_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents)
|
534
572
|
{
|
@@ -542,7 +580,8 @@ static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *
|
|
542
580
|
selector->selecting = 0;
|
543
581
|
|
544
582
|
/* Drain the wakeup pipe, giving us level-triggered behavior */
|
545
|
-
while(read(selector->wakeup_reader, buffer, 128) > 0)
|
583
|
+
while (read(selector->wakeup_reader, buffer, 128) > 0)
|
584
|
+
;
|
546
585
|
}
|
547
586
|
|
548
587
|
/* libev callback fired whenever a monitor gets an event */
|
@@ -558,7 +597,7 @@ void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, in
|
|
558
597
|
selector->ready_count++;
|
559
598
|
monitor_data->revents = revents;
|
560
599
|
|
561
|
-
if(rb_block_given_p()) {
|
600
|
+
if (rb_block_given_p()) {
|
562
601
|
rb_yield(monitor);
|
563
602
|
} else {
|
564
603
|
assert(selector->ready_array != Qnil);
|
data/lib/nio/bytebuffer.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2016, by Upekshe Jayasekera.
|
5
|
+
# Copyright, 2016-2017, by Tony Arcieri.
|
6
|
+
# Copyright, 2020, by Thomas Dziedzic.
|
7
|
+
# Copyright, 2023, by Samuel Williams.
|
8
|
+
|
3
9
|
module NIO
|
4
10
|
# Efficient byte buffers for performant I/O operations
|
5
11
|
class ByteBuffer
|
@@ -24,6 +30,7 @@ module NIO
|
|
24
30
|
# @return [NIO::ByteBuffer]
|
25
31
|
def initialize(capacity)
|
26
32
|
raise TypeError, "no implicit conversion of #{capacity.class} to Integer" unless capacity.is_a?(Integer)
|
33
|
+
|
27
34
|
@capacity = capacity
|
28
35
|
clear
|
29
36
|
end
|
@@ -119,9 +126,11 @@ module NIO
|
|
119
126
|
# @return [self]
|
120
127
|
def put(str)
|
121
128
|
raise TypeError, "expected String, got #{str.class}" unless str.respond_to?(:to_str)
|
129
|
+
|
122
130
|
str = str.to_str
|
123
131
|
|
124
132
|
raise OverflowError, "buffer is full" if str.length > @limit - @position
|
133
|
+
|
125
134
|
@buffer[@position...str.length] = str
|
126
135
|
@position += str.length
|
127
136
|
self
|
@@ -188,6 +197,7 @@ module NIO
|
|
188
197
|
# @raise [NIO::ByteBuffer::MarkUnsetError] mark has not been set (call `#mark` first)
|
189
198
|
def reset
|
190
199
|
raise MarkUnsetError, "mark has not been set" unless @mark
|
200
|
+
|
191
201
|
@position = @mark
|
192
202
|
self
|
193
203
|
end
|
data/lib/nio/monitor.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2011-2018, by Tony Arcieri.
|
5
|
+
# Copyright, 2015, by Upekshe Jayasekera.
|
6
|
+
# Copyright, 2015, by Vladimir Kochnev.
|
7
|
+
# Copyright, 2018-2023, by Samuel Williams.
|
8
|
+
# Copyright, 2019-2020, by Gregory Longtin.
|
9
|
+
|
3
10
|
module NIO
|
4
11
|
# Monitors watch IO objects for specific events
|
5
12
|
class Monitor
|
@@ -8,7 +15,7 @@ module NIO
|
|
8
15
|
|
9
16
|
# :nodoc:
|
10
17
|
def initialize(io, interests, selector)
|
11
|
-
unless io.is_a?
|
18
|
+
unless defined?(::OpenSSL) && io.is_a?(::OpenSSL::SSL::SSLSocket)
|
12
19
|
unless io.is_a?(IO)
|
13
20
|
if IO.respond_to? :try_convert
|
14
21
|
io = IO.try_convert(io)
|
data/lib/nio/selector.rb
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# Released under the MIT License.
|
4
|
+
# Copyright, 2011-2017, by Tony Arcieri.
|
5
|
+
# Copyright, 2012, by Logan Bowers.
|
6
|
+
# Copyright, 2013, by Sadayuki Furuhashi.
|
7
|
+
# Copyright, 2013, by Stephen von Takach.
|
8
|
+
# Copyright, 2013, by Tim Carey-Smith.
|
9
|
+
# Copyright, 2013, by Ravil Bayramgalin.
|
10
|
+
# Copyright, 2014, by Sergey Avseyev.
|
11
|
+
# Copyright, 2014, by John Thornton.
|
12
|
+
# Copyright, 2015, by Vladimir Kochnev.
|
13
|
+
# Copyright, 2015, by Upekshe Jayasekera.
|
14
|
+
# Copyright, 2019-2020, by Gregory Longtin.
|
15
|
+
# Copyright, 2020-2021, by Joao Fernandes.
|
16
|
+
# Copyright, 2023, by Samuel Williams.
|
17
|
+
|
3
18
|
require "set"
|
4
19
|
|
5
20
|
module NIO
|
@@ -14,7 +29,7 @@ module NIO
|
|
14
29
|
|
15
30
|
# Create a new NIO::Selector
|
16
31
|
def initialize(backend = :ruby)
|
17
|
-
raise ArgumentError, "unsupported backend: #{backend}" unless
|
32
|
+
raise ArgumentError, "unsupported backend: #{backend}" unless [:ruby, nil].include?(backend)
|
18
33
|
|
19
34
|
@selectables = {}
|
20
35
|
@lock = Mutex.new
|
@@ -26,14 +41,16 @@ module NIO
|
|
26
41
|
|
27
42
|
# Return a symbol representing the backend I/O multiplexing mechanism used.
|
28
43
|
# Supported backends are:
|
29
|
-
# * :ruby
|
30
|
-
# * :java
|
31
|
-
# * :epoll
|
32
|
-
# * :poll
|
33
|
-
# * :kqueue
|
34
|
-
# * :select
|
35
|
-
# * :port
|
36
|
-
# * :
|
44
|
+
# * :ruby - pure Ruby (i.e IO.select)
|
45
|
+
# * :java - Java NIO on JRuby
|
46
|
+
# * :epoll - libev w\ Linux epoll
|
47
|
+
# * :poll - libev w\ POSIX poll
|
48
|
+
# * :kqueue - libev w\ BSD kqueue
|
49
|
+
# * :select - libev w\ SysV select
|
50
|
+
# * :port - libev w\ I/O completion ports
|
51
|
+
# * :linuxaio - libev w\ Linux AIO io_submit (experimental)
|
52
|
+
# * :io_uring - libev w\ Linux io_uring (experimental)
|
53
|
+
# * :unknown - libev w\ unknown backend
|
37
54
|
def backend
|
38
55
|
:ruby
|
39
56
|
end
|
@@ -44,7 +61,7 @@ module NIO
|
|
44
61
|
# * :w - is the IO writeable?
|
45
62
|
# * :rw - is the IO either readable or writeable?
|
46
63
|
def register(io, interest)
|
47
|
-
unless io.is_a?
|
64
|
+
unless defined?(::OpenSSL) && io.is_a?(::OpenSSL::SSL::SSLSocket)
|
48
65
|
io = IO.try_convert(io)
|
49
66
|
end
|
50
67
|
|
data/lib/nio/version.rb
CHANGED