event 0.4.2 → 0.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/ext/event/Makefile +267 -0
- data/ext/event/backend.o +0 -0
- data/ext/event/backend/backend.c +178 -0
- data/ext/event/backend/backend.h +84 -1
- data/ext/event/backend/epoll.c +251 -13
- data/ext/event/backend/kqueue.c +288 -18
- data/ext/event/backend/pidfd.c +36 -0
- data/ext/event/backend/uring.c +336 -130
- data/ext/event/event.bundle +0 -0
- data/ext/event/event.c +3 -0
- data/ext/event/event.h +3 -3
- data/ext/event/event.o +0 -0
- data/ext/event/extconf.h +4 -0
- data/ext/event/extconf.rb +8 -1
- data/ext/event/kqueue.o +0 -0
- data/ext/event/mkmf.log +195 -0
- data/lib/event/backend/select.rb +90 -1
- data/lib/event/version.rb +1 -1
- metadata +12 -3
data/ext/event/backend/backend.h
CHANGED
@@ -18,6 +18,16 @@
|
|
18
18
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
// THE SOFTWARE.
|
20
20
|
|
21
|
+
#include <ruby.h>
|
22
|
+
#include <ruby/thread.h>
|
23
|
+
#include <ruby/io.h>
|
24
|
+
|
25
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
26
|
+
#include <ruby/io/buffer.h>
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#include <time.h>
|
30
|
+
|
21
31
|
enum Event {
|
22
32
|
READABLE = 1,
|
23
33
|
PRIORITY = 2,
|
@@ -26,4 +36,77 @@ enum Event {
|
|
26
36
|
HANGUP = 16
|
27
37
|
};
|
28
38
|
|
29
|
-
|
39
|
+
void Init_Event_Backend();
|
40
|
+
|
41
|
+
#ifdef HAVE__RB_FIBER_TRANSFER
|
42
|
+
#define Event_Backend_fiber_transfer(fiber) rb_fiber_transfer(fiber, 0, NULL)
|
43
|
+
#define Event_Backend_fiber_transfer_result(fiber, argument) rb_fiber_transfer(fiber, 1, &argument)
|
44
|
+
#else
|
45
|
+
VALUE Event_Backend_fiber_transfer(VALUE fiber);
|
46
|
+
VALUE Event_Backend_fiber_transfer_result(VALUE fiber, VALUE argument);
|
47
|
+
#endif
|
48
|
+
|
49
|
+
#ifdef HAVE_RB_IO_DESCRIPTOR
|
50
|
+
#define Event_Backend_io_descriptor(io) rb_io_descriptor(io)
|
51
|
+
#else
|
52
|
+
int Event_Backend_io_descriptor(VALUE io);
|
53
|
+
#endif
|
54
|
+
|
55
|
+
#ifdef HAVE_RB_PROCESS_STATUS_WAIT
|
56
|
+
#define Event_Backend_process_status_wait(pid) rb_process_status_wait(pid)
|
57
|
+
#else
|
58
|
+
VALUE Event_Backend_process_status_wait(rb_pid_t pid);
|
59
|
+
#endif
|
60
|
+
|
61
|
+
int Event_Backend_nonblock_set(int file_descriptor);
|
62
|
+
void Event_Backend_nonblock_restore(int file_descriptor, int flags);
|
63
|
+
|
64
|
+
struct Event_Backend_Queue {
|
65
|
+
struct Event_Backend_Queue *behind;
|
66
|
+
struct Event_Backend_Queue *infront;
|
67
|
+
|
68
|
+
VALUE fiber;
|
69
|
+
};
|
70
|
+
|
71
|
+
struct Event_Backend {
|
72
|
+
VALUE loop;
|
73
|
+
|
74
|
+
// Append to waiting.
|
75
|
+
struct Event_Backend_Queue *waiting;
|
76
|
+
// Process from ready.
|
77
|
+
struct Event_Backend_Queue *ready;
|
78
|
+
};
|
79
|
+
|
80
|
+
inline
|
81
|
+
void Event_Backend_initialize(struct Event_Backend *backend, VALUE loop) {
|
82
|
+
backend->loop = loop;
|
83
|
+
backend->waiting = NULL;
|
84
|
+
backend->ready = NULL;
|
85
|
+
}
|
86
|
+
|
87
|
+
inline
|
88
|
+
void Event_Backend_mark(struct Event_Backend *backend) {
|
89
|
+
rb_gc_mark(backend->loop);
|
90
|
+
|
91
|
+
struct Event_Backend_Queue *ready = backend->ready;
|
92
|
+
while (ready) {
|
93
|
+
rb_gc_mark(ready->fiber);
|
94
|
+
ready = ready->behind;
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
void Event_Backend_wait_and_transfer(struct Event_Backend *backend, VALUE fiber);
|
99
|
+
|
100
|
+
inline
|
101
|
+
void Event_Backend_defer(struct Event_Backend *backend)
|
102
|
+
{
|
103
|
+
Event_Backend_wait_and_transfer(backend, backend->loop);
|
104
|
+
}
|
105
|
+
|
106
|
+
void Event_Backend_ready_pop(struct Event_Backend *backend);
|
107
|
+
|
108
|
+
void Event_Backend_elapsed_time(struct timespec* start, struct timespec* stop, struct timespec *duration);
|
109
|
+
void Event_Backend_current_time(struct timespec *time);
|
110
|
+
|
111
|
+
#define PRINTF_TIMESPEC "%lld.%.9ld"
|
112
|
+
#define PRINTF_TIMESPEC_ARGS(ts) (long long)((ts).tv_sec), (ts).tv_nsec
|
data/ext/event/backend/epoll.c
CHANGED
@@ -25,20 +25,21 @@
|
|
25
25
|
#include <time.h>
|
26
26
|
#include <errno.h>
|
27
27
|
|
28
|
+
#include "pidfd.c"
|
29
|
+
|
28
30
|
static VALUE Event_Backend_EPoll = Qnil;
|
29
|
-
static ID id_fileno, id_transfer;
|
30
31
|
|
31
32
|
enum {EPOLL_MAX_EVENTS = 64};
|
32
33
|
|
33
34
|
struct Event_Backend_EPoll {
|
34
|
-
|
35
|
+
struct Event_Backend backend;
|
35
36
|
int descriptor;
|
36
37
|
};
|
37
38
|
|
38
39
|
void Event_Backend_EPoll_Type_mark(void *_data)
|
39
40
|
{
|
40
41
|
struct Event_Backend_EPoll *data = _data;
|
41
|
-
|
42
|
+
Event_Backend_mark(&data->backend);
|
42
43
|
}
|
43
44
|
|
44
45
|
static
|
@@ -78,7 +79,7 @@ VALUE Event_Backend_EPoll_allocate(VALUE self) {
|
|
78
79
|
struct Event_Backend_EPoll *data = NULL;
|
79
80
|
VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
80
81
|
|
81
|
-
data->
|
82
|
+
Event_Backend_initialize(&data->backend, Qnil);
|
82
83
|
data->descriptor = -1;
|
83
84
|
|
84
85
|
return instance;
|
@@ -88,7 +89,7 @@ VALUE Event_Backend_EPoll_initialize(VALUE self, VALUE loop) {
|
|
88
89
|
struct Event_Backend_EPoll *data = NULL;
|
89
90
|
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
90
91
|
|
91
|
-
data->
|
92
|
+
Event_Backend_initialize(&data->backend, loop);
|
92
93
|
int result = epoll_create1(EPOLL_CLOEXEC);
|
93
94
|
|
94
95
|
if (result == -1) {
|
@@ -111,6 +112,87 @@ VALUE Event_Backend_EPoll_close(VALUE self) {
|
|
111
112
|
return Qnil;
|
112
113
|
}
|
113
114
|
|
115
|
+
VALUE Event_Backend_EPoll_transfer(VALUE self, VALUE fiber)
|
116
|
+
{
|
117
|
+
struct Event_Backend_EPoll *data = NULL;
|
118
|
+
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
119
|
+
|
120
|
+
Event_Backend_wait_and_transfer(&data->backend, fiber);
|
121
|
+
|
122
|
+
return Qnil;
|
123
|
+
}
|
124
|
+
|
125
|
+
VALUE Event_Backend_EPoll_defer(VALUE self)
|
126
|
+
{
|
127
|
+
struct Event_Backend_EPoll *data = NULL;
|
128
|
+
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
129
|
+
|
130
|
+
Event_Backend_defer(&data->backend);
|
131
|
+
|
132
|
+
return Qnil;
|
133
|
+
}
|
134
|
+
|
135
|
+
VALUE Event_Backend_EPoll_ready_p(VALUE self) {
|
136
|
+
struct Event_Backend_EPoll *data = NULL;
|
137
|
+
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
138
|
+
|
139
|
+
return data->backend.ready ? Qtrue : Qfalse;
|
140
|
+
}
|
141
|
+
|
142
|
+
struct process_wait_arguments {
|
143
|
+
struct Event_Backend_EPoll *data;
|
144
|
+
pid_t pid;
|
145
|
+
int flags;
|
146
|
+
int descriptor;
|
147
|
+
};
|
148
|
+
|
149
|
+
static
|
150
|
+
VALUE process_wait_transfer(VALUE _arguments) {
|
151
|
+
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
152
|
+
|
153
|
+
Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
154
|
+
|
155
|
+
return Event_Backend_process_status_wait(arguments->pid);
|
156
|
+
}
|
157
|
+
|
158
|
+
static
|
159
|
+
VALUE process_wait_ensure(VALUE _arguments) {
|
160
|
+
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
161
|
+
|
162
|
+
// epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);
|
163
|
+
|
164
|
+
close(arguments->descriptor);
|
165
|
+
|
166
|
+
return Qnil;
|
167
|
+
}
|
168
|
+
|
169
|
+
VALUE Event_Backend_EPoll_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
|
170
|
+
struct Event_Backend_EPoll *data = NULL;
|
171
|
+
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
172
|
+
|
173
|
+
struct process_wait_arguments process_wait_arguments = {
|
174
|
+
.data = data,
|
175
|
+
.pid = NUM2PIDT(pid),
|
176
|
+
.flags = NUM2INT(flags),
|
177
|
+
};
|
178
|
+
|
179
|
+
process_wait_arguments.descriptor = pidfd_open(process_wait_arguments.pid, 0);
|
180
|
+
rb_update_max_fd(process_wait_arguments.descriptor);
|
181
|
+
|
182
|
+
struct epoll_event event = {
|
183
|
+
.events = EPOLLIN|EPOLLRDHUP|EPOLLONESHOT,
|
184
|
+
.data = {.ptr = (void*)fiber},
|
185
|
+
};
|
186
|
+
|
187
|
+
int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, process_wait_arguments.descriptor, &event);
|
188
|
+
|
189
|
+
if (result == -1) {
|
190
|
+
rb_sys_fail("epoll_ctl(process_wait)");
|
191
|
+
}
|
192
|
+
|
193
|
+
return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
|
194
|
+
}
|
195
|
+
|
114
196
|
static inline
|
115
197
|
uint32_t epoll_flags_from_events(int events) {
|
116
198
|
uint32_t flags = 0;
|
@@ -161,7 +243,7 @@ static
|
|
161
243
|
VALUE io_wait_transfer(VALUE _arguments) {
|
162
244
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
163
245
|
|
164
|
-
VALUE result =
|
246
|
+
VALUE result = Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
165
247
|
|
166
248
|
return INT2NUM(events_from_epoll_flags(NUM2INT(result)));
|
167
249
|
};
|
@@ -172,7 +254,7 @@ VALUE Event_Backend_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE event
|
|
172
254
|
|
173
255
|
struct epoll_event event = {0};
|
174
256
|
|
175
|
-
int descriptor =
|
257
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
176
258
|
int duplicate = -1;
|
177
259
|
|
178
260
|
event.events = epoll_flags_from_events(NUM2INT(events));
|
@@ -208,6 +290,153 @@ VALUE Event_Backend_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE event
|
|
208
290
|
return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
|
209
291
|
}
|
210
292
|
|
293
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
294
|
+
|
295
|
+
struct io_read_arguments {
|
296
|
+
VALUE self;
|
297
|
+
VALUE fiber;
|
298
|
+
VALUE io;
|
299
|
+
|
300
|
+
int flags;
|
301
|
+
|
302
|
+
int descriptor;
|
303
|
+
|
304
|
+
VALUE buffer;
|
305
|
+
size_t length;
|
306
|
+
};
|
307
|
+
|
308
|
+
static
|
309
|
+
VALUE io_read_loop(VALUE _arguments) {
|
310
|
+
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
311
|
+
|
312
|
+
void *base;
|
313
|
+
size_t size;
|
314
|
+
rb_io_buffer_get_mutable(arguments->buffer, &base, &size);
|
315
|
+
|
316
|
+
size_t offset = 0;
|
317
|
+
size_t length = arguments->length;
|
318
|
+
|
319
|
+
while (length > 0) {
|
320
|
+
size_t maximum_size = size - offset;
|
321
|
+
ssize_t result = read(arguments->descriptor, (char*)base+offset, maximum_size);
|
322
|
+
|
323
|
+
if (result == 0) {
|
324
|
+
break;
|
325
|
+
} else if (result > 0) {
|
326
|
+
offset += result;
|
327
|
+
length -= result;
|
328
|
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
329
|
+
Event_Backend_EPoll_io_wait(arguments->self, arguments->fiber, arguments->io, RB_INT2NUM(READABLE));
|
330
|
+
} else {
|
331
|
+
rb_sys_fail("Event_Backend_EPoll_io_read");
|
332
|
+
}
|
333
|
+
}
|
334
|
+
|
335
|
+
return SIZET2NUM(offset);
|
336
|
+
}
|
337
|
+
|
338
|
+
static
|
339
|
+
VALUE io_read_ensure(VALUE _arguments) {
|
340
|
+
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
341
|
+
|
342
|
+
Event_Backend_nonblock_restore(arguments->descriptor, arguments->flags);
|
343
|
+
|
344
|
+
return Qnil;
|
345
|
+
}
|
346
|
+
|
347
|
+
VALUE Event_Backend_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
348
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
349
|
+
|
350
|
+
size_t length = NUM2SIZET(_length);
|
351
|
+
|
352
|
+
struct io_read_arguments io_read_arguments = {
|
353
|
+
.self = self,
|
354
|
+
.fiber = fiber,
|
355
|
+
.io = io,
|
356
|
+
|
357
|
+
.flags = Event_Backend_nonblock_set(descriptor),
|
358
|
+
.descriptor = descriptor,
|
359
|
+
.buffer = buffer,
|
360
|
+
.length = length,
|
361
|
+
};
|
362
|
+
|
363
|
+
return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
|
364
|
+
}
|
365
|
+
|
366
|
+
struct io_write_arguments {
|
367
|
+
VALUE self;
|
368
|
+
VALUE fiber;
|
369
|
+
VALUE io;
|
370
|
+
|
371
|
+
int flags;
|
372
|
+
|
373
|
+
int descriptor;
|
374
|
+
|
375
|
+
VALUE buffer;
|
376
|
+
size_t length;
|
377
|
+
};
|
378
|
+
|
379
|
+
static
|
380
|
+
VALUE io_write_loop(VALUE _arguments) {
|
381
|
+
struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
|
382
|
+
|
383
|
+
const void *base;
|
384
|
+
size_t size;
|
385
|
+
rb_io_buffer_get_immutable(arguments->buffer, &base, &size);
|
386
|
+
|
387
|
+
size_t offset = 0;
|
388
|
+
size_t length = arguments->length;
|
389
|
+
|
390
|
+
if (length > size) {
|
391
|
+
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
392
|
+
}
|
393
|
+
|
394
|
+
while (length > 0) {
|
395
|
+
ssize_t result = write(arguments->descriptor, (char*)base+offset, length);
|
396
|
+
|
397
|
+
if (result >= 0) {
|
398
|
+
offset += result;
|
399
|
+
length -= result;
|
400
|
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
401
|
+
Event_Backend_EPoll_io_wait(arguments->self, arguments->fiber, arguments->io, RB_INT2NUM(WRITABLE));
|
402
|
+
} else {
|
403
|
+
rb_sys_fail("Event_Backend_EPoll_io_write");
|
404
|
+
}
|
405
|
+
}
|
406
|
+
|
407
|
+
return SIZET2NUM(offset);
|
408
|
+
};
|
409
|
+
|
410
|
+
static
|
411
|
+
VALUE io_write_ensure(VALUE _arguments) {
|
412
|
+
struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
|
413
|
+
|
414
|
+
Event_Backend_nonblock_restore(arguments->descriptor, arguments->flags);
|
415
|
+
|
416
|
+
return Qnil;
|
417
|
+
};
|
418
|
+
|
419
|
+
VALUE Event_Backend_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
420
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
421
|
+
|
422
|
+
size_t length = NUM2SIZET(_length);
|
423
|
+
|
424
|
+
struct io_write_arguments io_write_arguments = {
|
425
|
+
.self = self,
|
426
|
+
.fiber = fiber,
|
427
|
+
.io = io,
|
428
|
+
|
429
|
+
.flags = Event_Backend_nonblock_set(descriptor),
|
430
|
+
.descriptor = descriptor,
|
431
|
+
.buffer = buffer,
|
432
|
+
.length = length,
|
433
|
+
};
|
434
|
+
|
435
|
+
return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
|
436
|
+
}
|
437
|
+
|
438
|
+
#endif
|
439
|
+
|
211
440
|
static
|
212
441
|
int make_timeout(VALUE duration) {
|
213
442
|
if (duration == Qnil) {
|
@@ -267,6 +496,8 @@ VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
|
|
267
496
|
struct Event_Backend_EPoll *data = NULL;
|
268
497
|
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
|
269
498
|
|
499
|
+
Event_Backend_ready_pop(&data->backend);
|
500
|
+
|
270
501
|
struct select_arguments arguments = {
|
271
502
|
.data = data,
|
272
503
|
.timeout = 0
|
@@ -277,7 +508,7 @@ VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
|
|
277
508
|
if (arguments.count == 0) {
|
278
509
|
arguments.timeout = make_timeout(duration);
|
279
510
|
|
280
|
-
if (arguments.timeout != 0) {
|
511
|
+
if (!data->backend.ready && arguments.timeout != 0) {
|
281
512
|
select_internal_without_gvl(&arguments);
|
282
513
|
}
|
283
514
|
}
|
@@ -288,22 +519,29 @@ VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
|
|
288
519
|
|
289
520
|
// fprintf(stderr, "-> fiber=%p descriptor=%d\n", (void*)fiber, events[i].data.fd);
|
290
521
|
|
291
|
-
|
522
|
+
Event_Backend_fiber_transfer_result(fiber, result);
|
292
523
|
}
|
293
524
|
|
294
525
|
return INT2NUM(arguments.count);
|
295
526
|
}
|
296
527
|
|
297
528
|
void Init_Event_Backend_EPoll(VALUE Event_Backend) {
|
298
|
-
id_fileno = rb_intern("fileno");
|
299
|
-
id_transfer = rb_intern("transfer");
|
300
|
-
|
301
529
|
Event_Backend_EPoll = rb_define_class_under(Event_Backend, "EPoll", rb_cObject);
|
302
530
|
|
303
531
|
rb_define_alloc_func(Event_Backend_EPoll, Event_Backend_EPoll_allocate);
|
304
532
|
rb_define_method(Event_Backend_EPoll, "initialize", Event_Backend_EPoll_initialize, 1);
|
533
|
+
rb_define_method(Event_Backend_EPoll, "transfer", Event_Backend_EPoll_transfer, 1);
|
534
|
+
rb_define_method(Event_Backend_EPoll, "defer", Event_Backend_EPoll_defer, 0);
|
535
|
+
rb_define_method(Event_Backend_EPoll, "ready?", Event_Backend_EPoll_ready_p, 0);
|
536
|
+
rb_define_method(Event_Backend_EPoll, "select", Event_Backend_EPoll_select, 1);
|
305
537
|
rb_define_method(Event_Backend_EPoll, "close", Event_Backend_EPoll_close, 0);
|
306
538
|
|
307
539
|
rb_define_method(Event_Backend_EPoll, "io_wait", Event_Backend_EPoll_io_wait, 3);
|
308
|
-
|
540
|
+
|
541
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
542
|
+
rb_define_method(Event_Backend_EPoll, "io_read", Event_Backend_EPoll_io_read, 4);
|
543
|
+
rb_define_method(Event_Backend_EPoll, "io_write", Event_Backend_EPoll_io_write, 4);
|
544
|
+
#endif
|
545
|
+
|
546
|
+
rb_define_method(Event_Backend_EPoll, "process_wait", Event_Backend_EPoll_process_wait, 3);
|
309
547
|
}
|
data/ext/event/backend/kqueue.c
CHANGED
@@ -24,21 +24,21 @@
|
|
24
24
|
#include <sys/event.h>
|
25
25
|
#include <sys/ioctl.h>
|
26
26
|
#include <time.h>
|
27
|
+
#include <errno.h>
|
27
28
|
|
28
29
|
static VALUE Event_Backend_KQueue = Qnil;
|
29
|
-
static ID id_fileno, id_transfer;
|
30
30
|
|
31
31
|
enum {KQUEUE_MAX_EVENTS = 64};
|
32
32
|
|
33
33
|
struct Event_Backend_KQueue {
|
34
|
-
|
34
|
+
struct Event_Backend backend;
|
35
35
|
int descriptor;
|
36
36
|
};
|
37
37
|
|
38
38
|
void Event_Backend_KQueue_Type_mark(void *_data)
|
39
39
|
{
|
40
40
|
struct Event_Backend_KQueue *data = _data;
|
41
|
-
|
41
|
+
Event_Backend_mark(&data->backend);
|
42
42
|
}
|
43
43
|
|
44
44
|
static
|
@@ -78,7 +78,7 @@ VALUE Event_Backend_KQueue_allocate(VALUE self) {
|
|
78
78
|
struct Event_Backend_KQueue *data = NULL;
|
79
79
|
VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
80
80
|
|
81
|
-
data->
|
81
|
+
Event_Backend_initialize(&data->backend, Qnil);
|
82
82
|
data->descriptor = -1;
|
83
83
|
|
84
84
|
return instance;
|
@@ -88,7 +88,7 @@ VALUE Event_Backend_KQueue_initialize(VALUE self, VALUE loop) {
|
|
88
88
|
struct Event_Backend_KQueue *data = NULL;
|
89
89
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
90
90
|
|
91
|
-
data->
|
91
|
+
Event_Backend_initialize(&data->backend, loop);
|
92
92
|
int result = kqueue();
|
93
93
|
|
94
94
|
if (result == -1) {
|
@@ -112,6 +112,113 @@ VALUE Event_Backend_KQueue_close(VALUE self) {
|
|
112
112
|
return Qnil;
|
113
113
|
}
|
114
114
|
|
115
|
+
VALUE Event_Backend_KQueue_transfer(VALUE self, VALUE fiber)
|
116
|
+
{
|
117
|
+
struct Event_Backend_KQueue *data = NULL;
|
118
|
+
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
119
|
+
|
120
|
+
Event_Backend_wait_and_transfer(&data->backend, fiber);
|
121
|
+
|
122
|
+
return Qnil;
|
123
|
+
}
|
124
|
+
|
125
|
+
VALUE Event_Backend_KQueue_defer(VALUE self)
|
126
|
+
{
|
127
|
+
struct Event_Backend_KQueue *data = NULL;
|
128
|
+
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
129
|
+
|
130
|
+
Event_Backend_defer(&data->backend);
|
131
|
+
|
132
|
+
return Qnil;
|
133
|
+
}
|
134
|
+
|
135
|
+
VALUE Event_Backend_KQueue_ready_p(VALUE self) {
|
136
|
+
struct Event_Backend_KQueue *data = NULL;
|
137
|
+
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
138
|
+
|
139
|
+
return data->backend.ready ? Qtrue : Qfalse;
|
140
|
+
}
|
141
|
+
|
142
|
+
struct process_wait_arguments {
|
143
|
+
struct Event_Backend_KQueue *data;
|
144
|
+
pid_t pid;
|
145
|
+
int flags;
|
146
|
+
};
|
147
|
+
|
148
|
+
static
|
149
|
+
int process_add_filters(int descriptor, int ident, VALUE fiber) {
|
150
|
+
struct kevent event = {0};
|
151
|
+
|
152
|
+
event.ident = ident;
|
153
|
+
event.filter = EVFILT_PROC;
|
154
|
+
event.flags = EV_ADD | EV_ENABLE | EV_ONESHOT;
|
155
|
+
event.fflags = NOTE_EXIT;
|
156
|
+
event.udata = (void*)fiber;
|
157
|
+
|
158
|
+
int result = kevent(descriptor, &event, 1, NULL, 0, NULL);
|
159
|
+
|
160
|
+
if (result == -1) {
|
161
|
+
// No such process - the process has probably already terminated:
|
162
|
+
if (errno == ESRCH) {
|
163
|
+
return 0;
|
164
|
+
}
|
165
|
+
|
166
|
+
rb_sys_fail("kevent(process_add_filters)");
|
167
|
+
}
|
168
|
+
|
169
|
+
return 1;
|
170
|
+
}
|
171
|
+
|
172
|
+
static
|
173
|
+
void process_remove_filters(int descriptor, int ident) {
|
174
|
+
struct kevent event = {0};
|
175
|
+
|
176
|
+
event.ident = ident;
|
177
|
+
event.filter = EVFILT_PROC;
|
178
|
+
event.flags = EV_DELETE;
|
179
|
+
event.fflags = NOTE_EXIT;
|
180
|
+
|
181
|
+
// Ignore the result.
|
182
|
+
kevent(descriptor, &event, 1, NULL, 0, NULL);
|
183
|
+
}
|
184
|
+
|
185
|
+
static
|
186
|
+
VALUE process_wait_transfer(VALUE _arguments) {
|
187
|
+
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
188
|
+
|
189
|
+
Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
190
|
+
|
191
|
+
return Event_Backend_process_status_wait(arguments->pid);
|
192
|
+
}
|
193
|
+
|
194
|
+
static
|
195
|
+
VALUE process_wait_rescue(VALUE _arguments, VALUE exception) {
|
196
|
+
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
197
|
+
|
198
|
+
process_remove_filters(arguments->data->descriptor, arguments->pid);
|
199
|
+
|
200
|
+
rb_exc_raise(exception);
|
201
|
+
}
|
202
|
+
|
203
|
+
VALUE Event_Backend_KQueue_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
|
204
|
+
struct Event_Backend_KQueue *data = NULL;
|
205
|
+
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
206
|
+
|
207
|
+
struct process_wait_arguments process_wait_arguments = {
|
208
|
+
.data = data,
|
209
|
+
.pid = NUM2PIDT(pid),
|
210
|
+
.flags = RB_NUM2INT(flags),
|
211
|
+
};
|
212
|
+
|
213
|
+
int waiting = process_add_filters(data->descriptor, process_wait_arguments.pid, fiber);
|
214
|
+
|
215
|
+
if (waiting) {
|
216
|
+
return rb_rescue(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_rescue, (VALUE)&process_wait_arguments);
|
217
|
+
} else {
|
218
|
+
return Event_Backend_process_status_wait(process_wait_arguments.pid);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
115
222
|
static
|
116
223
|
int io_add_filters(int descriptor, int ident, int events, VALUE fiber) {
|
117
224
|
int count = 0;
|
@@ -143,7 +250,7 @@ int io_add_filters(int descriptor, int ident, int events, VALUE fiber) {
|
|
143
250
|
int result = kevent(descriptor, kevents, count, NULL, 0, NULL);
|
144
251
|
|
145
252
|
if (result == -1) {
|
146
|
-
rb_sys_fail("kevent(
|
253
|
+
rb_sys_fail("kevent(io_add_filters)");
|
147
254
|
}
|
148
255
|
|
149
256
|
return events;
|
@@ -186,7 +293,7 @@ VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
|
|
186
293
|
io_remove_filters(arguments->data->descriptor, arguments->descriptor, arguments->events);
|
187
294
|
|
188
295
|
rb_exc_raise(exception);
|
189
|
-
}
|
296
|
+
}
|
190
297
|
|
191
298
|
static inline
|
192
299
|
int events_from_kqueue_filter(int filter) {
|
@@ -200,19 +307,19 @@ static
|
|
200
307
|
VALUE io_wait_transfer(VALUE _arguments) {
|
201
308
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
202
309
|
|
203
|
-
VALUE result =
|
310
|
+
VALUE result = Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
204
311
|
|
205
|
-
return INT2NUM(events_from_kqueue_filter(
|
206
|
-
}
|
312
|
+
return INT2NUM(events_from_kqueue_filter(RB_NUM2INT(result)));
|
313
|
+
}
|
207
314
|
|
208
315
|
VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
|
209
316
|
struct Event_Backend_KQueue *data = NULL;
|
210
317
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
211
318
|
|
212
|
-
int descriptor =
|
319
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
213
320
|
|
214
321
|
struct io_wait_arguments io_wait_arguments = {
|
215
|
-
.events = io_add_filters(data->descriptor, descriptor,
|
322
|
+
.events = io_add_filters(data->descriptor, descriptor, RB_NUM2INT(events), fiber),
|
216
323
|
.data = data,
|
217
324
|
.descriptor = descriptor,
|
218
325
|
};
|
@@ -220,6 +327,159 @@ VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE even
|
|
220
327
|
return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
|
221
328
|
}
|
222
329
|
|
330
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
331
|
+
|
332
|
+
struct io_read_arguments {
|
333
|
+
VALUE self;
|
334
|
+
VALUE fiber;
|
335
|
+
VALUE io;
|
336
|
+
|
337
|
+
int flags;
|
338
|
+
|
339
|
+
int descriptor;
|
340
|
+
|
341
|
+
VALUE buffer;
|
342
|
+
size_t length;
|
343
|
+
};
|
344
|
+
|
345
|
+
static
|
346
|
+
VALUE io_read_loop(VALUE _arguments) {
|
347
|
+
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
348
|
+
|
349
|
+
void *base;
|
350
|
+
size_t size;
|
351
|
+
rb_io_buffer_get_mutable(arguments->buffer, &base, &size);
|
352
|
+
|
353
|
+
size_t offset = 0;
|
354
|
+
size_t length = arguments->length;
|
355
|
+
|
356
|
+
while (length > 0) {
|
357
|
+
size_t maximum_size = size - offset;
|
358
|
+
ssize_t result = read(arguments->descriptor, (char*)base+offset, maximum_size);
|
359
|
+
|
360
|
+
if (result == 0) {
|
361
|
+
break;
|
362
|
+
} else if (result > 0) {
|
363
|
+
offset += result;
|
364
|
+
length -= result;
|
365
|
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
366
|
+
Event_Backend_KQueue_io_wait(arguments->self, arguments->fiber, arguments->io, RB_INT2NUM(READABLE));
|
367
|
+
} else {
|
368
|
+
rb_sys_fail("Event_Backend_KQueue_io_read");
|
369
|
+
}
|
370
|
+
}
|
371
|
+
|
372
|
+
return SIZET2NUM(offset);
|
373
|
+
}
|
374
|
+
|
375
|
+
static
|
376
|
+
VALUE io_read_ensure(VALUE _arguments) {
|
377
|
+
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
378
|
+
|
379
|
+
Event_Backend_nonblock_restore(arguments->descriptor, arguments->flags);
|
380
|
+
|
381
|
+
return Qnil;
|
382
|
+
}
|
383
|
+
|
384
|
+
VALUE Event_Backend_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
385
|
+
struct Event_Backend_KQueue *data = NULL;
|
386
|
+
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
387
|
+
|
388
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
389
|
+
|
390
|
+
size_t length = NUM2SIZET(_length);
|
391
|
+
|
392
|
+
struct io_read_arguments io_read_arguments = {
|
393
|
+
.self = self,
|
394
|
+
.fiber = fiber,
|
395
|
+
.io = io,
|
396
|
+
|
397
|
+
.flags = Event_Backend_nonblock_set(descriptor),
|
398
|
+
.descriptor = descriptor,
|
399
|
+
.buffer = buffer,
|
400
|
+
.length = length,
|
401
|
+
};
|
402
|
+
|
403
|
+
return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
|
404
|
+
}
|
405
|
+
|
406
|
+
struct io_write_arguments {
|
407
|
+
VALUE self;
|
408
|
+
VALUE fiber;
|
409
|
+
VALUE io;
|
410
|
+
|
411
|
+
int flags;
|
412
|
+
|
413
|
+
int descriptor;
|
414
|
+
|
415
|
+
VALUE buffer;
|
416
|
+
size_t length;
|
417
|
+
};
|
418
|
+
|
419
|
+
static
|
420
|
+
VALUE io_write_loop(VALUE _arguments) {
|
421
|
+
struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
|
422
|
+
|
423
|
+
const void *base;
|
424
|
+
size_t size;
|
425
|
+
rb_io_buffer_get_immutable(arguments->buffer, &base, &size);
|
426
|
+
|
427
|
+
size_t offset = 0;
|
428
|
+
size_t length = arguments->length;
|
429
|
+
|
430
|
+
if (length > size) {
|
431
|
+
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
432
|
+
}
|
433
|
+
|
434
|
+
while (length > 0) {
|
435
|
+
ssize_t result = write(arguments->descriptor, (char*)base+offset, length);
|
436
|
+
|
437
|
+
if (result >= 0) {
|
438
|
+
offset += result;
|
439
|
+
length -= result;
|
440
|
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
441
|
+
Event_Backend_KQueue_io_wait(arguments->self, arguments->fiber, arguments->io, RB_INT2NUM(WRITABLE));
|
442
|
+
} else {
|
443
|
+
rb_sys_fail("Event_Backend_KQueue_io_write");
|
444
|
+
}
|
445
|
+
}
|
446
|
+
|
447
|
+
return SIZET2NUM(offset);
|
448
|
+
};
|
449
|
+
|
450
|
+
static
|
451
|
+
VALUE io_write_ensure(VALUE _arguments) {
|
452
|
+
struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
|
453
|
+
|
454
|
+
Event_Backend_nonblock_restore(arguments->descriptor, arguments->flags);
|
455
|
+
|
456
|
+
return Qnil;
|
457
|
+
};
|
458
|
+
|
459
|
+
VALUE Event_Backend_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
460
|
+
struct Event_Backend_KQueue *data = NULL;
|
461
|
+
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
462
|
+
|
463
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
464
|
+
|
465
|
+
size_t length = NUM2SIZET(_length);
|
466
|
+
|
467
|
+
struct io_write_arguments io_write_arguments = {
|
468
|
+
.self = self,
|
469
|
+
.fiber = fiber,
|
470
|
+
.io = io,
|
471
|
+
|
472
|
+
.flags = Event_Backend_nonblock_set(descriptor),
|
473
|
+
.descriptor = descriptor,
|
474
|
+
.buffer = buffer,
|
475
|
+
.length = length,
|
476
|
+
};
|
477
|
+
|
478
|
+
return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
|
479
|
+
}
|
480
|
+
|
481
|
+
#endif
|
482
|
+
|
223
483
|
static
|
224
484
|
struct timespec * make_timeout(VALUE duration, struct timespec * storage) {
|
225
485
|
if (duration == Qnil) {
|
@@ -292,6 +552,8 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
|
|
292
552
|
struct Event_Backend_KQueue *data = NULL;
|
293
553
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
294
554
|
|
555
|
+
Event_Backend_ready_pop(&data->backend);
|
556
|
+
|
295
557
|
struct select_arguments arguments = {
|
296
558
|
.data = data,
|
297
559
|
.count = KQUEUE_MAX_EVENTS,
|
@@ -315,7 +577,7 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
|
|
315
577
|
if (arguments.count == 0) {
|
316
578
|
arguments.timeout = make_timeout(duration, &arguments.storage);
|
317
579
|
|
318
|
-
if (!timeout_nonblocking(arguments.timeout)) {
|
580
|
+
if (!data->backend.ready && !timeout_nonblocking(arguments.timeout)) {
|
319
581
|
arguments.count = KQUEUE_MAX_EVENTS;
|
320
582
|
|
321
583
|
select_internal_without_gvl(&arguments);
|
@@ -325,22 +587,30 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
|
|
325
587
|
for (int i = 0; i < arguments.count; i += 1) {
|
326
588
|
VALUE fiber = (VALUE)arguments.events[i].udata;
|
327
589
|
VALUE result = INT2NUM(arguments.events[i].filter);
|
328
|
-
|
590
|
+
|
591
|
+
Event_Backend_fiber_transfer_result(fiber, result);
|
329
592
|
}
|
330
593
|
|
331
594
|
return INT2NUM(arguments.count);
|
332
595
|
}
|
333
596
|
|
334
597
|
void Init_Event_Backend_KQueue(VALUE Event_Backend) {
|
335
|
-
id_fileno = rb_intern("fileno");
|
336
|
-
id_transfer = rb_intern("transfer");
|
337
|
-
|
338
598
|
Event_Backend_KQueue = rb_define_class_under(Event_Backend, "KQueue", rb_cObject);
|
339
599
|
|
340
600
|
rb_define_alloc_func(Event_Backend_KQueue, Event_Backend_KQueue_allocate);
|
341
601
|
rb_define_method(Event_Backend_KQueue, "initialize", Event_Backend_KQueue_initialize, 1);
|
602
|
+
rb_define_method(Event_Backend_KQueue, "transfer", Event_Backend_KQueue_transfer, 1);
|
603
|
+
rb_define_method(Event_Backend_KQueue, "defer", Event_Backend_KQueue_defer, 0);
|
604
|
+
rb_define_method(Event_Backend_KQueue, "ready?", Event_Backend_KQueue_ready_p, 0);
|
605
|
+
rb_define_method(Event_Backend_KQueue, "select", Event_Backend_KQueue_select, 1);
|
342
606
|
rb_define_method(Event_Backend_KQueue, "close", Event_Backend_KQueue_close, 0);
|
343
607
|
|
344
608
|
rb_define_method(Event_Backend_KQueue, "io_wait", Event_Backend_KQueue_io_wait, 3);
|
345
|
-
|
609
|
+
|
610
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
611
|
+
rb_define_method(Event_Backend_KQueue, "io_read", Event_Backend_KQueue_io_read, 4);
|
612
|
+
rb_define_method(Event_Backend_KQueue, "io_write", Event_Backend_KQueue_io_write, 4);
|
613
|
+
#endif
|
614
|
+
|
615
|
+
rb_define_method(Event_Backend_KQueue, "process_wait", Event_Backend_KQueue_process_wait, 3);
|
346
616
|
}
|