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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/ext/extconf.rb +26 -13
  4. data/ext/io/event/{selector/array.h → array.h} +74 -18
  5. data/ext/io/event/event.c +9 -26
  6. data/ext/io/event/event.h +2 -19
  7. data/ext/io/event/fiber.c +63 -0
  8. data/ext/io/event/fiber.h +23 -0
  9. data/ext/io/event/interrupt.c +19 -27
  10. data/ext/io/event/interrupt.h +2 -19
  11. data/ext/io/event/{selector/list.h → list.h} +20 -2
  12. data/ext/io/event/profiler.c +505 -0
  13. data/ext/io/event/profiler.h +8 -0
  14. data/ext/io/event/selector/epoll.c +41 -43
  15. data/ext/io/event/selector/epoll.h +2 -19
  16. data/ext/io/event/selector/kqueue.c +34 -41
  17. data/ext/io/event/selector/kqueue.h +2 -19
  18. data/ext/io/event/selector/pidfd.c +2 -19
  19. data/ext/io/event/selector/selector.c +65 -102
  20. data/ext/io/event/selector/selector.h +51 -46
  21. data/ext/io/event/selector/uring.c +130 -47
  22. data/ext/io/event/selector/uring.h +2 -19
  23. data/ext/io/event/time.c +35 -0
  24. data/ext/io/event/time.h +17 -0
  25. data/lib/io/event/debug/selector.rb +44 -4
  26. data/lib/io/event/interrupt.rb +2 -2
  27. data/lib/io/event/native.rb +11 -0
  28. data/lib/io/event/priority_heap.rb +13 -14
  29. data/lib/io/event/profiler.rb +18 -0
  30. data/lib/io/event/selector/nonblock.rb +6 -2
  31. data/lib/io/event/selector/select.rb +25 -5
  32. data/lib/io/event/selector.rb +15 -5
  33. data/lib/io/event/support.rb +23 -2
  34. data/lib/io/event/timers.rb +42 -4
  35. data/lib/io/event/version.rb +4 -2
  36. data/lib/io/event.rb +5 -11
  37. data/license.md +4 -1
  38. data/readme.md +22 -4
  39. data/releases.md +57 -0
  40. data.tar.gz.sig +0 -0
  41. metadata +20 -11
  42. metadata.gz.sig +0 -0
@@ -1,27 +1,10 @@
1
- // Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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 = "IO_Event::Backend::EPoll",
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 = 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 = 0;
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
- IO_Event_Array_allocate(&selector->descriptors, 1024, sizeof(struct IO_Event_Selector_EPoll_Descriptor));
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 IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
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
- IO_Event_Selector_queue_push(&selector->backend, fiber);
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
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
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
- int result = IO_Event_Selector_EPoll_Waiting_register(selector, 0, descriptor, &waiting);
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
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
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
- IO_Event_Selector_queue_push(&selector->backend, fiber);
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
- IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
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 = IO_Event_Selector_queue_flush(&selector->backend);
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
- IO_Event_Selector_current_time(&start_time);
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
- IO_Event_Selector_current_time(&end_time);
1014
- IO_Event_Selector_elapsed_time(&start_time, &end_time, &selector->idle_duration);
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
- // Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
- // Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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 = "IO_Event::Backend::KQueue",
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
- IO_Event_Array_allocate(&selector->descriptors, 1024, sizeof(struct IO_Event_Selector_KQueue_Descriptor));
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 IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
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
- IO_Event_Selector_queue_push(&selector->backend, fiber);
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
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
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
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
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
- IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
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 = IO_Event_Selector_queue_flush(&selector->backend);
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=" PRINTF_TIMESPEC "\r\n", PRINTF_TIMESPEC_ARGS(arguments.storage));
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
- IO_Event_Selector_current_time(&start_time);
994
+ IO_Event_Time_current(&start_time);
1001
995
 
1002
- if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout=" PRINTF_TIMESPEC "\n", PRINTF_TIMESPEC_ARGS(arguments.storage));
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
- IO_Event_Selector_current_time(&end_time);
1007
- IO_Event_Selector_elapsed_time(&start_time, &end_time, &selector->idle_duration);
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
- // Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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
- // Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
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