io-event 1.2.2 → 1.3.3

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.
@@ -0,0 +1,88 @@
1
+ // Released under the MIT License.
2
+ // Copyright, 2023, by Samuel Williams.
3
+
4
+ #include <stdio.h>
5
+ #include <assert.h>
6
+
7
+ struct IO_Event_List_Type {
8
+ };
9
+
10
+ struct IO_Event_List {
11
+ struct IO_Event_List *head, *tail;
12
+ struct IO_Event_List_Type *type;
13
+ };
14
+
15
+ inline static void IO_Event_List_initialize(struct IO_Event_List *list)
16
+ {
17
+ list->head = list->tail = list;
18
+ list->type = 0;
19
+ }
20
+
21
+ inline static void IO_Event_List_clear(struct IO_Event_List *list)
22
+ {
23
+ list->head = list->tail = NULL;
24
+ list->type = 0;
25
+ }
26
+
27
+ // Append an item to the end of the list.
28
+ inline static void IO_Event_List_append(struct IO_Event_List *list, struct IO_Event_List *node)
29
+ {
30
+ assert(node->head == NULL);
31
+ assert(node->tail == NULL);
32
+
33
+ struct IO_Event_List *head = list->head;
34
+ node->tail = list;
35
+ node->head = head;
36
+ list->head = node;
37
+ head->tail = node;
38
+ }
39
+
40
+ inline static void IO_Event_List_prepend(struct IO_Event_List *list, struct IO_Event_List *node)
41
+ {
42
+ assert(node->head == NULL);
43
+ assert(node->tail == NULL);
44
+
45
+ struct IO_Event_List *tail = list->tail;
46
+ node->head = list;
47
+ node->tail = tail;
48
+ list->tail = node;
49
+ tail->head = node;
50
+ }
51
+
52
+ // Pop an item from the list.
53
+ inline static void IO_Event_List_pop(struct IO_Event_List *node)
54
+ {
55
+ assert(node->head != NULL);
56
+ assert(node->tail != NULL);
57
+
58
+ struct IO_Event_List *head = node->head;
59
+ struct IO_Event_List *tail = node->tail;
60
+
61
+ head->tail = tail;
62
+ tail->head = head;
63
+ node->head = node->tail = NULL;
64
+ }
65
+
66
+ inline static void IO_Event_List_free(struct IO_Event_List *node)
67
+ {
68
+ if (node->head && node->tail) {
69
+ IO_Event_List_pop(node);
70
+ }
71
+ }
72
+
73
+ inline static int IO_Event_List_empty(struct IO_Event_List *list)
74
+ {
75
+ return list->head == list->tail;
76
+ }
77
+
78
+ inline static void IO_Event_List_immutable_each(struct IO_Event_List *list, void (*callback)(struct IO_Event_List *node))
79
+ {
80
+ struct IO_Event_List *node = list->tail;
81
+
82
+ while (node != list) {
83
+ if (node->type)
84
+ callback(node);
85
+
86
+ node = node->tail;
87
+ }
88
+ }
@@ -25,10 +25,6 @@ static const int DEBUG = 0;
25
25
 
26
26
  static ID id_transfer, id_alive_p;
27
27
 
28
- #ifndef HAVE_RB_PROCESS_STATUS_WAIT
29
- static VALUE process_wnohang;
30
- #endif
31
-
32
28
  VALUE IO_Event_Selector_fiber_transfer(VALUE fiber, int argc, VALUE *argv) {
33
29
  // TODO Consider introducing something like `rb_fiber_scheduler_transfer(...)`.
34
30
  #ifdef HAVE__RB_FIBER_TRANSFER
@@ -76,9 +72,9 @@ int IO_Event_Selector_io_descriptor(VALUE io) {
76
72
  static ID id_wait;
77
73
  static VALUE rb_Process_Status = Qnil;
78
74
 
79
- VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid)
75
+ VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid, int flags)
80
76
  {
81
- return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), process_wnohang);
77
+ return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), INT2NUM(flags | WNOHANG));
82
78
  }
83
79
  #endif
84
80
 
