io-event 1.6.5 → 1.9.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
- checksums.yaml.gz.sig +0 -0
- data/ext/extconf.rb +26 -13
- data/ext/io/event/{selector/array.h → array.h} +74 -18
- data/ext/io/event/event.c +9 -26
- data/ext/io/event/event.h +2 -19
- data/ext/io/event/fiber.c +63 -0
- data/ext/io/event/fiber.h +23 -0
- data/ext/io/event/interrupt.c +19 -27
- data/ext/io/event/interrupt.h +2 -19
- data/ext/io/event/{selector/list.h → list.h} +20 -2
- data/ext/io/event/profiler.c +505 -0
- data/ext/io/event/profiler.h +8 -0
- data/ext/io/event/selector/epoll.c +41 -43
- data/ext/io/event/selector/epoll.h +2 -19
- data/ext/io/event/selector/kqueue.c +34 -41
- data/ext/io/event/selector/kqueue.h +2 -19
- data/ext/io/event/selector/pidfd.c +2 -19
- data/ext/io/event/selector/selector.c +65 -102
- data/ext/io/event/selector/selector.h +51 -46
- data/ext/io/event/selector/uring.c +130 -47
- data/ext/io/event/selector/uring.h +2 -19
- data/ext/io/event/time.c +35 -0
- data/ext/io/event/time.h +17 -0
- data/lib/io/event/debug/selector.rb +44 -4
- data/lib/io/event/interrupt.rb +2 -2
- data/lib/io/event/native.rb +11 -0
- data/lib/io/event/priority_heap.rb +13 -14
- data/lib/io/event/profiler.rb +18 -0
- data/lib/io/event/selector/nonblock.rb +6 -2
- data/lib/io/event/selector/select.rb +25 -5
- data/lib/io/event/selector.rb +15 -5
- data/lib/io/event/support.rb +23 -2
- data/lib/io/event/timers.rb +42 -4
- data/lib/io/event/version.rb +4 -2
- data/lib/io/event.rb +5 -11
- data/license.md +4 -1
- data/readme.md +22 -4
- data/releases.md +57 -0
- data.tar.gz.sig +0 -0
- metadata +20 -11
- metadata.gz.sig +0 -0
|
@@ -1,27 +1,10 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
// in the Software without restriction, including without limitation the rights
|
|
6
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
// furnished to do so, subject to the following conditions:
|
|
9
|
-
//
|
|
10
|
-
// The above copyright notice and this permission notice shall be included in
|
|
11
|
-
// all copies or substantial portions of the Software.
|
|
12
|
-
//
|
|
13
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
// THE SOFTWARE.
|
|
1
|
+
// Released under the MIT License.
|
|
2
|
+
// Copyright, 2021-2025, by Samuel Williams.
|
|
20
3
|
|
|
21
4
|
#include "epoll.h"
|
|
22
5
|
#include "selector.h"
|
|
23
|
-
#include "list.h"
|
|
24
|
-
#include "array.h"
|
|
6
|
+
#include "../list.h"
|
|
7
|
+
#include "../array.h"
|
|
25
8
|
|
|
26
9
|
#include <sys/epoll.h>
|
|
27
10
|
#include <time.h>
|
|
@@ -34,8 +17,6 @@ enum {
|
|
|
34
17
|
DEBUG = 0,
|
|
35
18
|
};
|
|
36
19
|
|
|
37
|
-
static VALUE IO_Event_Selector_EPoll = Qnil;
|
|
38
|
-
|
|
39
20
|
enum {EPOLL_MAX_EVENTS = 64};
|
|
40
21
|
|
|
41
22
|
// This represents an actual fiber waiting for a specific event.
|
|
@@ -176,7 +157,7 @@ size_t IO_Event_Selector_EPoll_Type_size(const void *_selector)
|
|
|
176
157
|
}
|
|
177
158
|
|
|
178
159
|
static const rb_data_type_t IO_Event_Selector_EPoll_Type = {
|
|
179
|
-
.wrap_struct_name = "
|
|
160
|
+
.wrap_struct_name = "IO::Event::Backend::EPoll",
|
|
180
161
|
.function = {
|
|
181
162
|
.dmark = IO_Event_Selector_EPoll_Type_mark,
|
|
182
163
|
.dcompact = IO_Event_Selector_EPoll_Type_compact,
|
|
@@ -184,7 +165,7 @@ static const rb_data_type_t IO_Event_Selector_EPoll_Type = {
|
|
|
184
165
|
.dsize = IO_Event_Selector_EPoll_Type_size,
|
|
185
166
|
},
|
|
186
167
|
.data = NULL,
|
|
187
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
168
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
188
169
|
};
|
|
189
170
|
|
|
190
171
|
inline static
|
|
@@ -243,7 +224,7 @@ int IO_Event_Selector_EPoll_Descriptor_update(struct IO_Event_Selector_EPoll *se
|
|
|
243
224
|
} else {
|
|
244
225
|
// The IO has changed, we need to reset the state:
|
|
245
226
|
epoll_descriptor->registered_events = 0;
|
|
246
|
-
epoll_descriptor->io
|
|
227
|
+
RB_OBJ_WRITE(selector->backend.self, &epoll_descriptor->io, io);
|
|
247
228
|
}
|
|
248
229
|
|
|
249
230
|
if (epoll_descriptor->waiting_events == 0) {
|
|
@@ -253,7 +234,7 @@ int IO_Event_Selector_EPoll_Descriptor_update(struct IO_Event_Selector_EPoll *se
|
|
|
253
234
|
epoll_descriptor->registered_events = 0;
|
|
254
235
|
}
|
|
255
236
|
|
|
256
|
-
epoll_descriptor->io
|
|
237
|
+
RB_OBJ_WRITE(selector->backend.self, &epoll_descriptor->io, 0);
|
|
257
238
|
|
|
258
239
|
return 0;
|
|
259
240
|
}
|
|
@@ -333,13 +314,16 @@ VALUE IO_Event_Selector_EPoll_allocate(VALUE self) {
|
|
|
333
314
|
struct IO_Event_Selector_EPoll *selector = NULL;
|
|
334
315
|
VALUE instance = TypedData_Make_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
|
|
335
316
|
|
|
336
|
-
IO_Event_Selector_initialize(&selector->backend, Qnil);
|
|
317
|
+
IO_Event_Selector_initialize(&selector->backend, self, Qnil);
|
|
337
318
|
selector->descriptor = -1;
|
|
338
319
|
selector->blocked = 0;
|
|
339
320
|
|
|
340
321
|
selector->descriptors.element_initialize = IO_Event_Selector_EPoll_Descriptor_initialize;
|
|
341
322
|
selector->descriptors.element_free = IO_Event_Selector_EPoll_Descriptor_free;
|
|
342
|
-
|
|
323
|
+
int result = IO_Event_Array_initialize(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_EPoll_Descriptor));
|
|
324
|
+
if (result < 0) {
|
|
325
|
+
rb_sys_fail("IO_Event_Selector_EPoll_allocate:IO_Event_Array_initialize");
|
|
326
|
+
}
|
|
343
327
|
|
|
344
328
|
return instance;
|
|
345
329
|
}
|
|
@@ -363,7 +347,7 @@ VALUE IO_Event_Selector_EPoll_initialize(VALUE self, VALUE loop) {
|
|
|
363
347
|
struct IO_Event_Selector_EPoll *selector = NULL;
|
|
364
348
|
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
|
|
365
349
|
|
|
366
|
-
IO_Event_Selector_initialize(&selector->backend, loop);
|
|
350
|
+
IO_Event_Selector_initialize(&selector->backend, self, loop);
|
|
367
351
|
int result = epoll_create1(EPOLL_CLOEXEC);
|
|
368
352
|
|
|
369
353
|
if (result == -1) {
|
|
@@ -410,7 +394,7 @@ VALUE IO_Event_Selector_EPoll_transfer(VALUE self)
|
|
|
410
394
|
struct IO_Event_Selector_EPoll *selector = NULL;
|
|
411
395
|
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
|
|
412
396
|
|
|
413
|
-
return
|
|
397
|
+
return IO_Event_Selector_loop_yield(&selector->backend);
|
|
414
398
|
}
|
|
415
399
|
|
|
416
400
|
VALUE IO_Event_Selector_EPoll_resume(int argc, VALUE *argv, VALUE self)
|
|
@@ -434,7 +418,7 @@ VALUE IO_Event_Selector_EPoll_push(VALUE self, VALUE fiber)
|
|
|
434
418
|
struct IO_Event_Selector_EPoll *selector = NULL;
|
|
435
419
|
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
|
|
436
420
|
|
|
437
|
-
|
|
421
|
+
IO_Event_Selector_ready_push(&selector->backend, fiber);
|
|
438
422
|
|
|
439
423
|
return Qnil;
|
|
440
424
|
}
|
|
@@ -466,7 +450,7 @@ static
|
|
|
466
450
|
VALUE process_wait_transfer(VALUE _arguments) {
|
|
467
451
|
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
|
468
452
|
|
|
469
|
-
|
|
453
|
+
IO_Event_Selector_loop_yield(&arguments->selector->backend);
|
|
470
454
|
|
|
471
455
|
if (arguments->waiting->ready) {
|
|
472
456
|
return IO_Event_Selector_process_status_wait(arguments->pid, arguments->flags);
|
|
@@ -503,13 +487,22 @@ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
|
503
487
|
|
|
504
488
|
rb_update_max_fd(descriptor);
|
|
505
489
|
|
|
490
|
+
// `pidfd_open` (above) may be edge triggered, so we need to check if the process is already exited, and if so, return immediately, otherwise we will block indefinitely.
|
|
491
|
+
VALUE status = IO_Event_Selector_process_status_wait(pid, flags);
|
|
492
|
+
if (status != Qnil) {
|
|
493
|
+
close(descriptor);
|
|
494
|
+
return status;
|
|
495
|
+
}
|
|
496
|
+
|
|
506
497
|
struct IO_Event_Selector_EPoll_Waiting waiting = {
|
|
507
498
|
.list = {.type = &IO_Event_Selector_EPoll_process_wait_list_type},
|
|
508
499
|
.fiber = fiber,
|
|
509
500
|
.events = IO_EVENT_READABLE,
|
|
510
501
|
};
|
|
511
502
|
|
|
512
|
-
|
|
503
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
504
|
+
|
|
505
|
+
int result = IO_Event_Selector_EPoll_Waiting_register(selector, _pid, descriptor, &waiting);
|
|
513
506
|
|
|
514
507
|
if (result == -1) {
|
|
515
508
|
close(descriptor);
|
|
@@ -545,7 +538,7 @@ static
|
|
|
545
538
|
VALUE io_wait_transfer(VALUE _arguments) {
|
|
546
539
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
|
547
540
|
|
|
548
|
-
|
|
541
|
+
IO_Event_Selector_loop_yield(&arguments->selector->backend);
|
|
549
542
|
|
|
550
543
|
if (arguments->waiting->ready) {
|
|
551
544
|
return RB_INT2NUM(arguments->waiting->ready);
|
|
@@ -568,11 +561,13 @@ VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
|
|
|
568
561
|
.events = RB_NUM2INT(events),
|
|
569
562
|
};
|
|
570
563
|
|
|
564
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
565
|
+
|
|
571
566
|
int result = IO_Event_Selector_EPoll_Waiting_register(selector, io, descriptor, &waiting);
|
|
572
567
|
|
|
573
568
|
if (result == -1) {
|
|
574
569
|
if (errno == EPERM) {
|
|
575
|
-
|
|
570
|
+
IO_Event_Selector_ready_push(&selector->backend, fiber);
|
|
576
571
|
IO_Event_Selector_yield(&selector->backend);
|
|
577
572
|
return events;
|
|
578
573
|
}
|
|
@@ -666,6 +661,8 @@ VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
|
|
|
666
661
|
.offset = offset,
|
|
667
662
|
};
|
|
668
663
|
|
|
664
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
665
|
+
|
|
669
666
|
return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
|
|
670
667
|
}
|
|
671
668
|
|
|
@@ -762,6 +759,8 @@ VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
762
759
|
.offset = offset,
|
|
763
760
|
};
|
|
764
761
|
|
|
762
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
763
|
+
|
|
765
764
|
return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
|
|
766
765
|
}
|
|
767
766
|
|
|
@@ -926,7 +925,7 @@ int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, con
|
|
|
926
925
|
|
|
927
926
|
// Resume the fiber:
|
|
928
927
|
waiting->ready = matching_events;
|
|
929
|
-
|
|
928
|
+
IO_Event_Selector_loop_resume(&selector->backend, waiting->fiber, 0, NULL);
|
|
930
929
|
|
|
931
930
|
node = saved->tail;
|
|
932
931
|
IO_Event_List_pop(saved);
|
|
@@ -978,7 +977,7 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
|
|
978
977
|
selector->idle_duration.tv_sec = 0;
|
|
979
978
|
selector->idle_duration.tv_nsec = 0;
|
|
980
979
|
|
|
981
|
-
int ready =
|
|
980
|
+
int ready = IO_Event_Selector_ready_flush(&selector->backend);
|
|
982
981
|
|
|
983
982
|
struct select_arguments arguments = {
|
|
984
983
|
.selector = selector,
|
|
@@ -1004,14 +1003,14 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
|
|
1004
1003
|
|
|
1005
1004
|
if (!timeout_nonblocking(arguments.timeout)) {
|
|
1006
1005
|
struct timespec start_time;
|
|
1007
|
-
|
|
1006
|
+
IO_Event_Time_current(&start_time);
|
|
1008
1007
|
|
|
1009
1008
|
// Wait for events to occur:
|
|
1010
1009
|
select_internal_without_gvl(&arguments);
|
|
1011
1010
|
|
|
1012
1011
|
struct timespec end_time;
|
|
1013
|
-
|
|
1014
|
-
|
|
1012
|
+
IO_Event_Time_current(&end_time);
|
|
1013
|
+
IO_Event_Time_elapsed(&start_time, &end_time, &selector->idle_duration);
|
|
1015
1014
|
}
|
|
1016
1015
|
}
|
|
1017
1016
|
|
|
@@ -1037,8 +1036,7 @@ VALUE IO_Event_Selector_EPoll_wakeup(VALUE self) {
|
|
|
1037
1036
|
}
|
|
1038
1037
|
|
|
1039
1038
|
void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
|
|
1040
|
-
IO_Event_Selector_EPoll = rb_define_class_under(IO_Event_Selector, "EPoll", rb_cObject);
|
|
1041
|
-
rb_gc_register_mark_object(IO_Event_Selector_EPoll);
|
|
1039
|
+
VALUE IO_Event_Selector_EPoll = rb_define_class_under(IO_Event_Selector, "EPoll", rb_cObject);
|
|
1042
1040
|
|
|
1043
1041
|
rb_define_alloc_func(IO_Event_Selector_EPoll, IO_Event_Selector_EPoll_allocate);
|
|
1044
1042
|
rb_define_method(IO_Event_Selector_EPoll, "initialize", IO_Event_Selector_EPoll_initialize, 1);
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
// in the Software without restriction, including without limitation the rights
|
|
6
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
// furnished to do so, subject to the following conditions:
|
|
9
|
-
//
|
|
10
|
-
// The above copyright notice and this permission notice shall be included in
|
|
11
|
-
// all copies or substantial portions of the Software.
|
|
12
|
-
//
|
|
13
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
// THE SOFTWARE.
|
|
1
|
+
// Released under the MIT License.
|
|
2
|
+
// Copyright, 2021-2025, by Samuel Williams.
|
|
20
3
|
|
|
21
4
|
#pragma once
|
|
22
5
|
|
|
@@ -1,27 +1,10 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
// in the Software without restriction, including without limitation the rights
|
|
6
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
// furnished to do so, subject to the following conditions:
|
|
9
|
-
//
|
|
10
|
-
// The above copyright notice and this permission notice shall be included in
|
|
11
|
-
// all copies or substantial portions of the Software.
|
|
12
|
-
//
|
|
13
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
// THE SOFTWARE.
|
|
1
|
+
// Released under the MIT License.
|
|
2
|
+
// Copyright, 2021-2025, by Samuel Williams.
|
|
20
3
|
|
|
21
4
|
#include "kqueue.h"
|
|
22
5
|
#include "selector.h"
|
|
23
|
-
#include "list.h"
|
|
24
|
-
#include "array.h"
|
|
6
|
+
#include "../list.h"
|
|
7
|
+
#include "../array.h"
|
|
25
8
|
|
|
26
9
|
#include <sys/event.h>
|
|
27
10
|
#include <sys/ioctl.h>
|
|
@@ -43,8 +26,6 @@ enum {
|
|
|
43
26
|
#define IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
|
|
44
27
|
#endif
|
|
45
28
|
|
|
46
|
-
static VALUE IO_Event_Selector_KQueue = Qnil;
|
|
47
|
-
|
|
48
29
|
enum {KQUEUE_MAX_EVENTS = 64};
|
|
49
30
|
|
|
50
31
|
// This represents an actual fiber waiting for a specific event.
|
|
@@ -175,7 +156,7 @@ size_t IO_Event_Selector_KQueue_Type_size(const void *_selector)
|
|
|
175
156
|
}
|
|
176
157
|
|
|
177
158
|
static const rb_data_type_t IO_Event_Selector_KQueue_Type = {
|
|
178
|
-
.wrap_struct_name = "
|
|
159
|
+
.wrap_struct_name = "IO::Event::Backend::KQueue",
|
|
179
160
|
.function = {
|
|
180
161
|
.dmark = IO_Event_Selector_KQueue_Type_mark,
|
|
181
162
|
.dcompact = IO_Event_Selector_KQueue_Type_compact,
|
|
@@ -183,7 +164,7 @@ static const rb_data_type_t IO_Event_Selector_KQueue_Type = {
|
|
|
183
164
|
.dsize = IO_Event_Selector_KQueue_Type_size,
|
|
184
165
|
},
|
|
185
166
|
.data = NULL,
|
|
186
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY,
|
|
167
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
|
187
168
|
};
|
|
188
169
|
|
|
189
170
|
inline static
|
|
@@ -307,13 +288,17 @@ VALUE IO_Event_Selector_KQueue_allocate(VALUE self) {
|
|
|
307
288
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
308
289
|
VALUE instance = TypedData_Make_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
309
290
|
|
|
310
|
-
IO_Event_Selector_initialize(&selector->backend, Qnil);
|
|
291
|
+
IO_Event_Selector_initialize(&selector->backend, self, Qnil);
|
|
311
292
|
selector->descriptor = -1;
|
|
312
293
|
selector->blocked = 0;
|
|
313
294
|
|
|
314
295
|
selector->descriptors.element_initialize = IO_Event_Selector_KQueue_Descriptor_initialize;
|
|
315
296
|
selector->descriptors.element_free = IO_Event_Selector_KQueue_Descriptor_free;
|
|
316
|
-
|
|
297
|
+
|
|
298
|
+
int result = IO_Event_Array_initialize(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_KQueue_Descriptor));
|
|
299
|
+
if (result < 0) {
|
|
300
|
+
rb_sys_fail("IO_Event_Selector_KQueue_allocate:IO_Event_Array_initialize");
|
|
301
|
+
}
|
|
317
302
|
|
|
318
303
|
return instance;
|
|
319
304
|
}
|
|
@@ -340,7 +325,7 @@ VALUE IO_Event_Selector_KQueue_initialize(VALUE self, VALUE loop) {
|
|
|
340
325
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
341
326
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
342
327
|
|
|
343
|
-
IO_Event_Selector_initialize(&selector->backend, loop);
|
|
328
|
+
IO_Event_Selector_initialize(&selector->backend, self, loop);
|
|
344
329
|
int result = kqueue();
|
|
345
330
|
|
|
346
331
|
if (result == -1) {
|
|
@@ -396,7 +381,7 @@ VALUE IO_Event_Selector_KQueue_transfer(VALUE self)
|
|
|
396
381
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
397
382
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
398
383
|
|
|
399
|
-
return
|
|
384
|
+
return IO_Event_Selector_loop_yield(&selector->backend);
|
|
400
385
|
}
|
|
401
386
|
|
|
402
387
|
VALUE IO_Event_Selector_KQueue_resume(int argc, VALUE *argv, VALUE self)
|
|
@@ -420,7 +405,7 @@ VALUE IO_Event_Selector_KQueue_push(VALUE self, VALUE fiber)
|
|
|
420
405
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
421
406
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
422
407
|
|
|
423
|
-
|
|
408
|
+
IO_Event_Selector_ready_push(&selector->backend, fiber);
|
|
424
409
|
|
|
425
410
|
return Qnil;
|
|
426
411
|
}
|
|
@@ -459,6 +444,7 @@ void process_prewait(pid_t pid) {
|
|
|
459
444
|
result = waitid(P_PID, pid, &info, WEXITED | WNOWAIT);
|
|
460
445
|
// This can sometimes get interrupted by SIGCHLD.
|
|
461
446
|
} while (result == -1 && errno == EINTR);
|
|
447
|
+
|
|
462
448
|
if (result == -1) {
|
|
463
449
|
rb_sys_fail("process_prewait:waitid");
|
|
464
450
|
}
|
|
@@ -469,7 +455,7 @@ static
|
|
|
469
455
|
VALUE process_wait_transfer(VALUE _arguments) {
|
|
470
456
|
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
|
471
457
|
|
|
472
|
-
|
|
458
|
+
IO_Event_Selector_loop_yield(&arguments->selector->backend);
|
|
473
459
|
|
|
474
460
|
if (arguments->waiting->ready) {
|
|
475
461
|
process_prewait(arguments->pid);
|
|
@@ -503,6 +489,8 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
|
503
489
|
.events = IO_EVENT_EXIT,
|
|
504
490
|
};
|
|
505
491
|
|
|
492
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
493
|
+
|
|
506
494
|
struct process_wait_arguments process_wait_arguments = {
|
|
507
495
|
.selector = selector,
|
|
508
496
|
.waiting = &waiting,
|
|
@@ -543,7 +531,7 @@ static
|
|
|
543
531
|
VALUE io_wait_transfer(VALUE _arguments) {
|
|
544
532
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
|
545
533
|
|
|
546
|
-
|
|
534
|
+
IO_Event_Selector_loop_yield(&arguments->selector->backend);
|
|
547
535
|
|
|
548
536
|
if (arguments->waiting->ready) {
|
|
549
537
|
return RB_INT2NUM(arguments->waiting->ready);
|
|
@@ -566,6 +554,8 @@ VALUE IO_Event_Selector_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
566
554
|
.events = RB_NUM2INT(events),
|
|
567
555
|
};
|
|
568
556
|
|
|
557
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
558
|
+
|
|
569
559
|
int result = IO_Event_Selector_KQueue_Waiting_register(selector, descriptor, &waiting);
|
|
570
560
|
if (result == -1) {
|
|
571
561
|
rb_sys_fail("IO_Event_Selector_KQueue_io_wait:IO_Event_Selector_KQueue_Waiting_register");
|
|
@@ -669,6 +659,8 @@ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
669
659
|
.offset = offset,
|
|
670
660
|
};
|
|
671
661
|
|
|
662
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
663
|
+
|
|
672
664
|
return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
|
|
673
665
|
}
|
|
674
666
|
|
|
@@ -775,6 +767,8 @@ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
775
767
|
.offset = offset,
|
|
776
768
|
};
|
|
777
769
|
|
|
770
|
+
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
771
|
+
|
|
778
772
|
return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
|
|
779
773
|
}
|
|
780
774
|
|
|
@@ -903,7 +897,7 @@ int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, u
|
|
|
903
897
|
IO_Event_List_append(node, saved);
|
|
904
898
|
|
|
905
899
|
waiting->ready = matching_events;
|
|
906
|
-
|
|
900
|
+
IO_Event_Selector_loop_resume(&selector->backend, waiting->fiber, 0, NULL);
|
|
907
901
|
|
|
908
902
|
node = saved->tail;
|
|
909
903
|
IO_Event_List_pop(saved);
|
|
@@ -960,7 +954,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
960
954
|
selector->idle_duration.tv_sec = 0;
|
|
961
955
|
selector->idle_duration.tv_nsec = 0;
|
|
962
956
|
|
|
963
|
-
int ready =
|
|
957
|
+
int ready = IO_Event_Selector_ready_flush(&selector->backend);
|
|
964
958
|
|
|
965
959
|
struct select_arguments arguments = {
|
|
966
960
|
.selector = selector,
|
|
@@ -981,7 +975,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
981
975
|
// Non-comprehensive testing shows this gives a 1.5x speedup.
|
|
982
976
|
|
|
983
977
|
// First do the syscall with no timeout to get any immediately available events:
|
|
984
|
-
if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl timeout="
|
|
978
|
+
if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl timeout=" IO_EVENT_TIME_PRINTF_TIMESPEC "\r\n", IO_EVENT_TIME_PRINTF_TIMESPEC_ARGUMENTS(arguments.storage));
|
|
985
979
|
select_internal_with_gvl(&arguments);
|
|
986
980
|
if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl done\r\n");
|
|
987
981
|
|
|
@@ -997,14 +991,14 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
997
991
|
arguments.count = KQUEUE_MAX_EVENTS;
|
|
998
992
|
|
|
999
993
|
struct timespec start_time;
|
|
1000
|
-
|
|
994
|
+
IO_Event_Time_current(&start_time);
|
|
1001
995
|
|
|
1002
|
-
if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout="
|
|
996
|
+
if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout=" IO_EVENT_TIME_PRINTF_TIMESPEC "\n", IO_EVENT_TIME_PRINTF_TIMESPEC_ARGUMENTS(arguments.storage));
|
|
1003
997
|
select_internal_without_gvl(&arguments);
|
|
1004
998
|
|
|
1005
999
|
struct timespec end_time;
|
|
1006
|
-
|
|
1007
|
-
|
|
1000
|
+
IO_Event_Time_current(&end_time);
|
|
1001
|
+
IO_Event_Time_elapsed(&start_time, &end_time, &selector->idle_duration);
|
|
1008
1002
|
}
|
|
1009
1003
|
}
|
|
1010
1004
|
|
|
@@ -1052,8 +1046,7 @@ VALUE IO_Event_Selector_KQueue_wakeup(VALUE self) {
|
|
|
1052
1046
|
}
|
|
1053
1047
|
|
|
1054
1048
|
void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
|
|
1055
|
-
IO_Event_Selector_KQueue = rb_define_class_under(IO_Event_Selector, "KQueue", rb_cObject);
|
|
1056
|
-
rb_gc_register_mark_object(IO_Event_Selector_KQueue);
|
|
1049
|
+
VALUE IO_Event_Selector_KQueue = rb_define_class_under(IO_Event_Selector, "KQueue", rb_cObject);
|
|
1057
1050
|
|
|
1058
1051
|
rb_define_alloc_func(IO_Event_Selector_KQueue, IO_Event_Selector_KQueue_allocate);
|
|
1059
1052
|
rb_define_method(IO_Event_Selector_KQueue, "initialize", IO_Event_Selector_KQueue_initialize, 1);
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
// in the Software without restriction, including without limitation the rights
|
|
6
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
// furnished to do so, subject to the following conditions:
|
|
9
|
-
//
|
|
10
|
-
// The above copyright notice and this permission notice shall be included in
|
|
11
|
-
// all copies or substantial portions of the Software.
|
|
12
|
-
//
|
|
13
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
// THE SOFTWARE.
|
|
1
|
+
// Released under the MIT License.
|
|
2
|
+
// Copyright, 2021-2025, by Samuel Williams.
|
|
20
3
|
|
|
21
4
|
#pragma once
|
|
22
5
|
|
|
@@ -1,22 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
// in the Software without restriction, including without limitation the rights
|
|
6
|
-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
// furnished to do so, subject to the following conditions:
|
|
9
|
-
//
|
|
10
|
-
// The above copyright notice and this permission notice shall be included in
|
|
11
|
-
// all copies or substantial portions of the Software.
|
|
12
|
-
//
|
|
13
|
-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
// THE SOFTWARE.
|
|
1
|
+
// Released under the MIT License.
|
|
2
|
+
// Copyright, 2021-2025, by Samuel Williams.
|
|
20
3
|
|
|
21
4
|
#include <ruby.h>
|
|
22
5
|
|