event 0.6.0 → 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/backend.o +0 -0
- data/ext/event/backend/backend.c +119 -49
- data/ext/event/backend/backend.h +75 -8
- data/ext/event/backend/epoll.c +78 -48
- data/ext/event/backend/kqueue.c +77 -40
- data/ext/event/backend/uring.c +220 -91
- data/ext/event/event.bundle +0 -0
- data/ext/event/event.o +0 -0
- data/ext/event/extconf.rb +5 -0
- data/ext/event/kqueue.o +0 -0
- data/ext/event/mkmf.log +95 -0
- data/lib/event/backend/select.rb +63 -35
- data/lib/event/version.rb +1 -1
- metadata +2 -2
data/ext/event/backend/kqueue.c
CHANGED
@@ -27,19 +27,18 @@
|
|
27
27
|
#include <errno.h>
|
28
28
|
|
29
29
|
static VALUE Event_Backend_KQueue = Qnil;
|
30
|
-
static ID id_fileno;
|
31
30
|
|
32
31
|
enum {KQUEUE_MAX_EVENTS = 64};
|
33
32
|
|
34
33
|
struct Event_Backend_KQueue {
|
35
|
-
|
34
|
+
struct Event_Backend backend;
|
36
35
|
int descriptor;
|
37
36
|
};
|
38
37
|
|
39
38
|
void Event_Backend_KQueue_Type_mark(void *_data)
|
40
39
|
{
|
41
40
|
struct Event_Backend_KQueue *data = _data;
|
42
|
-
|
41
|
+
Event_Backend_mark(&data->backend);
|
43
42
|
}
|
44
43
|
|
45
44
|
static
|
@@ -79,7 +78,7 @@ VALUE Event_Backend_KQueue_allocate(VALUE self) {
|
|
79
78
|
struct Event_Backend_KQueue *data = NULL;
|
80
79
|
VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
81
80
|
|
82
|
-
data->
|
81
|
+
Event_Backend_initialize(&data->backend, Qnil);
|
83
82
|
data->descriptor = -1;
|
84
83
|
|
85
84
|
return instance;
|
@@ -89,7 +88,7 @@ VALUE Event_Backend_KQueue_initialize(VALUE self, VALUE loop) {
|
|
89
88
|
struct Event_Backend_KQueue *data = NULL;
|
90
89
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
91
90
|
|
92
|
-
data->
|
91
|
+
Event_Backend_initialize(&data->backend, loop);
|
93
92
|
int result = kqueue();
|
94
93
|
|
95
94
|
if (result == -1) {
|
@@ -113,6 +112,33 @@ VALUE Event_Backend_KQueue_close(VALUE self) {
|
|
113
112
|
return Qnil;
|
114
113
|
}
|
115
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
|
+
|
116
142
|
struct process_wait_arguments {
|
117
143
|
struct Event_Backend_KQueue *data;
|
118
144
|
pid_t pid;
|
@@ -160,7 +186,7 @@ static
|
|
160
186
|
VALUE process_wait_transfer(VALUE _arguments) {
|
161
187
|
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
162
188
|
|
163
|
-
|
189
|
+
Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
164
190
|
|
165
191
|
return Event_Backend_process_status_wait(arguments->pid);
|
166
192
|
}
|
@@ -281,7 +307,7 @@ static
|
|
281
307
|
VALUE io_wait_transfer(VALUE _arguments) {
|
282
308
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
283
309
|
|
284
|
-
VALUE result =
|
310
|
+
VALUE result = Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
285
311
|
|
286
312
|
return INT2NUM(events_from_kqueue_filter(RB_NUM2INT(result)));
|
287
313
|
}
|
@@ -290,7 +316,7 @@ VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE even
|
|
290
316
|
struct Event_Backend_KQueue *data = NULL;
|
291
317
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
292
318
|
|
293
|
-
int descriptor =
|
319
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
294
320
|
|
295
321
|
struct io_wait_arguments io_wait_arguments = {
|
296
322
|
.events = io_add_filters(data->descriptor, descriptor, RB_NUM2INT(events), fiber),
|
@@ -301,6 +327,8 @@ VALUE Event_Backend_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE even
|
|
301
327
|
return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
|
302
328
|
}
|
303
329
|
|
330
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
331
|
+
|
304
332
|
struct io_read_arguments {
|
305
333
|
VALUE self;
|
306
334
|
VALUE fiber;
|
@@ -311,7 +339,6 @@ struct io_read_arguments {
|
|
311
339
|
int descriptor;
|
312
340
|
|
313
341
|
VALUE buffer;
|
314
|
-
size_t offset;
|
315
342
|
size_t length;
|
316
343
|
};
|
317
344
|
|
@@ -319,18 +346,22 @@ static
|
|
319
346
|
VALUE io_read_loop(VALUE _arguments) {
|
320
347
|
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
321
348
|
|
322
|
-
|
349
|
+
void *base;
|
350
|
+
size_t size;
|
351
|
+
rb_io_buffer_get_mutable(arguments->buffer, &base, &size);
|
352
|
+
|
353
|
+
size_t offset = 0;
|
323
354
|
size_t length = arguments->length;
|
324
|
-
size_t total = 0;
|
325
355
|
|
326
356
|
while (length > 0) {
|
327
|
-
|
328
|
-
ssize_t result = read(arguments->descriptor,
|
357
|
+
size_t maximum_size = size - offset;
|
358
|
+
ssize_t result = read(arguments->descriptor, (char*)base+offset, maximum_size);
|
329
359
|
|
330
|
-
if (result
|
360
|
+
if (result == 0) {
|
361
|
+
break;
|
362
|
+
} else if (result > 0) {
|
331
363
|
offset += result;
|
332
364
|
length -= result;
|
333
|
-
total += result;
|
334
365
|
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
335
366
|
Event_Backend_KQueue_io_wait(arguments->self, arguments->fiber, arguments->io, RB_INT2NUM(READABLE));
|
336
367
|
} else {
|
@@ -338,9 +369,7 @@ VALUE io_read_loop(VALUE _arguments) {
|
|
338
369
|
}
|
339
370
|
}
|
340
371
|
|
341
|
-
|
342
|
-
|
343
|
-
return SIZET2NUM(total);
|
372
|
+
return SIZET2NUM(offset);
|
344
373
|
}
|
345
374
|
|
346
375
|
static
|
@@ -352,13 +381,12 @@ VALUE io_read_ensure(VALUE _arguments) {
|
|
352
381
|
return Qnil;
|
353
382
|
}
|
354
383
|
|
355
|
-
VALUE Event_Backend_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE
|
384
|
+
VALUE Event_Backend_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
356
385
|
struct Event_Backend_KQueue *data = NULL;
|
357
386
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
358
387
|
|
359
|
-
int descriptor =
|
388
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
360
389
|
|
361
|
-
size_t offset = NUM2SIZET(_offset);
|
362
390
|
size_t length = NUM2SIZET(_length);
|
363
391
|
|
364
392
|
struct io_read_arguments io_read_arguments = {
|
@@ -369,7 +397,6 @@ VALUE Event_Backend_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buff
|
|
369
397
|
.flags = Event_Backend_nonblock_set(descriptor),
|
370
398
|
.descriptor = descriptor,
|
371
399
|
.buffer = buffer,
|
372
|
-
.offset = offset,
|
373
400
|
.length = length,
|
374
401
|
};
|
375
402
|
|
@@ -386,7 +413,6 @@ struct io_write_arguments {
|
|
386
413
|
int descriptor;
|
387
414
|
|
388
415
|
VALUE buffer;
|
389
|
-
size_t offset;
|
390
416
|
size_t length;
|
391
417
|
};
|
392
418
|
|
@@ -394,18 +420,23 @@ static
|
|
394
420
|
VALUE io_write_loop(VALUE _arguments) {
|
395
421
|
struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
|
396
422
|
|
397
|
-
|
423
|
+
const void *base;
|
424
|
+
size_t size;
|
425
|
+
rb_io_buffer_get_immutable(arguments->buffer, &base, &size);
|
426
|
+
|
427
|
+
size_t offset = 0;
|
398
428
|
size_t length = arguments->length;
|
399
|
-
|
429
|
+
|
430
|
+
if (length > size) {
|
431
|
+
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
432
|
+
}
|
400
433
|
|
401
434
|
while (length > 0) {
|
402
|
-
|
403
|
-
ssize_t result = write(arguments->descriptor, buffer+offset, length);
|
435
|
+
ssize_t result = write(arguments->descriptor, (char*)base+offset, length);
|
404
436
|
|
405
437
|
if (result >= 0) {
|
406
|
-
length -= result;
|
407
438
|
offset += result;
|
408
|
-
|
439
|
+
length -= result;
|
409
440
|
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
410
441
|
Event_Backend_KQueue_io_wait(arguments->self, arguments->fiber, arguments->io, RB_INT2NUM(WRITABLE));
|
411
442
|
} else {
|
@@ -413,7 +444,7 @@ VALUE io_write_loop(VALUE _arguments) {
|
|
413
444
|
}
|
414
445
|
}
|
415
446
|
|
416
|
-
return SIZET2NUM(
|
447
|
+
return SIZET2NUM(offset);
|
417
448
|
};
|
418
449
|
|
419
450
|
static
|
@@ -425,13 +456,12 @@ VALUE io_write_ensure(VALUE _arguments) {
|
|
425
456
|
return Qnil;
|
426
457
|
};
|
427
458
|
|
428
|
-
VALUE Event_Backend_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE
|
459
|
+
VALUE Event_Backend_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
429
460
|
struct Event_Backend_KQueue *data = NULL;
|
430
461
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
431
462
|
|
432
|
-
int descriptor =
|
463
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
433
464
|
|
434
|
-
size_t offset = NUM2SIZET(_offset);
|
435
465
|
size_t length = NUM2SIZET(_length);
|
436
466
|
|
437
467
|
struct io_write_arguments io_write_arguments = {
|
@@ -442,13 +472,14 @@ VALUE Event_Backend_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buf
|
|
442
472
|
.flags = Event_Backend_nonblock_set(descriptor),
|
443
473
|
.descriptor = descriptor,
|
444
474
|
.buffer = buffer,
|
445
|
-
.offset = offset,
|
446
475
|
.length = length,
|
447
476
|
};
|
448
477
|
|
449
478
|
return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
|
450
479
|
}
|
451
480
|
|
481
|
+
#endif
|
482
|
+
|
452
483
|
static
|
453
484
|
struct timespec * make_timeout(VALUE duration, struct timespec * storage) {
|
454
485
|
if (duration == Qnil) {
|
@@ -521,6 +552,8 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
|
|
521
552
|
struct Event_Backend_KQueue *data = NULL;
|
522
553
|
TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
|
523
554
|
|
555
|
+
Event_Backend_ready_pop(&data->backend);
|
556
|
+
|
524
557
|
struct select_arguments arguments = {
|
525
558
|
.data = data,
|
526
559
|
.count = KQUEUE_MAX_EVENTS,
|
@@ -544,7 +577,7 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
|
|
544
577
|
if (arguments.count == 0) {
|
545
578
|
arguments.timeout = make_timeout(duration, &arguments.storage);
|
546
579
|
|
547
|
-
if (!timeout_nonblocking(arguments.timeout)) {
|
580
|
+
if (!data->backend.ready && !timeout_nonblocking(arguments.timeout)) {
|
548
581
|
arguments.count = KQUEUE_MAX_EVENTS;
|
549
582
|
|
550
583
|
select_internal_without_gvl(&arguments);
|
@@ -555,25 +588,29 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
|
|
555
588
|
VALUE fiber = (VALUE)arguments.events[i].udata;
|
556
589
|
VALUE result = INT2NUM(arguments.events[i].filter);
|
557
590
|
|
558
|
-
|
591
|
+
Event_Backend_fiber_transfer_result(fiber, result);
|
559
592
|
}
|
560
593
|
|
561
594
|
return INT2NUM(arguments.count);
|
562
595
|
}
|
563
596
|
|
564
597
|
void Init_Event_Backend_KQueue(VALUE Event_Backend) {
|
565
|
-
id_fileno = rb_intern("fileno");
|
566
|
-
|
567
598
|
Event_Backend_KQueue = rb_define_class_under(Event_Backend, "KQueue", rb_cObject);
|
568
599
|
|
569
600
|
rb_define_alloc_func(Event_Backend_KQueue, Event_Backend_KQueue_allocate);
|
570
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);
|
571
605
|
rb_define_method(Event_Backend_KQueue, "select", Event_Backend_KQueue_select, 1);
|
572
606
|
rb_define_method(Event_Backend_KQueue, "close", Event_Backend_KQueue_close, 0);
|
573
607
|
|
574
608
|
rb_define_method(Event_Backend_KQueue, "io_wait", Event_Backend_KQueue_io_wait, 3);
|
575
|
-
|
576
|
-
|
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
|
577
614
|
|
578
615
|
rb_define_method(Event_Backend_KQueue, "process_wait", Event_Backend_KQueue_process_wait, 3);
|
579
616
|
}
|
data/ext/event/backend/uring.c
CHANGED
@@ -27,21 +27,25 @@
|
|
27
27
|
|
28
28
|
#include "pidfd.c"
|
29
29
|
|
30
|
+
static const int DEBUG = 0;
|
31
|
+
|
32
|
+
// This option controls whether to all `io_uring_submit()` after every operation:
|
33
|
+
static const int EARLY_SUBMIT = 1;
|
34
|
+
|
30
35
|
static VALUE Event_Backend_URing = Qnil;
|
31
|
-
static ID id_fileno;
|
32
36
|
|
33
|
-
enum {URING_ENTRIES =
|
34
|
-
enum {URING_MAX_EVENTS = 128};
|
37
|
+
enum {URING_ENTRIES = 64};
|
35
38
|
|
36
39
|
struct Event_Backend_URing {
|
37
|
-
|
40
|
+
struct Event_Backend backend;
|
38
41
|
struct io_uring ring;
|
42
|
+
size_t pending;
|
39
43
|
};
|
40
44
|
|
41
45
|
void Event_Backend_URing_Type_mark(void *_data)
|
42
46
|
{
|
43
47
|
struct Event_Backend_URing *data = _data;
|
44
|
-
|
48
|
+
Event_Backend_mark(&data->backend);
|
45
49
|
}
|
46
50
|
|
47
51
|
static
|
@@ -81,9 +85,11 @@ VALUE Event_Backend_URing_allocate(VALUE self) {
|
|
81
85
|
struct Event_Backend_URing *data = NULL;
|
82
86
|
VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
83
87
|
|
84
|
-
data->
|
88
|
+
Event_Backend_initialize(&data->backend, Qnil);
|
85
89
|
data->ring.ring_fd = -1;
|
86
90
|
|
91
|
+
data->pending = 0;
|
92
|
+
|
87
93
|
return instance;
|
88
94
|
}
|
89
95
|
|
@@ -91,8 +97,7 @@ VALUE Event_Backend_URing_initialize(VALUE self, VALUE loop) {
|
|
91
97
|
struct Event_Backend_URing *data = NULL;
|
92
98
|
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
93
99
|
|
94
|
-
data->
|
95
|
-
|
100
|
+
Event_Backend_initialize(&data->backend, loop);
|
96
101
|
int result = io_uring_queue_init(URING_ENTRIES, &data->ring, 0);
|
97
102
|
|
98
103
|
if (result < 0) {
|
@@ -113,16 +118,91 @@ VALUE Event_Backend_URing_close(VALUE self) {
|
|
113
118
|
return Qnil;
|
114
119
|
}
|
115
120
|
|
121
|
+
VALUE Event_Backend_URing_transfer(VALUE self, VALUE fiber)
|
122
|
+
{
|
123
|
+
struct Event_Backend_URing *data = NULL;
|
124
|
+
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
125
|
+
|
126
|
+
Event_Backend_wait_and_transfer(&data->backend, fiber);
|
127
|
+
|
128
|
+
return Qnil;
|
129
|
+
}
|
130
|
+
|
131
|
+
VALUE Event_Backend_URing_defer(VALUE self)
|
132
|
+
{
|
133
|
+
struct Event_Backend_URing *data = NULL;
|
134
|
+
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
135
|
+
|
136
|
+
Event_Backend_defer(&data->backend);
|
137
|
+
|
138
|
+
return Qnil;
|
139
|
+
}
|
140
|
+
|
141
|
+
VALUE Event_Backend_URing_ready_p(VALUE self) {
|
142
|
+
struct Event_Backend_URing *data = NULL;
|
143
|
+
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
144
|
+
|
145
|
+
return data->backend.ready ? Qtrue : Qfalse;
|
146
|
+
}
|
147
|
+
|
148
|
+
static
|
149
|
+
int io_uring_submit_flush(struct Event_Backend_URing *data) {
|
150
|
+
if (data->pending) {
|
151
|
+
if (DEBUG) fprintf(stderr, "io_uring_submit_flush(pending=%ld)\n", data->pending);
|
152
|
+
|
153
|
+
// Try to submit:
|
154
|
+
int result = io_uring_submit(&data->ring);
|
155
|
+
|
156
|
+
if (result >= 0) {
|
157
|
+
// If it was submitted, reset pending count:
|
158
|
+
data->pending = 0;
|
159
|
+
} else if (result != -EBUSY && result != -EAGAIN) {
|
160
|
+
rb_syserr_fail(-result, "io_uring_submit_flush");
|
161
|
+
}
|
162
|
+
|
163
|
+
return result;
|
164
|
+
}
|
165
|
+
|
166
|
+
return 0;
|
167
|
+
}
|
168
|
+
|
169
|
+
static
|
170
|
+
int io_uring_submit_now(struct Event_Backend_URing *data) {
|
171
|
+
while (true) {
|
172
|
+
int result = io_uring_submit(&data->ring);
|
173
|
+
|
174
|
+
if (result >= 0) {
|
175
|
+
data->pending = 0;
|
176
|
+
return result;
|
177
|
+
}
|
178
|
+
|
179
|
+
if (result == -EBUSY || result == -EAGAIN) {
|
180
|
+
Event_Backend_defer(&data->backend);
|
181
|
+
} else {
|
182
|
+
rb_syserr_fail(-result, "io_uring_submit_now");
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
static
|
188
|
+
void io_uring_submit_pending(struct Event_Backend_URing *data) {
|
189
|
+
if (EARLY_SUBMIT) {
|
190
|
+
io_uring_submit_now(data);
|
191
|
+
} else {
|
192
|
+
data->pending += 1;
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
116
196
|
struct io_uring_sqe * io_get_sqe(struct Event_Backend_URing *data) {
|
117
197
|
struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
|
118
198
|
|
119
199
|
while (sqe == NULL) {
|
120
|
-
|
200
|
+
// The submit queue is full, we need to drain it:
|
201
|
+
io_uring_submit_now(data);
|
202
|
+
|
121
203
|
sqe = io_uring_get_sqe(&data->ring);
|
122
204
|
}
|
123
205
|
|
124
|
-
// fprintf(stderr, "io_get_sqe -> %p\n", sqe);
|
125
|
-
|
126
206
|
return sqe;
|
127
207
|
}
|
128
208
|
|
@@ -137,7 +217,7 @@ static
|
|
137
217
|
VALUE process_wait_transfer(VALUE _arguments) {
|
138
218
|
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
139
219
|
|
140
|
-
|
220
|
+
Event_Backend_fiber_transfer(arguments->data->backend.loop);
|
141
221
|
|
142
222
|
return Event_Backend_process_status_wait(arguments->pid);
|
143
223
|
}
|
@@ -165,11 +245,12 @@ VALUE Event_Backend_URing_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE
|
|
165
245
|
rb_update_max_fd(process_wait_arguments.descriptor);
|
166
246
|
|
167
247
|
struct io_uring_sqe *sqe = io_get_sqe(data);
|
168
|
-
|
169
|
-
|
248
|
+
|
249
|
+
if (DEBUG) fprintf(stderr, "Event_Backend_URing_process_wait:io_uring_prep_poll_add(%p)\n", (void*)fiber);
|
170
250
|
io_uring_prep_poll_add(sqe, process_wait_arguments.descriptor, POLLIN|POLLHUP|POLLERR);
|
171
251
|
io_uring_sqe_set_data(sqe, (void*)fiber);
|
172
|
-
|
252
|
+
io_uring_submit_pending(data);
|
253
|
+
|
173
254
|
return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
|
174
255
|
}
|
175
256
|
|
@@ -210,12 +291,10 @@ VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
|
|
210
291
|
struct Event_Backend_URing *data = arguments->data;
|
211
292
|
|
212
293
|
struct io_uring_sqe *sqe = io_get_sqe(data);
|
213
|
-
assert(sqe);
|
214
294
|
|
215
|
-
|
295
|
+
if (DEBUG) fprintf(stderr, "io_wait_rescue:io_uring_prep_poll_remove(%p)\n", (void*)arguments->fiber);
|
216
296
|
|
217
297
|
io_uring_prep_poll_remove(sqe, (void*)arguments->fiber);
|
218
|
-
io_uring_submit(&data->ring);
|
219
298
|
|
220
299
|
rb_exc_raise(exception);
|
221
300
|
};
|
@@ -225,8 +304,9 @@ VALUE io_wait_transfer(VALUE _arguments) {
|
|
225
304
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
226
305
|
struct Event_Backend_URing *data = arguments->data;
|
227
306
|
|
228
|
-
VALUE result =
|
229
|
-
|
307
|
+
VALUE result = Event_Backend_fiber_transfer(data->backend.loop);
|
308
|
+
if (DEBUG) fprintf(stderr, "io_wait:Event_Backend_fiber_transfer -> %d\n", RB_NUM2INT(result));
|
309
|
+
|
230
310
|
// We explicitly filter the resulting events based on the requested events.
|
231
311
|
// In some cases, poll will report events we didn't ask for.
|
232
312
|
short flags = arguments->flags & NUM2INT(result);
|
@@ -238,18 +318,16 @@ VALUE Event_Backend_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE event
|
|
238
318
|
struct Event_Backend_URing *data = NULL;
|
239
319
|
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
240
320
|
|
241
|
-
int descriptor =
|
321
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
242
322
|
struct io_uring_sqe *sqe = io_get_sqe(data);
|
243
|
-
assert(sqe);
|
244
323
|
|
245
324
|
short flags = poll_flags_from_events(NUM2INT(events));
|
246
325
|
|
247
|
-
|
326
|
+
if (DEBUG) fprintf(stderr, "Event_Backend_URing_io_wait:io_uring_prep_poll_add(descriptor=%d, flags=%d, fiber=%p)\n", descriptor, flags, (void*)fiber);
|
248
327
|
|
249
328
|
io_uring_prep_poll_add(sqe, descriptor, flags);
|
250
329
|
io_uring_sqe_set_data(sqe, (void*)fiber);
|
251
|
-
|
252
|
-
// io_uring_submit(&data->ring);
|
330
|
+
io_uring_submit_pending(data);
|
253
331
|
|
254
332
|
struct io_wait_arguments io_wait_arguments = {
|
255
333
|
.data = data,
|
@@ -260,42 +338,46 @@ VALUE Event_Backend_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE event
|
|
260
338
|
return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
|
261
339
|
}
|
262
340
|
|
263
|
-
|
264
|
-
|
341
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
342
|
+
|
343
|
+
static int io_read(struct Event_Backend_URing *data, VALUE fiber, int descriptor, char *buffer, size_t length) {
|
265
344
|
struct io_uring_sqe *sqe = io_get_sqe(data);
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
iovecs[0].iov_len = length;
|
271
|
-
|
272
|
-
io_uring_prep_readv(sqe, descriptor, iovecs, 1, 0);
|
345
|
+
|
346
|
+
if (DEBUG) fprintf(stderr, "io_read:io_uring_prep_read(fiber=%p)\n", (void*)fiber);
|
347
|
+
|
348
|
+
io_uring_prep_read(sqe, descriptor, buffer, length, 0);
|
273
349
|
io_uring_sqe_set_data(sqe, (void*)fiber);
|
274
|
-
|
350
|
+
io_uring_submit_pending(data);
|
275
351
|
|
276
|
-
|
352
|
+
VALUE result = Event_Backend_fiber_transfer(data->backend.loop);
|
353
|
+
if (DEBUG) fprintf(stderr, "io_read:Event_Backend_fiber_transfer -> %d\n", RB_NUM2INT(result));
|
354
|
+
|
355
|
+
return RB_NUM2INT(result);
|
277
356
|
}
|
278
357
|
|
279
|
-
VALUE Event_Backend_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
|
358
|
+
VALUE Event_Backend_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
280
359
|
struct Event_Backend_URing *data = NULL;
|
281
360
|
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
282
361
|
|
283
|
-
int descriptor =
|
362
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
284
363
|
|
285
|
-
|
286
|
-
size_t
|
364
|
+
void *base;
|
365
|
+
size_t size;
|
366
|
+
rb_io_buffer_get_mutable(buffer, &base, &size);
|
287
367
|
|
288
|
-
size_t
|
289
|
-
size_t
|
368
|
+
size_t offset = 0;
|
369
|
+
size_t length = NUM2SIZET(_length);
|
290
370
|
|
291
371
|
while (length > 0) {
|
292
|
-
|
293
|
-
int result = io_read(data, fiber, descriptor,
|
372
|
+
size_t maximum_size = size - offset;
|
373
|
+
int result = io_read(data, fiber, descriptor, (char*)base+offset, maximum_size);
|
294
374
|
|
295
|
-
if (result
|
375
|
+
if (result == 0) {
|
376
|
+
break;
|
377
|
+
} else if (result > 0) {
|
296
378
|
offset += result;
|
379
|
+
if ((size_t)result >= length) break;
|
297
380
|
length -= result;
|
298
|
-
total += result;
|
299
381
|
} else if (-result == EAGAIN || -result == EWOULDBLOCK) {
|
300
382
|
Event_Backend_URing_io_wait(self, fiber, io, RB_INT2NUM(READABLE));
|
301
383
|
} else {
|
@@ -303,47 +385,49 @@ VALUE Event_Backend_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE _buff
|
|
303
385
|
}
|
304
386
|
}
|
305
387
|
|
306
|
-
|
307
|
-
|
308
|
-
return SIZET2NUM(total);
|
388
|
+
return SIZET2NUM(offset);
|
309
389
|
}
|
310
390
|
|
311
391
|
static
|
312
392
|
int io_write(struct Event_Backend_URing *data, VALUE fiber, int descriptor, char *buffer, size_t length) {
|
313
393
|
struct io_uring_sqe *sqe = io_get_sqe(data);
|
314
|
-
assert(sqe);
|
315
394
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
io_uring_prep_writev(sqe, descriptor, iovecs, 1, 0);
|
395
|
+
if (DEBUG) fprintf(stderr, "io_write:io_uring_prep_write(fiber=%p)\n", (void*)fiber);
|
396
|
+
|
397
|
+
io_uring_prep_write(sqe, descriptor, buffer, length, 0);
|
321
398
|
io_uring_sqe_set_data(sqe, (void*)fiber);
|
322
|
-
|
399
|
+
io_uring_submit_pending(data);
|
323
400
|
|
324
|
-
|
401
|
+
int result = RB_NUM2INT(Event_Backend_fiber_transfer(data->backend.loop));
|
402
|
+
if (DEBUG) fprintf(stderr, "io_write:Event_Backend_fiber_transfer -> %d\n", result);
|
403
|
+
|
404
|
+
return result;
|
325
405
|
}
|
326
406
|
|
327
|
-
VALUE Event_Backend_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
|
407
|
+
VALUE Event_Backend_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
328
408
|
struct Event_Backend_URing *data = NULL;
|
329
409
|
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
330
410
|
|
331
|
-
int descriptor =
|
411
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
332
412
|
|
333
|
-
|
334
|
-
size_t
|
413
|
+
const void *base;
|
414
|
+
size_t size;
|
415
|
+
rb_io_buffer_get_immutable(buffer, &base, &size);
|
335
416
|
|
336
|
-
|
417
|
+
size_t offset = 0;
|
418
|
+
size_t length = NUM2SIZET(_length);
|
337
419
|
|
338
|
-
|
420
|
+
if (length > size) {
|
421
|
+
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
422
|
+
}
|
339
423
|
|
340
424
|
while (length > 0) {
|
341
|
-
int result = io_write(data, fiber, descriptor,
|
425
|
+
int result = io_write(data, fiber, descriptor, (char*)base+offset, length);
|
342
426
|
|
343
427
|
if (result >= 0) {
|
344
|
-
length -= result;
|
345
428
|
offset += result;
|
346
|
-
|
429
|
+
if ((size_t)result >= length) break;
|
430
|
+
length -= result;
|
347
431
|
} else if (-result == EAGAIN || -result == EWOULDBLOCK) {
|
348
432
|
Event_Backend_URing_io_wait(self, fiber, io, RB_INT2NUM(WRITABLE));
|
349
433
|
} else {
|
@@ -351,7 +435,34 @@ VALUE Event_Backend_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE _buf
|
|
351
435
|
}
|
352
436
|
}
|
353
437
|
|
354
|
-
return SIZET2NUM(
|
438
|
+
return SIZET2NUM(offset);
|
439
|
+
}
|
440
|
+
|
441
|
+
#endif
|
442
|
+
|
443
|
+
static const int ASYNC_CLOSE = 2;
|
444
|
+
|
445
|
+
VALUE Event_Backend_URing_io_close(VALUE self, VALUE io) {
|
446
|
+
struct Event_Backend_URing *data = NULL;
|
447
|
+
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
448
|
+
|
449
|
+
int descriptor = Event_Backend_io_descriptor(io);
|
450
|
+
|
451
|
+
if (ASYNC_CLOSE) {
|
452
|
+
struct io_uring_sqe *sqe = io_get_sqe(data);
|
453
|
+
|
454
|
+
io_uring_prep_close(sqe, descriptor);
|
455
|
+
io_uring_sqe_set_data(sqe, NULL);
|
456
|
+
if (ASYNC_CLOSE == 1)
|
457
|
+
io_uring_submit_now(data);
|
458
|
+
else if (ASYNC_CLOSE == 2)
|
459
|
+
io_uring_submit_pending(data);
|
460
|
+
} else {
|
461
|
+
close(descriptor);
|
462
|
+
}
|
463
|
+
|
464
|
+
// We don't wait for the result of close since it has no use in pratice:
|
465
|
+
return Qtrue;
|
355
466
|
}
|
356
467
|
|
357
468
|
static
|
@@ -397,9 +508,9 @@ struct select_arguments {
|
|
397
508
|
static
|
398
509
|
void * select_internal(void *_arguments) {
|
399
510
|
struct select_arguments * arguments = (struct select_arguments *)_arguments;
|
400
|
-
|
401
|
-
|
402
|
-
|
511
|
+
|
512
|
+
io_uring_submit_flush(arguments->data);
|
513
|
+
|
403
514
|
struct io_uring_cqe *cqe = NULL;
|
404
515
|
arguments->result = io_uring_wait_cqe_timeout(&arguments->data->ring, &cqe, arguments->timeout);
|
405
516
|
|
@@ -433,21 +544,24 @@ unsigned select_process_completions(struct io_uring *ring) {
|
|
433
544
|
|
434
545
|
// If the operation was cancelled, or the operation has no user data (fiber):
|
435
546
|
if (cqe->res == -ECANCELED || cqe->user_data == 0 || cqe->user_data == LIBURING_UDATA_TIMEOUT) {
|
547
|
+
io_uring_cq_advance(ring, 1);
|
436
548
|
continue;
|
437
549
|
}
|
438
550
|
|
439
551
|
VALUE fiber = (VALUE)cqe->user_data;
|
440
|
-
VALUE result =
|
552
|
+
VALUE result = RB_INT2NUM(cqe->res);
|
441
553
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
if (completed) {
|
448
|
-
io_uring_cq_advance(ring, completed);
|
554
|
+
if (DEBUG) fprintf(stderr, "cqe res=%d user_data=%p\n", cqe->res, (void*)cqe->user_data);
|
555
|
+
|
556
|
+
io_uring_cq_advance(ring, 1);
|
557
|
+
|
558
|
+
Event_Backend_fiber_transfer_result(fiber, result);
|
449
559
|
}
|
450
560
|
|
561
|
+
// io_uring_cq_advance(ring, completed);
|
562
|
+
|
563
|
+
if (DEBUG) fprintf(stderr, "select_process_completions(completed=%d)\n", completed);
|
564
|
+
|
451
565
|
return completed;
|
452
566
|
}
|
453
567
|
|
@@ -455,11 +569,17 @@ VALUE Event_Backend_URing_select(VALUE self, VALUE duration) {
|
|
455
569
|
struct Event_Backend_URing *data = NULL;
|
456
570
|
TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
|
457
571
|
|
458
|
-
|
572
|
+
Event_Backend_ready_pop(&data->backend);
|
459
573
|
|
460
|
-
|
461
|
-
|
462
|
-
|
574
|
+
int result = 0;
|
575
|
+
|
576
|
+
// There can only be events waiting if we have been submitting them early:
|
577
|
+
if (EARLY_SUBMIT) {
|
578
|
+
result = select_process_completions(&data->ring);
|
579
|
+
}
|
580
|
+
|
581
|
+
// If we aren't submitting events early, we need to submit them and/or wait for them:
|
582
|
+
if (result == 0) {
|
463
583
|
// We might need to wait for events:
|
464
584
|
struct select_arguments arguments = {
|
465
585
|
.data = data,
|
@@ -468,31 +588,40 @@ VALUE Event_Backend_URing_select(VALUE self, VALUE duration) {
|
|
468
588
|
|
469
589
|
arguments.timeout = make_timeout(duration, &arguments.storage);
|
470
590
|
|
471
|
-
if (!timeout_nonblocking(arguments.timeout)) {
|
591
|
+
if (!data->backend.ready && !timeout_nonblocking(arguments.timeout)) {
|
592
|
+
// This is a blocking operation, we wait for events:
|
472
593
|
result = select_internal_without_gvl(&arguments);
|
473
594
|
} else {
|
474
|
-
|
595
|
+
// The timeout specified required "nonblocking" behaviour so we just flush the SQ if required:
|
596
|
+
io_uring_submit_flush(data);
|
475
597
|
}
|
598
|
+
|
599
|
+
// After waiting/flushing the SQ, check if there are any completions:
|
600
|
+
result = select_process_completions(&data->ring);
|
476
601
|
}
|
477
602
|
|
478
|
-
|
479
|
-
|
480
|
-
return INT2NUM(result);
|
603
|
+
return RB_INT2NUM(result);
|
481
604
|
}
|
482
605
|
|
483
606
|
void Init_Event_Backend_URing(VALUE Event_Backend) {
|
484
|
-
id_fileno = rb_intern("fileno");
|
485
|
-
|
486
607
|
Event_Backend_URing = rb_define_class_under(Event_Backend, "URing", rb_cObject);
|
487
608
|
|
488
609
|
rb_define_alloc_func(Event_Backend_URing, Event_Backend_URing_allocate);
|
489
610
|
rb_define_method(Event_Backend_URing, "initialize", Event_Backend_URing_initialize, 1);
|
611
|
+
rb_define_method(Event_Backend_URing, "transfer", Event_Backend_URing_transfer, 1);
|
612
|
+
rb_define_method(Event_Backend_URing, "defer", Event_Backend_URing_defer, 0);
|
613
|
+
rb_define_method(Event_Backend_URing, "ready?", Event_Backend_URing_ready_p, 0);
|
490
614
|
rb_define_method(Event_Backend_URing, "select", Event_Backend_URing_select, 1);
|
491
615
|
rb_define_method(Event_Backend_URing, "close", Event_Backend_URing_close, 0);
|
492
616
|
|
493
617
|
rb_define_method(Event_Backend_URing, "io_wait", Event_Backend_URing_io_wait, 3);
|
494
|
-
|
495
|
-
|
618
|
+
|
619
|
+
#ifdef HAVE_RUBY_IO_BUFFER_H
|
620
|
+
rb_define_method(Event_Backend_URing, "io_read", Event_Backend_URing_io_read, 4);
|
621
|
+
rb_define_method(Event_Backend_URing, "io_write", Event_Backend_URing_io_write, 4);
|
622
|
+
#endif
|
623
|
+
|
624
|
+
rb_define_method(Event_Backend_URing, "io_close", Event_Backend_URing_io_close, 1);
|
496
625
|
|
497
626
|
rb_define_method(Event_Backend_URing, "process_wait", Event_Backend_URing_process_wait, 3);
|
498
627
|
}
|