io-event 1.7.4 → 1.10.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9761a366e91db284c56c77d2ec19db8b6d652d98f2fe39750108e685ff3c2b12
4
- data.tar.gz: 3d9d1fab942ec257073a317cecefb06248952e5e7c2518f0298d60b476ec1905
3
+ metadata.gz: ec418d3289f8648ac13d7808bbe8d56b50a3b4cf518f61da116c56c3c345daa9
4
+ data.tar.gz: 8de6423981f2bfb2da54e0cd99e493787253a2c2c83bc644f72fffdcf52a295c
5
5
  SHA512:
6
- metadata.gz: 4e7c4790ad17bb655136e1ce25b006c4bc97906b7b46eac2abddddd100eb882d19569da27ae195455b457ea3f243bd8ebe6475a9d0255f1bd11bf33cf66edd15
7
- data.tar.gz: 00b9bc9c8ad79828b50b67fdf9fb9a9d25664fb5d9b8c77eb70aa708ee719974b07ba6ed4c3098d76c9b33132061070d36bc39c2c5c707448a9400cef0f2a4ed
6
+ metadata.gz: 9fd70cf075b1703fd8e4659fa2adaf7381f7d5523e47e8700eeda233a01679c671ebb8197fd06f525da17b7a30332e996dd087874503f8ff7a594b8f88268554
7
+ data.tar.gz: c42e23c74e1069fb199fd1044b7fc487b8f1587294703a19362242bbbfa23c21fbba36a6a114fafb978ddc4cfcd2a21d2a6c7b7c3d3dc1c4a08094ca9b51bd2a
checksums.yaml.gz.sig CHANGED
Binary file
data/ext/extconf.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  # Released under the MIT License.
5
- # Copyright, 2021-2024, by Samuel Williams.
5
+ # Copyright, 2021-2025, by Samuel Williams.
6
6
  # Copyright, 2023, by Math Ieu.
7
7
 
8
8
  return if RUBY_DESCRIPTION =~ /jruby/
@@ -22,7 +22,7 @@ if ENV.key?("RUBY_DEBUG")
22
22
  $CFLAGS << " -DRUBY_DEBUG -O0"
23
23
  end
24
24
 
25
- $srcs = ["io/event/event.c", "io/event/selector/selector.c"]
25
+ $srcs = ["io/event/event.c", "io/event/time.c", "io/event/fiber.c", "io/event/selector/selector.c"]
26
26
  $VPATH << "$(srcdir)/io/event"
27
27
  $VPATH << "$(srcdir)/io/event/selector"
28
28
 
@@ -28,7 +28,7 @@ struct IO_Event_Array {
28
28
  void (*element_free)(void*);
29
29
  };
30
30
 