@@ -157,7 +153,6 @@ void Init_IO_Event_Selector(VALUE IO_Event_Selector) {
157
153
 
158
154
  #ifndef HAVE_RB_PROCESS_STATUS_WAIT
159
155
  id_wait = rb_intern("wait");
160
- process_wnohang = rb_const_get(rb_mProcess, rb_intern("WNOHANG"));
161
156
  rb_Process_Status = rb_const_get_at(rb_mProcess, rb_intern("Status"));
162
157
  rb_gc_register_mark_object(rb_Process_Status);
163
158
  #endif
@@ -174,23 +169,23 @@ struct wait_and_transfer_arguments {
174
169
  };
175
170
 
176
171
  static void queue_pop(struct IO_Event_Selector *backend, struct IO_Event_Selector_Queue *waiting) {
177
- if (waiting->behind) {
178
- waiting->behind->infront = waiting->infront;
172
+ if (waiting->head) {
173
+ waiting->head->tail = waiting->tail;
179
174
  } else {
180
- backend->waiting = waiting->infront;
175
+ backend->waiting = waiting->tail;
181
176
  }
182
177
 
183
- if (waiting->infront) {
184
- waiting->infront->behind = waiting->behind;
178
+ if (waiting->tail) {
179
+ waiting->tail->head = waiting->head;
185
180
  } else {
186
- backend->ready = waiting->behind;
181
+ backend->ready = waiting->head;
187
182
  }
188
183
  }
189
184
 
190
185
  static void queue_push(struct IO_Event_Selector *backend, struct IO_Event_Selector_Queue *waiting) {
191
186
  if (backend->waiting) {
192
- backend->waiting->behind = waiting;
193
- waiting->infront = backend->waiting;
187
+ backend->waiting->head = waiting;
188
+ waiting->tail = backend->waiting;
194
189
  } else {
195
190
  backend->ready = waiting;
196
191
  }
@@ -221,8 +216,8 @@ VALUE IO_Event_Selector_resume(struct IO_Event_Selector *backend, int argc, VALU
221
216
  rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
222
217
 
223
218
  struct IO_Event_Selector_Queue waiting = {
224
- .behind = NULL,
225
- .infront = NULL,
219
+ .head = NULL,
220
+ .tail = NULL,
226
221
  .flags = IO_EVENT_SELECTOR_QUEUE_FIBER,
227
222
  .fiber = rb_fiber_current()
228
223
  };
@@ -254,8 +249,8 @@ VALUE IO_Event_Selector_raise(struct IO_Event_Selector *backend, int argc, VALUE
254
249
  rb_check_arity(argc, 2, UNLIMITED_ARGUMENTS);
255
250
 
256
251
  struct IO_Event_Selector_Queue waiting = {
257
- .behind = NULL,
258
- .infront = NULL,
252
+ .head = NULL,
253
+ .tail = NULL,
259
254
  .flags = IO_EVENT_SELECTOR_QUEUE_FIBER,
260
255
  .fiber = rb_fiber_current()
261
256
  };
@@ -276,8 +271,8 @@ void IO_Event_Selector_queue_push(struct IO_Event_Selector *backend, VALUE fiber
276
271
  {
277
272
  struct IO_Event_Selector_Queue *waiting = malloc(sizeof(struct IO_Event_Selector_Queue));
278
273
 
279
- waiting->behind = NULL;
280
- waiting->infront = NULL;
274
+ waiting->head = NULL;
275
+ waiting->tail = NULL;
281
276
  waiting->flags = IO_EVENT_SELECTOR_QUEUE_INTERNAL;
282
277
  waiting->fiber = fiber;
283
278
 
@@ -40,7 +40,10 @@ enum IO_Event {
40
40
  IO_EVENT_PRIORITY = 2,
41
41
  IO_EVENT_WRITABLE = 4,
42
42
  IO_EVENT_ERROR = 8,
43
- IO_EVENT_HANGUP = 16
43
+ IO_EVENT_HANGUP = 16,
44
+
45
+ // Used by kqueue to differentiate between process exit and file descriptor events:
46
+ IO_EVENT_EXIT = 32,
44
47
  };
45
48
 
46
49
  void Init_IO_Event_Selector(VALUE IO_Event_Selector);
@@ -63,10 +66,11 @@ VALUE IO_Event_Selector_fiber_raise(VALUE fiber, int argc, VALUE *argv);
63
66
  int IO_Event_Selector_io_descriptor(VALUE io);
64
67
  #endif
65
68
 
69
+ // Reap a process without hanging.
66
70
  #ifdef HAVE_RB_PROCESS_STATUS_WAIT
67
- #define IO_Event_Selector_process_status_wait(pid) rb_process_status_wait(pid)
71
+ #define IO_Event_Selector_process_status_wait(pid, flags) rb_process_status_wait(pid, flags | WNOHANG)
68
72
  #else
69
- VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid);
73
+ VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid, int flags);
70
74
  #endif
71
75
 
72
76
  int IO_Event_Selector_nonblock_set(int file_descriptor);
@@ -78,8 +82,8 @@ enum IO_Event_Selector_Queue_Flags {
78
82
  };
79
83
 
80
84
  struct IO_Event_Selector_Queue {
81
- struct IO_Event_Selector_Queue *behind;
82
- struct IO_Event_Selector_Queue *infront;
85
+ struct IO_Event_Selector_Queue *head;
86
+ struct IO_Event_Selector_Queue *tail;
83
87
 
84
88
  enum IO_Event_Selector_Queue_Flags flags;
85
89
 
@@ -106,12 +110,23 @@ void IO_Event_Selector_initialize(struct IO_Event_Selector *backend, VALUE loop)
106
110
 
107
111
  static inline
108
112
  void IO_Event_Selector_mark(struct IO_Event_Selector *backend) {
109
- rb_gc_mark(backend->loop);
113
+ rb_gc_mark_movable(backend->loop);
114
+
115
+ struct IO_Event_Selector_Queue *ready = backend->ready;
116
+ while (ready) {
117
+ rb_gc_mark_movable(ready->fiber);
118
+ ready = ready->head;
119
+ }
120
+ }
121
+
122
+ static inline
123
+ void IO_Event_Selector_compact(struct IO_Event_Selector *backend) {
124
+ backend->loop = rb_gc_location(backend->loop);
110
125
 
111
126
  struct IO_Event_Selector_Queue *ready = backend->ready;
112
127
  while (ready) {
113
- rb_gc_mark(ready->fiber);
114
- ready = ready->behind;
128
+ ready->fiber = rb_gc_location(ready->fiber);
129
+ ready = ready->head;
115
130
  }
116
131
  }
117
132