31
- inline static int IO_Event_Array_allocate(struct IO_Event_Array *array, size_t count, size_t element_size)
31
+ inline static int IO_Event_Array_initialize(struct IO_Event_Array *array, size_t count, size_t element_size)
32
32
  {
33
33
  array->limit = 0;
34
34
  array->element_size = element_size;
@@ -153,6 +153,28 @@ inline static void* IO_Event_Array_lookup(struct IO_Event_Array *array, size_t i
153
153
  return *element;
154
154
  }
155
155
 
156
+ inline static void* IO_Event_Array_last(struct IO_Event_Array *array)
157
+ {
158
+ if (array->limit == 0) return NULL;
159
+ else return array->base[array->limit - 1];
160
+ }
161
+
162
+ inline static void IO_Event_Array_truncate(struct IO_Event_Array *array, size_t limit)
163
+ {
164
+ if (limit < array->limit) {
165
+ for (size_t i = limit; i < array->limit; i += 1) {
166
+ void **element = array->base + i;
167
+ if (*element) {
168
+ array->element_free(*element);
169
+ free(*element);
170
+ *element = NULL;
171
+ }
172
+ }
173
+
174
+ array->limit = limit;
175
+ }
176
+ }
177
+
156
178
  // Push a new element onto the end of the array.
157
179
  inline static void* IO_Event_Array_push(struct IO_Event_Array *array)
158
180
  {
data/ext/io/event/event.c CHANGED
@@ -1,24 +1,8 @@
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 "event.h"
5
+ #include "fiber.h"
22
6
  #include "selector/selector.h"
23
7
 
24
8
  void Init_IO_Event(void)
@@ -28,8 +12,10 @@ void Init_IO_Event(void)
28
12
  #endif
29
13
 
30
14
  VALUE IO_Event = rb_define_module_under(rb_cIO, "Event");
31
- VALUE IO_Event_Selector = rb_define_module_under(IO_Event, "Selector");
32
15
 
16
+ Init_IO_Event_Fiber(IO_Event);
17
+
18
+ VALUE IO_Event_Selector = rb_define_module_under(IO_Event, "Selector");
33
19
  Init_IO_Event_Selector(IO_Event_Selector);
34
20
 
35
21
  #ifdef IO_EVENT_SELECTOR_URING
data/ext/io/event/event.h CHANGED
@@ -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
 
@@ -0,0 +1,63 @@
1
+ // Released under the MIT License.
2
+ // Copyright, 2025, by Samuel Williams.
3
+
4
+ #include "fiber.h"
5
+
6
+ static ID id_transfer, id_alive_p;
7
+
8
+ VALUE IO_Event_Fiber_transfer(VALUE fiber, int argc, VALUE *argv) {
9
+ // TODO Consider introducing something like `rb_fiber_scheduler_transfer(...)`.
10
+ #ifdef HAVE__RB_FIBER_TRANSFER
11
+ if (RTEST(rb_obj_is_fiber(fiber))) {
12
+ if (RTEST(rb_fiber_alive_p(fiber))) {
13
+ return rb_fiber_transfer(fiber, argc, argv);
14
+ }
15
+
16
+ // If it's a fiber, but dead, we are done.
17
+ return Qnil;
18
+ }
19
+ #endif
20
+ if (RTEST(rb_funcall(fiber, id_alive_p, 0))) {
21
+ return rb_funcallv(fiber, id_transfer, argc, argv);
22
+ }
23
+
24
+ return Qnil;
25
+ }
26
+
27
+ #ifndef HAVE__RB_FIBER_RAISE
28
+ static ID id_raise;
29
+
30
+ VALUE IO_Event_Fiber_raise(VALUE fiber, int argc, VALUE *argv) {
31
+ return rb_funcallv(fiber, id_raise, argc, argv);
32
+ }
33
+ #endif
34
+
35
+ #ifndef HAVE_RB_FIBER_CURRENT
36
+ static ID id_current;
37
+
38
+ static VALUE IO_Event_Fiber_current(void) {
39
+ return rb_funcall(rb_cFiber, id_current, 0);
40
+ }
41
+ #endif
42
+
43
+ // There is no public interface for this... yet.
44
+ static ID id_blocking_p;
45
+
46
+ int IO_Event_Fiber_blocking(VALUE fiber) {
47
+ return RTEST(rb_funcall(fiber, id_blocking_p, 0));
48
+ }
49
+
50
+ void Init_IO_Event_Fiber(VALUE IO_Event) {
51
+ id_transfer = rb_intern("transfer");
52
+ id_alive_p = rb_intern("alive?");
53
+
54
+ #ifndef HAVE__RB_FIBER_RAISE
55
+ id_raise = rb_intern("raise");
56
+ #endif
57
+
58
+ #ifndef HAVE_RB_FIBER_CURRENT
59
+ id_current = rb_intern("current");
60
+ #endif
61
+
62
+ id_blocking_p = rb_intern("blocking?");
63
+ }
@@ -0,0 +1,23 @@
1
+ // Released under the MIT License.
2
+ // Copyright, 2025, by Samuel Williams.
3
+
4
+ #pragma once
5
+
6
+ #include <ruby.h>
7
+
8
+ VALUE IO_Event_Fiber_transfer(VALUE fiber, int argc, VALUE *argv);
9
+
10
+ #ifdef HAVE__RB_FIBER_RAISE
11
+ #define IO_Event_Fiber_raise(fiber, argc, argv) rb_fiber_raise(fiber, argc, argv)
12
+ #else
13
+ VALUE IO_Event_Fiber_raise(VALUE fiber, int argc, VALUE *argv);
14
+ #endif
15
+
16
+ #ifdef HAVE_RB_FIBER_CURRENT
17
+ #define IO_Event_Fiber_current() rb_fiber_current()
18
+ #else
19
+ VALUE IO_Event_Fiber_current(void);
20
+ #endif
21
+
22
+ int IO_Event_Fiber_blocking(VALUE fiber);
23
+ void Init_IO_Event_Fiber(VALUE IO_Event);
@@ -1,24 +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.
20
-
21
- // static const int DEBUG = 0;
1
+ // Released under the MIT License.
2
+ // Copyright, 2021-2025, by Samuel Williams.
22
3
 
23
4
  #include "interrupt.h"
24
5
  #include <unistd.h>
@@ -95,9 +76,11 @@ void IO_Event_Interrupt_signal(struct IO_Event_Interrupt *interrupt)
95
76
  ssize_t result = write(interrupt->descriptor[1], ".", 1);
96
77
 
97
78
  if (result == -1) {
98
- if (errno == EAGAIN || errno == EWOULDBLOCK) return;
99
-
100
- rb_sys_fail("IO_Event_Interrupt_signal:write");
79
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
80
+ // If we can't write to the pipe, it means the other end is full. In that case, we can be sure that the other end has already been woken up or is about to be woken up.
81
+ } else {
82
+ rb_sys_fail("IO_Event_Interrupt_signal:write");
83
+ }
101
84
  }
102
85
  }
103
86
 
@@ -107,9 +90,11 @@ void IO_Event_Interrupt_clear(struct IO_Event_Interrupt *interrupt)
107
90
  ssize_t result = read(interrupt->descriptor[0], buffer, sizeof(buffer));
108
91
 
109
92
  if (result == -1) {
110
- if (errno == EAGAIN || errno == EWOULDBLOCK) return;
111
-
112
- rb_sys_fail("IO_Event_Interrupt_clear:read");
93
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
94
+ // If we can't read from the pipe, it means the other end is empty. In that case, we can be sure that the other end is already clear.
95
+ } else {
96
+ rb_sys_fail("IO_Event_Interrupt_clear:read");
97
+ }
113
98
  }
114
99
  }
115
100
  #endif
@@ -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,5 +1,5 @@
1
1
  // Released under the MIT License.
2
- // Copyright, 2023, by Samuel Williams.
2
+ // Copyright, 2023-2025, by Samuel Williams.
3
3
 
4
4
  #include <ruby.h>
5
5
  #include <stdio.h>
@@ -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>
@@ -174,7 +157,7 @@ size_t IO_Event_Selector_EPoll_Type_size(const void *_selector)
174
157
  }
175
158
 
176
159
  static const rb_data_type_t IO_Event_Selector_EPoll_Type = {
177
- .wrap_struct_name = "IO_Event::Backend::EPoll",
160
+ .wrap_struct_name = "IO::Event::Backend::EPoll",
178
161
  .function = {
179
162
  .dmark = IO_Event_Selector_EPoll_Type_mark,
180
163
  .dcompact = IO_Event_Selector_EPoll_Type_compact,
@@ -337,9 +320,9 @@ VALUE IO_Event_Selector_EPoll_allocate(VALUE self) {
337
320
 
338
321
  selector->descriptors.element_initialize = IO_Event_Selector_EPoll_Descriptor_initialize;
339
322
  selector->descriptors.element_free = IO_Event_Selector_EPoll_Descriptor_free;
340
- int result = IO_Event_Array_allocate(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, 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));
341
324
  if (result < 0) {
342
- rb_sys_fail("IO_Event_Selector_EPoll_allocate:IO_Event_Array_allocate");
325
+ rb_sys_fail("IO_Event_Selector_EPoll_allocate:IO_Event_Array_initialize");
343
326
  }
344
327
 
345
328
  return instance;
@@ -411,7 +394,7 @@ VALUE IO_Event_Selector_EPoll_transfer(VALUE self)
411
394
  struct IO_Event_Selector_EPoll *selector = NULL;
412
395
  TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
413
396
 
414
- return IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
397
+ return IO_Event_Selector_loop_yield(&selector->backend);
415
398
  }
416
399
 
417
400
  VALUE IO_Event_Selector_EPoll_resume(int argc, VALUE *argv, VALUE self)
@@ -435,7 +418,7 @@ VALUE IO_Event_Selector_EPoll_push(VALUE self, VALUE fiber)
435
418
  struct IO_Event_Selector_EPoll *selector = NULL;
436
419
  TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
437
420
 
438
- IO_Event_Selector_queue_push(&selector->backend, fiber);
421
+ IO_Event_Selector_ready_push(&selector->backend, fiber);
439
422
 
440
423
  return Qnil;
441
424
  }
@@ -467,7 +450,7 @@ static
467
450
  VALUE process_wait_transfer(VALUE _arguments) {
468
451
  struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
469
452
 
470
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
453
+ IO_Event_Selector_loop_yield(&arguments->selector->backend);
471
454
 
472
455
  if (arguments->waiting->ready) {
473
456
  return IO_Event_Selector_process_status_wait(arguments->pid, arguments->flags);
@@ -519,7 +502,7 @@ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid,
519
502
 
520
503
  RB_OBJ_WRITTEN(self, Qundef, fiber);
521
504
 
522
- int result = IO_Event_Selector_EPoll_Waiting_register(selector, 0, descriptor, &waiting);
505
+ int result = IO_Event_Selector_EPoll_Waiting_register(selector, _pid, descriptor, &waiting);
523
506
 
524
507
  if (result == -1) {
525
508
  close(descriptor);
@@ -555,7 +538,7 @@ static
555
538
  VALUE io_wait_transfer(VALUE _arguments) {
556
539
  struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
557
540
 
558
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
541
+ IO_Event_Selector_loop_yield(&arguments->selector->backend);
559
542
 
560
543
  if (arguments->waiting->ready) {
561
544
  return RB_INT2NUM(arguments->waiting->ready);
@@ -584,7 +567,7 @@ VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
584
567
 
585
568
  if (result == -1) {
586
569
  if (errno == EPERM) {
587
- IO_Event_Selector_queue_push(&selector->backend, fiber);
570
+ IO_Event_Selector_ready_push(&selector->backend, fiber);
588
571
  IO_Event_Selector_yield(&selector->backend);
589
572
  return events;
590
573
  }
@@ -942,7 +925,7 @@ int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, con
942
925
 
943
926
  // Resume the fiber:
944
927
  waiting->ready = matching_events;
945
- IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
928
+ IO_Event_Selector_loop_resume(&selector->backend, waiting->fiber, 0, NULL);
946
929
 
947
930
  node = saved->tail;
948
931
  IO_Event_List_pop(saved);
@@ -994,7 +977,7 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
994
977
  selector->idle_duration.tv_sec = 0;
995
978
  selector->idle_duration.tv_nsec = 0;
996
979
 
997
- int ready = IO_Event_Selector_queue_flush(&selector->backend);
980
+ int ready = IO_Event_Selector_ready_flush(&selector->backend);
998
981
 
999
982
  struct select_arguments arguments = {
1000
983
  .selector = selector,
@@ -1020,14 +1003,14 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
1020
1003
 
1021
1004
  if (!timeout_nonblocking(arguments.timeout)) {
1022
1005
  struct timespec start_time;
1023
- IO_Event_Selector_current_time(&start_time);
1006
+ IO_Event_Time_current(&start_time);
1024
1007
 
1025
1008
  // Wait for events to occur:
1026
1009
  select_internal_without_gvl(&arguments);
1027
1010
 
1028
1011
  struct timespec end_time;
1029
- IO_Event_Selector_current_time(&end_time);
1030
- 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);
1031
1014
  }
1032
1015
  }
1033
1016
 
@@ -1052,7 +1035,25 @@ VALUE IO_Event_Selector_EPoll_wakeup(VALUE self) {
1052
1035
  return Qfalse;
1053
1036
  }
1054
1037
 
1038
+ static int IO_Event_Selector_EPoll_supported_p(void) {
1039
+ int fd = epoll_create1(EPOLL_CLOEXEC);
1040
+
1041
+ if (fd < 0) {
1042
+ rb_warn("epoll_create1() was available at compile time but failed at run time: %s\n", strerror(errno));
1043
+
1044
+ return 0;
1045
+ }
1046
+
1047
+ close(fd);
1048
+
1049
+ return 1;
1050
+ }
1051
+
1055
1052
  void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
1053
+ if (!IO_Event_Selector_EPoll_supported_p()) {
1054
+ return;
1055
+ }
1056
+
1056
1057
  VALUE IO_Event_Selector_EPoll = rb_define_class_under(IO_Event_Selector, "EPoll", rb_cObject);
1057
1058
 
1058
1059
  rb_define_alloc_func(IO_Event_Selector_EPoll, IO_Event_Selector_EPoll_allocate);
@@ -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>
@@ -173,7 +156,7 @@ size_t IO_Event_Selector_KQueue_Type_size(const void *_selector)
173
156
  }
174
157
 
175
158
  static const rb_data_type_t IO_Event_Selector_KQueue_Type = {
176
- .wrap_struct_name = "IO_Event::Backend::KQueue",
159
+ .wrap_struct_name = "IO::Event::Backend::KQueue",
177
160
  .function = {
178
161
  .dmark = IO_Event_Selector_KQueue_Type_mark,
179
162
  .dcompact = IO_Event_Selector_KQueue_Type_compact,
@@ -312,9 +295,9 @@ VALUE IO_Event_Selector_KQueue_allocate(VALUE self) {
312
295
  selector->descriptors.element_initialize = IO_Event_Selector_KQueue_Descriptor_initialize;
313
296
  selector->descriptors.element_free = IO_Event_Selector_KQueue_Descriptor_free;
314
297
 
315
- int result = IO_Event_Array_allocate(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_KQueue_Descriptor));
298
+ int result = IO_Event_Array_initialize(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_KQueue_Descriptor));
316
299
  if (result < 0) {
317
- rb_sys_fail("IO_Event_Selector_KQueue_allocate:IO_Event_Array_allocate");
300
+ rb_sys_fail("IO_Event_Selector_KQueue_allocate:IO_Event_Array_initialize");
318
301
  }
319
302
 
320
303
  return instance;
@@ -398,7 +381,7 @@ VALUE IO_Event_Selector_KQueue_transfer(VALUE self)
398
381
  struct IO_Event_Selector_KQueue *selector = NULL;
399
382
  TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
400
383
 
401
- return IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
384
+ return IO_Event_Selector_loop_yield(&selector->backend);
402
385
  }
403
386
 
404
387
  VALUE IO_Event_Selector_KQueue_resume(int argc, VALUE *argv, VALUE self)
@@ -422,7 +405,7 @@ VALUE IO_Event_Selector_KQueue_push(VALUE self, VALUE fiber)
422
405
  struct IO_Event_Selector_KQueue *selector = NULL;
423
406
  TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
424
407
 
425
- IO_Event_Selector_queue_push(&selector->backend, fiber);
408
+ IO_Event_Selector_ready_push(&selector->backend, fiber);
426
409
 
427
410
  return Qnil;
428
411
  }
@@ -472,7 +455,7 @@ static
472
455
  VALUE process_wait_transfer(VALUE _arguments) {
473
456
  struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
474
457
 
475
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
458
+ IO_Event_Selector_loop_yield(&arguments->selector->backend);
476
459
 
477
460
  if (arguments->waiting->ready) {
478
461
  process_prewait(arguments->pid);
@@ -548,7 +531,7 @@ static
548
531
  VALUE io_wait_transfer(VALUE _arguments) {
549
532
  struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
550
533
 
551
- IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
534
+ IO_Event_Selector_loop_yield(&arguments->selector->backend);
552
535
 
553
536
  if (arguments->waiting->ready) {
554
537
  return RB_INT2NUM(arguments->waiting->ready);
@@ -914,7 +897,7 @@ int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, u
914
897
  IO_Event_List_append(node, saved);
915
898
 
916
899
  waiting->ready = matching_events;
917
- IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
900
+ IO_Event_Selector_loop_resume(&selector->backend, waiting->fiber, 0, NULL);
918
901
 
919
902
  node = saved->tail;
920
903
  IO_Event_List_pop(saved);
@@ -971,7 +954,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
971
954
  selector->idle_duration.tv_sec = 0;
972
955
  selector->idle_duration.tv_nsec = 0;
973
956
 
974
- int ready = IO_Event_Selector_queue_flush(&selector->backend);
957
+ int ready = IO_Event_Selector_ready_flush(&selector->backend);
975
958
 
976
959
  struct select_arguments arguments = {
977
960
  .selector = selector,
@@ -992,7 +975,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
992
975
  // Non-comprehensive testing shows this gives a 1.5x speedup.
993
976
 
994
977
  // First do the syscall with no timeout to get any immediately available events:
995
- if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl timeout=" IO_EVENT_PRINTF_TIMESPEC "\r\n", IO_EVENT_PRINTF_TIMESPEC_ARGUMENTS(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));
996
979
  select_internal_with_gvl(&arguments);
997
980
  if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl done\r\n");
998
981
 
@@ -1008,14 +991,14 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
1008
991
  arguments.count = KQUEUE_MAX_EVENTS;
1009
992
 
1010
993
  struct timespec start_time;
1011
- IO_Event_Selector_current_time(&start_time);
994
+ IO_Event_Time_current(&start_time);
1012
995
 
1013
- if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout=" IO_EVENT_PRINTF_TIMESPEC "\n", IO_EVENT_PRINTF_TIMESPEC_ARGUMENTS(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));
1014
997
  select_internal_without_gvl(&arguments);
1015
998
 
1016
999
  struct timespec end_time;
1017
- IO_Event_Selector_current_time(&end_time);
1018
- 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);
1019
1002
  }
1020
1003
  }
1021
1004
 
@@ -1062,7 +1045,26 @@ VALUE IO_Event_Selector_KQueue_wakeup(VALUE self) {
1062
1045
  return Qfalse;
1063
1046
  }
1064
1047
 
1048
+
1049
+ static int IO_Event_Selector_KQueue_supported_p(void) {
1050
+ int fd = kqueue();
1051
+
1052
+ if (fd < 0) {
1053
+ rb_warn("kqueue() was available at compile time but failed at run time: %s\n", strerror(errno));
1054
+
1055
+ return 0;
1056
+ }
1057
+
1058
+ close(fd);
1059
+
1060
+ return 1;
1061
+ }
1062
+
1065
1063
  void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
1064
+ if (!IO_Event_Selector_KQueue_supported_p()) {
1065
+ return;
1066
+ }
1067
+
1066
1068
  VALUE IO_Event_Selector_KQueue = rb_define_class_under(IO_Event_Selector, "KQueue", rb_cObject);
1067
1069
 
1068
1070
  rb_define_alloc_func(IO_Event_Selector_KQueue, IO_Event_Selector_KQueue_allocate);