io-event 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,6 +20,8 @@
20
20
 
21
21
  #include "kqueue.h"
22
22
  #include "selector.h"
23
+ #include "list.h"
24
+ #include "array.h"
23
25
 
24
26
  #include <sys/epoll.h>
25
27
  #include <time.h>
@@ -36,47 +38,145 @@ static VALUE IO_Event_Selector_EPoll = Qnil;
36
38
 
37
39
  enum {EPOLL_MAX_EVENTS = 64};
38
40
 
39
- struct IO_Event_Selector_EPoll {
41
+ // This represents an actual fiber waiting for a specific event.
42
+ struct IO_Event_Selector_EPoll_Waiting
43
+ {
44
+ struct IO_Event_List list;
45
+
46
+ // The events the fiber is waiting for.
47
+ enum IO_Event events;
48
+
49
+ // The events that are currently ready.
50
+ enum IO_Event ready;
51
+
52
+ // The fiber value itself.
53
+ VALUE fiber;
54
+ };
55
+
56
+ struct IO_Event_Selector_EPoll
57
+ {
40
58
  struct IO_Event_Selector backend;
41
59
  int descriptor;
42
60
  int blocked;
61
+
43
62
  struct IO_Event_Interrupt interrupt;
63
+ struct IO_Event_Array descriptors;
44
64
  };
45
65
 
46
- void IO_Event_Selector_EPoll_Type_mark(void *_data)
66
+ // This represents zero or more fibers waiting for a specific descriptor.
67
+ struct IO_Event_Selector_EPoll_Descriptor
47
68
  {
48
- struct IO_Event_Selector_EPoll *data = _data;
49
- IO_Event_Selector_mark(&data->backend);
69
+ struct IO_Event_List list;
70
+
71
+ // The last IO object that was used to register events.
72
+ VALUE io;
73
+
74
+ // The union of all events we are waiting for:
75
+ enum IO_Event waiting_events;
76
+
77
+ // The union of events we are registered for:
78
+ enum IO_Event registered_events;
79
+ };
80
+
81
+ static
82
+ void IO_Event_Selector_EPoll_Waiting_mark(struct IO_Event_List *_waiting)
83
+ {
84
+ struct IO_Event_Selector_EPoll_Waiting *waiting = (void*)_waiting;
85
+
86
+ if (waiting->fiber) {
87
+ rb_gc_mark_movable(waiting->fiber);
88
+ }
50
89
  }
51
90
 
52
91
  static
53
- void close_internal(struct IO_Event_Selector_EPoll *data) {
54
- if (data->descriptor >= 0) {
55
- close(data->descriptor);
56
- data->descriptor = -1;
57
-
58
- IO_Event_Interrupt_close(&data->interrupt);
92
+ void IO_Event_Selector_EPoll_Descriptor_mark(void *_descriptor)
93
+ {
94
+ struct IO_Event_Selector_EPoll_Descriptor *descriptor = _descriptor;
95
+
96
+ IO_Event_List_immutable_each(&descriptor->list, IO_Event_Selector_EPoll_Waiting_mark);
97
+
98
+ if (descriptor->io) {
99
+ rb_gc_mark_movable(descriptor->io);
59
100
  }
60
101
  }
61
102
 
62
- void IO_Event_Selector_EPoll_Type_free(void *_data)
103
+ static
104
+ void IO_Event_Selector_EPoll_Type_mark(void *_selector)
63
105
  {
64
- struct IO_Event_Selector_EPoll *data = _data;
106
+ struct IO_Event_Selector_EPoll *selector = _selector;
65
107
 
66
- close_internal(data);
108
+ IO_Event_Selector_mark(&selector->backend);
109
+ IO_Event_Array_each(&selector->descriptors, IO_Event_Selector_EPoll_Descriptor_mark);
110
+ }
111
+
112
+ static
113
+ void IO_Event_Selector_EPoll_Waiting_compact(struct IO_Event_List *_waiting)
114
+ {
115
+ struct IO_Event_Selector_EPoll_Waiting *waiting = (void*)_waiting;
67
116
 
68
- free(data);
117
+ if (waiting->fiber) {
118
+ waiting->fiber = rb_gc_location(waiting->fiber);
119
+ }
69
120
  }
70
121
 
71
- size_t IO_Event_Selector_EPoll_Type_size(const void *data)
122
+ static
123
+ void IO_Event_Selector_EPoll_Descriptor_compact(void *_descriptor)
124
+ {
125
+ struct IO_Event_Selector_EPoll_Descriptor *descriptor = _descriptor;
126
+
127
+ IO_Event_List_immutable_each(&descriptor->list, IO_Event_Selector_EPoll_Waiting_compact);
128
+
129
+ if (descriptor->io) {
130
+ descriptor->io = rb_gc_location(descriptor->io);
131
+ }
132
+ }
133
+
134
+ static
135
+ void IO_Event_Selector_EPoll_Type_compact(void *_selector)
136
+ {
137
+ struct IO_Event_Selector_EPoll *selector = _selector;
138
+
139
+ IO_Event_Selector_compact(&selector->backend);
140
+ IO_Event_Array_each(&selector->descriptors, IO_Event_Selector_EPoll_Descriptor_compact);
141
+ }
142
+
143
+ static
144
+ void close_internal(struct IO_Event_Selector_EPoll *selector)
145
+ {
146
+ if (selector->descriptor >= 0) {
147
+ close(selector->descriptor);
148
+ selector->descriptor = -1;
149
+
150
+ IO_Event_Interrupt_close(&selector->interrupt);
151
+ }
152
+ }
153
+ static
154
+ void IO_Event_Selector_EPoll_Type_free(void *_selector)
155
+ {
156
+ struct IO_Event_Selector_EPoll *selector = _selector;
157
+
158
+ close_internal(selector);
159
+
160
+ IO_Event_Array_free(&selector->descriptors);
161
+
162
+ free(selector);
163
+ }
164
+
165
+ static
166
+ size_t IO_Event_Selector_EPoll_Type_size(const void *_selector)
72
167
  {
73
- return sizeof(struct IO_Event_Selector_EPoll);
168
+ const struct IO_Event_Selector_EPoll *selector = _selector;
169
+
170
+ return sizeof(struct IO_Event_Selector_EPoll)
171
+ + IO_Event_Array_memory_size(&selector->descriptors)
172
+ ;
74
173
  }
75
174
 
76
175
  static const rb_data_type_t IO_Event_Selector_EPoll_Type = {
77
176
  .wrap_struct_name = "IO_Event::Backend::EPoll",
78
177
  .function = {
79
178
  .dmark = IO_Event_Selector_EPoll_Type_mark,
179
+ .dcompact = IO_Event_Selector_EPoll_Type_compact,
80
180
  .dfree = IO_Event_Selector_EPoll_Type_free,
81
181
  .dsize = IO_Event_Selector_EPoll_Type_size,
82
182
  },
@@ -84,25 +184,172 @@ static const rb_data_type_t IO_Event_Selector_EPoll_Type = {
84
184
  .flags = RUBY_TYPED_FREE_IMMEDIATELY,
85
185
  };
86
186
 
187
+ inline static
188
+ struct IO_Event_Selector_EPoll_Descriptor * IO_Event_Selector_EPoll_Descriptor_lookup(struct IO_Event_Selector_EPoll *selector, int descriptor)
189
+ {
190
+ struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor = IO_Event_Array_lookup(&selector->descriptors, descriptor);
191
+
192
+ if (!epoll_descriptor) {
193
+ rb_sys_fail("IO_Event_Selector_EPoll_Descriptor_lookup:IO_Event_Array_lookup");
194
+ }
195
+
196
+ return epoll_descriptor;
197
+ }
198
+
199
+ static inline
200
+ uint32_t epoll_flags_from_events(int events)
201
+ {
202
+ uint32_t flags = 0;
203
+
204
+ if (events & IO_EVENT_READABLE) flags |= EPOLLIN;
205
+ if (events & IO_EVENT_PRIORITY) flags |= EPOLLPRI;
206
+ if (events & IO_EVENT_WRITABLE) flags |= EPOLLOUT;
207
+
208
+ flags |= EPOLLHUP;
209
+ flags |= EPOLLERR;
210
+
211
+ if (DEBUG) fprintf(stderr, "epoll_flags_from_events events=%d flags=%d\n", events, flags);
212
+
213
+ return flags;
214
+ }
215
+
216
+ static inline
217
+ int events_from_epoll_flags(uint32_t flags)
218
+ {
219
+ int events = 0;
220
+
221
+ if (DEBUG) fprintf(stderr, "events_from_epoll_flags flags=%d\n", flags);
222
+
223
+ // Occasionally, (and noted specifically when dealing with child processes stdout), flags will only be POLLHUP. In this case, we arm the file descriptor for reading so that the HUP will be noted, rather than potentially ignored, since there is no dedicated event for it.
224
+ // if (flags & (EPOLLIN)) events |= IO_EVENT_READABLE;
225
+ if (flags & (EPOLLIN|EPOLLHUP|EPOLLERR)) events |= IO_EVENT_READABLE;
226
+ if (flags & EPOLLPRI) events |= IO_EVENT_PRIORITY;
227
+ if (flags & EPOLLOUT) events |= IO_EVENT_WRITABLE;
228
+
229
+ return events;
230
+ }
231
+
232
+ inline static
233
+ int IO_Event_Selector_EPoll_Descriptor_update(struct IO_Event_Selector_EPoll *selector, VALUE io, int descriptor, struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor)
234
+ {
235
+ if (epoll_descriptor->io == io) {
236
+ if (epoll_descriptor->registered_events == epoll_descriptor->waiting_events) {
237
+ // All the events we are interested in are already registered.
238
+ return 0;
239
+ }
240
+ } else {
241
+ // The IO has changed, we need to reset the state:
242
+ epoll_descriptor->registered_events = 0;
243
+ epoll_descriptor->io = io;
244
+ }
245
+
246
+ if (epoll_descriptor->waiting_events == 0) {
247
+ if (epoll_descriptor->registered_events) {
248
+ // We are no longer interested in any events.
249
+ epoll_ctl(selector->descriptor, EPOLL_CTL_DEL, descriptor, NULL);
250
+ epoll_descriptor->registered_events = 0;
251
+ }
252
+
253
+ epoll_descriptor->io = 0;
254
+
255
+ return 0;
256
+ }
257
+
258
+ // We need to register for additional events:
259
+ struct epoll_event event = {
260
+ .events = epoll_flags_from_events(epoll_descriptor->waiting_events),
261
+ .data = {.fd = descriptor},
262
+ };
263
+
264
+ int operation;
265
+
266
+ if (epoll_descriptor->registered_events) {
267
+ operation = EPOLL_CTL_MOD;
268
+ } else {
269
+ operation = EPOLL_CTL_ADD;
270
+ }
271
+
272
+ int result = epoll_ctl(selector->descriptor, operation, descriptor, &event);
273
+ if (result == -1) {
274
+ if (errno == ENOENT) {
275
+ result = epoll_ctl(selector->descriptor, EPOLL_CTL_ADD, descriptor, &event);
276
+ } else if (errno == EEXIST) {
277
+ result = epoll_ctl(selector->descriptor, EPOLL_CTL_MOD, descriptor, &event);
278
+ }
279
+
280
+ if (result == -1) {
281
+ return -1;
282
+ }
283
+ }
284
+
285
+ epoll_descriptor->registered_events = epoll_descriptor->waiting_events;
286
+
287
+ return 1;
288
+ }
289
+
290
+ inline static
291
+ int IO_Event_Selector_EPoll_Waiting_register(struct IO_Event_Selector_EPoll *selector, VALUE io, int descriptor, struct IO_Event_Selector_EPoll_Waiting *waiting)
292
+ {
293
+ struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor = IO_Event_Selector_EPoll_Descriptor_lookup(selector, descriptor);
294
+
295
+ // We are waiting for these events:
296
+ epoll_descriptor->waiting_events |= waiting->events;
297
+
298
+ int result = IO_Event_Selector_EPoll_Descriptor_update(selector, io, descriptor, epoll_descriptor);
299
+ if (result == -1) return -1;
300
+
301
+ IO_Event_List_prepend(&epoll_descriptor->list, &waiting->list);
302
+
303
+ return result;
304
+ }
305
+
306
+ inline static
307
+ void IO_Event_Selector_EPoll_Waiting_cancel(struct IO_Event_Selector_EPoll_Waiting *waiting)
308
+ {
309
+ IO_Event_List_pop(&waiting->list);
310
+ waiting->fiber = 0;
311
+ }
312
+
313
+ void IO_Event_Selector_EPoll_Descriptor_initialize(void *element)
314
+ {
315
+ struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor = element;
316
+ IO_Event_List_initialize(&epoll_descriptor->list);
317
+ epoll_descriptor->io = 0;
318
+ epoll_descriptor->waiting_events = 0;
319
+ epoll_descriptor->registered_events = 0;
320
+ }
321
+
322
+ void IO_Event_Selector_EPoll_Descriptor_free(void *element)
323
+ {
324
+ struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor = element;
325
+
326
+ IO_Event_List_free(&epoll_descriptor->list);
327
+ }
328
+
87
329
  VALUE IO_Event_Selector_EPoll_allocate(VALUE self) {
88
- struct IO_Event_Selector_EPoll *data = NULL;
89
- VALUE instance = TypedData_Make_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
330
+ struct IO_Event_Selector_EPoll *selector = NULL;
331
+ VALUE instance = TypedData_Make_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
332
+
333
+ IO_Event_Selector_initialize(&selector->backend, Qnil);
334
+ selector->descriptor = -1;
335
+ selector->blocked = 0;
90
336
 
91
- IO_Event_Selector_initialize(&data->backend, Qnil);
92
- data->descriptor = -1;
337
+ selector->descriptors.element_initialize = IO_Event_Selector_EPoll_Descriptor_initialize;
338
+ selector->descriptors.element_free = IO_Event_Selector_EPoll_Descriptor_free;
339
+ IO_Event_Array_allocate(&selector->descriptors, 1024, sizeof(struct IO_Event_Selector_EPoll_Descriptor));
93
340
 
94
341
  return instance;
95
342
  }
96
343
 
97
- void IO_Event_Interrupt_add(struct IO_Event_Interrupt *interrupt, struct IO_Event_Selector_EPoll *data) {
344
+ void IO_Event_Interrupt_add(struct IO_Event_Interrupt *interrupt, struct IO_Event_Selector_EPoll *selector) {
98
345
  int descriptor = IO_Event_Interrupt_descriptor(interrupt);
99
346
 
100
347
  struct epoll_event event = {
101
348
  .events = EPOLLIN|EPOLLRDHUP,
102
- .data = {.ptr = NULL},
349
+ .data = {.fd = -1},
103
350
  };
104
351
 
105
- int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
352
+ int result = epoll_ctl(selector->descriptor, EPOLL_CTL_ADD, descriptor, &event);
106
353
 
107
354
  if (result == -1) {
108
355
  rb_sys_fail("IO_Event_Interrupt_add:epoll_ctl");
@@ -110,95 +357,95 @@ void IO_Event_Interrupt_add(struct IO_Event_Interrupt *interrupt, struct IO_Even
110
357
  }
111
358
 
112
359
  VALUE IO_Event_Selector_EPoll_initialize(VALUE self, VALUE loop) {
113
- struct IO_Event_Selector_EPoll *data = NULL;
114
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
360
+ struct IO_Event_Selector_EPoll *selector = NULL;
361
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
115
362
 
116
- IO_Event_Selector_initialize(&data->backend, loop);
363
+ IO_Event_Selector_initialize(&selector->backend, loop);
117
364
  int result = epoll_create1(EPOLL_CLOEXEC);
118
365
 
119
366
  if (result == -1) {
120
367
  rb_sys_fail("IO_Event_Selector_EPoll_initialize:epoll_create");
121
368
  } else {
122
- data->descriptor = result;
369
+ selector->descriptor = result;
123
370
 
124
- rb_update_max_fd(data->descriptor);
371
+ rb_update_max_fd(selector->descriptor);
125
372
  }
126
373
 
127
- IO_Event_Interrupt_open(&data->interrupt);
128
- IO_Event_Interrupt_add(&data->interrupt, data);
374
+ IO_Event_Interrupt_open(&selector->interrupt);
375
+ IO_Event_Interrupt_add(&selector->interrupt, selector);
129
376
 
130
377
  return self;
131
378
  }
132
379
 
133
380
  VALUE IO_Event_Selector_EPoll_loop(VALUE self) {
134
- struct IO_Event_Selector_EPoll *data = NULL;
135
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
381
+ struct IO_Event_Selector_EPoll *selector = NULL;
382
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
136
383
 
137
- return data->backend.loop;
384
+ return selector->backend.loop;
138
385
  }
139
386
 
140
387
  VALUE IO_Event_Selector_EPoll_close(VALUE self) {
141
- struct IO_Event_Selector_EPoll *data = NULL;
142
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
388
+ struct IO_Event_Selector_EPoll *selector = NULL;
389
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
143
390
 
144
- close_internal(data);
391
+ close_internal(selector);
145
392
 
146
393
  return Qnil;
147
394
  }
148
395
 
149
396
  VALUE IO_Event_Selector_EPoll_transfer(VALUE self)
150
397
  {
151
- struct IO_Event_Selector_EPoll *data = NULL;
152
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
398
+ struct IO_Event_Selector_EPoll *selector = NULL;
399
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
153
400
 
154
- return IO_Event_Selector_fiber_transfer(data->backend.loop, 0, NULL);
401
+ return IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
155
402
  }
156
403
 
157
404
  VALUE IO_Event_Selector_EPoll_resume(int argc, VALUE *argv, VALUE self)
158
405
  {
159
- struct IO_Event_Selector_EPoll *data = NULL;
160
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
406
+ struct IO_Event_Selector_EPoll *selector = NULL;
407
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
161
408
 
162
- return IO_Event_Selector_resume(&data->backend, argc, argv);
409
+ return IO_Event_Selector_resume(&selector->backend, argc, argv);
163
410
  }
164
411
 
165
412
  VALUE IO_Event_Selector_EPoll_yield(VALUE self)
166
413
  {
167
- struct IO_Event_Selector_EPoll *data = NULL;
168
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
414
+ struct IO_Event_Selector_EPoll *selector = NULL;
415
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
169
416
 
170
- return IO_Event_Selector_yield(&data->backend);
417
+ return IO_Event_Selector_yield(&selector->backend);
171
418
  }
172
419
 
173
420
  VALUE IO_Event_Selector_EPoll_push(VALUE self, VALUE fiber)
174
421
  {
175
- struct IO_Event_Selector_EPoll *data = NULL;
176
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
422
+ struct IO_Event_Selector_EPoll *selector = NULL;
423
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
177
424
 
178
- IO_Event_Selector_queue_push(&data->backend, fiber);
425
+ IO_Event_Selector_queue_push(&selector->backend, fiber);
179
426
 
180
427
  return Qnil;
181
428
  }
182
429
 
183
430
  VALUE IO_Event_Selector_EPoll_raise(int argc, VALUE *argv, VALUE self)
184
431
  {
185
- struct IO_Event_Selector_EPoll *data = NULL;
186
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
432
+ struct IO_Event_Selector_EPoll *selector = NULL;
433
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
187
434
 
188
- return IO_Event_Selector_raise(&data->backend, argc, argv);
435
+ return IO_Event_Selector_raise(&selector->backend, argc, argv);
189
436
  }
190
437
 
191
438
  VALUE IO_Event_Selector_EPoll_ready_p(VALUE self) {
192
- struct IO_Event_Selector_EPoll *data = NULL;
193
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
439
+ struct IO_Event_Selector_EPoll *selector = NULL;
440
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
194
441
 
195
- return data->backend.ready ? Qtrue : Qfalse;
442
+ return selector->backend.ready ? Qtrue : Qfalse;
196
443
  }
197
444
 
198
445
  struct process_wait_arguments {
199
- struct IO_Event_Selector_EPoll *data;
200
- pid_t pid;
201
- int flags;
446
+ struct IO_Event_Selector_EPoll *selector;
447
+ struct IO_Event_Selector_EPoll_Waiting *waiting;
448
+ int pid;
202
449
  int descriptor;
203
450
  };
204
451
 
@@ -206,106 +453,76 @@ static
206
453
  VALUE process_wait_transfer(VALUE _arguments) {
207
454
  struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
208
455
 
209
- IO_Event_Selector_fiber_transfer(arguments->data->backend.loop, 0, NULL);
456
+ IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
210
457
 
211
- return IO_Event_Selector_process_status_wait(arguments->pid);
458
+ if (arguments->waiting->ready) {
459
+ return IO_Event_Selector_process_status_wait(arguments->pid);
460
+ } else {
461
+ return Qfalse;
462
+ }
212
463
  }
213
464
 
214
465
  static
215
466
  VALUE process_wait_ensure(VALUE _arguments) {
216
467
  struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
217
468
 
218
- // epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);
219
-
220
469
  close(arguments->descriptor);
221
470
 
471
+ IO_Event_Selector_EPoll_Waiting_cancel(arguments->waiting);
472
+
222
473
  return Qnil;
223
474
  }
224
475
 
225
- VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
226
- struct IO_Event_Selector_EPoll *data = NULL;
227
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
476
+ struct IO_Event_List_Type IO_Event_Selector_EPoll_process_wait_list_type = {};
477
+
478
+ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid, VALUE _flags) {
479
+ struct IO_Event_Selector_EPoll *selector = NULL;
480
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
228
481
 
229
- struct process_wait_arguments process_wait_arguments = {
230
- .data = data,
231
- .pid = NUM2PIDT(pid),
232
- .flags = NUM2INT(flags),
233
- };
482
+ pid_t pid = NUM2PIDT(_pid);
483
+ // int flags = NUM2INT(_flags);
234
484
 
235
- process_wait_arguments.descriptor = pidfd_open(process_wait_arguments.pid, 0);
485
+ int descriptor = pidfd_open(pid, 0);
236
486
 
237
- if (process_wait_arguments.descriptor == -1) {
487
+ if (descriptor == -1) {
238
488
  rb_sys_fail("IO_Event_Selector_EPoll_process_wait:pidfd_open");
239
489
  }
240
490
 
241
- rb_update_max_fd(process_wait_arguments.descriptor);
491
+ rb_update_max_fd(descriptor);
242
492
 
243
- struct epoll_event event = {
244
- .events = EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLONESHOT,
245
- .data = {.ptr = (void*)fiber},
493
+ struct IO_Event_Selector_EPoll_Waiting waiting = {
494
+ .list = {.type = &IO_Event_Selector_EPoll_process_wait_list_type},
495
+ .fiber = fiber,
496
+ .events = IO_EVENT_READABLE,
246
497
  };
247
498
 
248
- int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, process_wait_arguments.descriptor, &event);
499
+ int result = IO_Event_Selector_EPoll_Waiting_register(selector, 0, descriptor, &waiting);
249
500
 
250
501
  if (result == -1) {
251
- close(process_wait_arguments.descriptor);
252
- rb_sys_fail("IO_Event_Selector_EPoll_process_wait:epoll_ctl");
502
+ close(descriptor);
503
+ rb_sys_fail("IO_Event_Selector_EPoll_process_wait:IO_Event_Selector_EPoll_Waiting_register");
253
504
  }
254
505
 
255
- return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
256
- }
257
-
258
- static inline
259
- uint32_t epoll_flags_from_events(int events) {
260
- uint32_t flags = 0;
261
-
262
- if (events & IO_EVENT_READABLE) flags |= EPOLLIN;
263
- if (events & IO_EVENT_PRIORITY) flags |= EPOLLPRI;
264
- if (events & IO_EVENT_WRITABLE) flags |= EPOLLOUT;
265
-
266
- flags |= EPOLLHUP;
267
- flags |= EPOLLERR;
268
-
269
- // Immediately remove this descriptor after reading one event:
270
- flags |= EPOLLONESHOT;
271
-
272
- if (DEBUG) fprintf(stderr, "epoll_flags_from_events events=%d flags=%d\n", events, flags);
273
-
274
- return flags;
275
- }
276
-
277
- static inline
278
- int events_from_epoll_flags(uint32_t flags) {
279
- int events = 0;
280
-
281
- if (DEBUG) fprintf(stderr, "events_from_epoll_flags flags=%d\n", flags);
282
-
283
- // Occasionally, (and noted specifically when dealing with child processes stdout), flags will only be POLLHUP. In this case, we arm the file descriptor for reading so that the HUP will be noted, rather than potentially ignored, since there is no dedicated event for it.
284
- // if (flags & (EPOLLIN)) events |= IO_EVENT_READABLE;
285
- if (flags & (EPOLLIN|EPOLLHUP|EPOLLERR)) events |= IO_EVENT_READABLE;
286
- if (flags & EPOLLPRI) events |= IO_EVENT_PRIORITY;
287
- if (flags & EPOLLOUT) events |= IO_EVENT_WRITABLE;
506
+ struct process_wait_arguments process_wait_arguments = {
507
+ .selector = selector,
508
+ .pid = pid,
509
+ .descriptor = descriptor,
510
+ .waiting = &waiting,
511
+ };
288
512
 
289
- return events;
513
+ return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
290
514
  }
291
515
 
292
516
  struct io_wait_arguments {
293
- struct IO_Event_Selector_EPoll *data;
294
- int descriptor;
295
- int duplicate;
517
+ struct IO_Event_Selector_EPoll *selector;
518
+ struct IO_Event_Selector_EPoll_Waiting *waiting;
296
519
  };
297
520
 
298
521
  static
299
522
  VALUE io_wait_ensure(VALUE _arguments) {
300
523
  struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
301
524
 
302
- if (arguments->duplicate >= 0) {
303
- epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->duplicate, NULL);
304
-
305
- close(arguments->duplicate);
306
- } else {
307
- epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);
308
- }
525
+ IO_Event_Selector_EPoll_Waiting_cancel(arguments->waiting);
309
526
 
310
527
  return Qnil;
311
528
  };
@@ -314,72 +531,44 @@ static
314
531
  VALUE io_wait_transfer(VALUE _arguments) {
315
532
  struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
316
533
 
317
- VALUE result = IO_Event_Selector_fiber_transfer(arguments->data->backend.loop, 0, NULL);
534
+ IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
318
535
 
319
- if (DEBUG) fprintf(stderr, "io_wait_transfer errno=%d\n", errno);
320
-
321
- // If the fiber is being cancelled, it might be resumed with nil:
322
- if (!RTEST(result)) {
323
- if (DEBUG) fprintf(stderr, "io_wait_transfer flags=false\n");
536
+ if (arguments->waiting->ready) {
537
+ return RB_INT2NUM(arguments->waiting->ready);
538
+ } else {
324
539
  return Qfalse;
325
540
  }
326
-
327
- if (DEBUG) fprintf(stderr, "io_wait_transfer flags=%d\n", NUM2INT(result));
328
-
329
- return INT2NUM(events_from_epoll_flags(NUM2INT(result)));
330
541
  };
331
542
 
543
+ struct IO_Event_List_Type IO_Event_Selector_EPoll_io_wait_list_type = {};
544
+
332
545
  VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
333
- struct IO_Event_Selector_EPoll *data = NULL;
334
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
546
+ struct IO_Event_Selector_EPoll *selector = NULL;
547
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
335
548
 
336
- struct epoll_event event = {0};
549
+ int descriptor = IO_Event_Selector_io_descriptor(io);
337
550
 
338
- int descriptor = IO_Event_Selector_io_descriptor(io);
339
- int duplicate = -1;
340
-
341
- event.events = epoll_flags_from_events(NUM2INT(events));
342
- event.data.ptr = (void*)fiber;
343
-
344
- if (DEBUG) fprintf(stderr, "<- fiber=%p descriptor=%d\n", (void*)fiber, descriptor);
345
-
346
- // A better approach is to batch all changes:
347
- int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
551
+ struct IO_Event_Selector_EPoll_Waiting waiting = {
552
+ .list = {.type = &IO_Event_Selector_EPoll_io_wait_list_type},
553
+ .fiber = fiber,
554
+ .events = RB_NUM2INT(events),
555
+ };
348
556
 
349
- if (result == -1 && errno == EEXIST) {
350
- // The file descriptor was already inserted into epoll.
351
- duplicate = dup(descriptor);
352
-
353
- if (duplicate == -1) {
354
- rb_sys_fail("IO_Event_Selector_EPoll_io_wait:dup");
355
- }
356
-
357
- descriptor = duplicate;
358
-
359
- rb_update_max_fd(descriptor);
360
-
361
- result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
362
- }
557
+ int result = IO_Event_Selector_EPoll_Waiting_register(selector, io, descriptor, &waiting);
363
558
 
364
559
  if (result == -1) {
365
- // If we duplicated the file descriptor, ensure it's closed:
366
- if (duplicate >= 0) {
367
- close(duplicate);
368
- }
369
-
370
560
  if (errno == EPERM) {
371
- IO_Event_Selector_queue_push(&data->backend, fiber);
372
- IO_Event_Selector_yield(&data->backend);
561
+ IO_Event_Selector_queue_push(&selector->backend, fiber);
562
+ IO_Event_Selector_yield(&selector->backend);
373
563
  return events;
374
564
  }
375
565
 
376
- rb_sys_fail("IO_Event_Selector_EPoll_io_wait:epoll_ctl");
566
+ rb_sys_fail("IO_Event_Selector_EPoll_io_wait:IO_Event_Selector_EPoll_Waiting_register");
377
567
  }
378
568
 
379
569
  struct io_wait_arguments io_wait_arguments = {
380
- .data = data,
381
- .descriptor = descriptor,
382
- .duplicate = duplicate
570
+ .selector = selector,
571
+ .waiting = &waiting,
383
572
  };
384
573
 
385
574
  return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
@@ -411,12 +600,14 @@ VALUE io_read_loop(VALUE _arguments) {
411
600
 
412
601
  size_t length = arguments->length;
413
602
  size_t offset = arguments->offset;
603
+ size_t total = 0;
414
604
 
415
- while (true) {
416
- size_t maximum_size = size - offset;
605
+ size_t maximum_size = size - offset;
606
+ while (maximum_size) {
417
607
  ssize_t result = read(arguments->descriptor, (char*)base+offset, maximum_size);
418
608
 
419
609
  if (result > 0) {
610
+ total += result;
420
611
  offset += result;
421
612
  if ((size_t)result >= length) break;
422
613
  length -= result;
@@ -427,9 +618,11 @@ VALUE io_read_loop(VALUE _arguments) {
427
618
  } else {
428
619
  return rb_fiber_scheduler_io_result(-1, errno);
429
620
  }
621
+
622
+ maximum_size = size - offset;
430
623
  }
431
624
 
432
- return rb_fiber_scheduler_io_result(offset, 0);
625
+ return rb_fiber_scheduler_io_result(total, 0);
433
626
  }
434
627
 
435
628
  static
@@ -499,16 +692,18 @@ VALUE io_write_loop(VALUE _arguments) {
499
692
 
500
693
  size_t length = arguments->length;
501
694
  size_t offset = arguments->offset;
695
+ size_t total = 0;
502
696
 
503
697
  if (length > size) {
504
698
  rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
505
699
  }
506
700
 
507
- while (true) {
508
- size_t maximum_size = size - offset;
701
+ size_t maximum_size = size - offset;
702
+ while (maximum_size) {
509
703
  ssize_t result = write(arguments->descriptor, (char*)base+offset, maximum_size);
510
704
 
511
705
  if (result > 0) {
706
+ total += result;
512
707
  offset += result;
513
708
  if ((size_t)result >= length) break;
514
709
  length -= result;
@@ -519,9 +714,11 @@ VALUE io_write_loop(VALUE _arguments) {
519
714
  } else {
520
715
  return rb_fiber_scheduler_io_result(-1, errno);
521
716
  }
717
+
718
+ maximum_size = size - offset;
522
719
  }
523
720
 
524
- return rb_fiber_scheduler_io_result(offset, 0);
721
+ return rb_fiber_scheduler_io_result(total, 0);
525
722
  };
526
723
 
527
724
  static
@@ -601,7 +798,7 @@ int timeout_nonblocking(struct timespec * timespec) {
601
798
  }
602
799
 
603
800
  struct select_arguments {
604
- struct IO_Event_Selector_EPoll *data;
801
+ struct IO_Event_Selector_EPoll *selector;
605
802
 
606
803
  int count;
607
804
  struct epoll_event events[EPOLL_MAX_EVENTS];
@@ -636,7 +833,7 @@ void * select_internal(void *_arguments) {
636
833
  struct select_arguments * arguments = (struct select_arguments *)_arguments;
637
834
 
638
835
  #if defined(HAVE_EPOLL_PWAIT2)
639
- arguments->count = epoll_pwait2(arguments->data->descriptor, arguments->events, EPOLL_MAX_EVENTS, arguments->timeout, NULL);
836
+ arguments->count = epoll_pwait2(arguments->selector->descriptor, arguments->events, EPOLL_MAX_EVENTS, arguments->timeout, NULL);
640
837
 
641
838
  // Comment out the above line and enable the below lines to test ENOSYS code path.
642
839
  // arguments->count = -1;
@@ -650,16 +847,16 @@ void * select_internal(void *_arguments) {
650
847
  }
651
848
  #endif
652
849
 
653
- arguments->count = epoll_wait(arguments->data->descriptor, arguments->events, EPOLL_MAX_EVENTS, make_timeout_ms(arguments->timeout));
850
+ arguments->count = epoll_wait(arguments->selector->descriptor, arguments->events, EPOLL_MAX_EVENTS, make_timeout_ms(arguments->timeout));
654
851
 
655
852
  return NULL;
656
853
  }
657
854
 
658
855
  static
659
856
  void select_internal_without_gvl(struct select_arguments *arguments) {
660
- arguments->data->blocked = 1;
857
+ arguments->selector->blocked = 1;
661
858
  rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
662
- arguments->data->blocked = 0;
859
+ arguments->selector->blocked = 0;
663
860
 
664
861
  if (arguments->count == -1) {
665
862
  if (errno != EINTR) {
@@ -683,14 +880,59 @@ void select_internal_with_gvl(struct select_arguments *arguments) {
683
880
  }
684
881
  }
685
882
 
883
+ static
884
+ int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, const struct epoll_event *event)
885
+ {
886
+ int descriptor = event->data.fd;
887
+
888
+ // This is the mask of all events that occured for the given descriptor:
889
+ enum IO_Event ready_events = events_from_epoll_flags(event->events);
890
+
891
+ struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor = IO_Event_Selector_EPoll_Descriptor_lookup(selector, descriptor);
892
+ struct IO_Event_List *list = &epoll_descriptor->list;
893
+ struct IO_Event_List *node = list->tail;
894
+ struct IO_Event_List saved = {NULL, NULL};
895
+
896
+ // Reset the events back to 0 so that we can re-arm if necessary:
897
+ epoll_descriptor->waiting_events = 0;
898
+
899
+ // It's possible (but unlikely) that the address of list will changing during iteration.
900
+ while (node != list) {
901
+ struct IO_Event_Selector_EPoll_Waiting *waiting = (struct IO_Event_Selector_EPoll_Waiting *)node;
902
+
903
+ // Compute the intersection of the events we are waiting for and the events that occured:
904
+ enum IO_Event matching_events = waiting->events & ready_events;
905
+
906
+ if (DEBUG) fprintf(stderr, "IO_Event_Selector_EPoll_handle: descriptor=%d, ready_events=%d, matching_events=%d\n", descriptor, ready_events, matching_events);
907
+
908
+ if (matching_events) {
909
+ IO_Event_List_append(node, &saved);
910
+
911
+ // Resume the fiber:
912
+ waiting->ready = matching_events;
913
+ IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
914
+
915
+ node = saved.tail;
916
+ IO_Event_List_pop(&saved);
917
+ } else {
918
+ // We are still waiting for the events:
919
+ epoll_descriptor->waiting_events |= waiting->events;
920
+ node = node->tail;
921
+ }
922
+ }
923
+
924
+ return IO_Event_Selector_EPoll_Descriptor_update(selector, epoll_descriptor->io, descriptor, epoll_descriptor);
925
+ }
926
+
927
+ // TODO This function is not re-entrant and we should document and assert as such.
686
928
  VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
687
- struct IO_Event_Selector_EPoll *data = NULL;
688
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
929
+ struct IO_Event_Selector_EPoll *selector = NULL;
930
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
689
931
 
690
- int ready = IO_Event_Selector_queue_flush(&data->backend);
932
+ int ready = IO_Event_Selector_queue_flush(&selector->backend);
691
933
 
692
934
  struct select_arguments arguments = {
693
- .data = data,
935
+ .selector = selector,
694
936
  .storage = {
695
937
  .tv_sec = 0,
696
938
  .tv_nsec = 0
@@ -707,7 +949,7 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
707
949
  // 2. Didn't process any events from non-blocking select (above), and
708
950
  // 3. There are no items in the ready list,
709
951
  // then we can perform a blocking select.
710
- if (!ready && !arguments.count && !data->backend.ready) {
952
+ if (!ready && !arguments.count && !selector->backend.ready) {
711
953
  arguments.timeout = make_timeout(duration, &arguments.storage);
712
954
 
713
955
  if (!timeout_nonblocking(arguments.timeout)) {
@@ -720,13 +962,10 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
720
962
  const struct epoll_event *event = &arguments.events[i];
721
963
  if (DEBUG) fprintf(stderr, "-> ptr=%p events=%d\n", event->data.ptr, event->events);
722
964
 
723
- if (event->data.ptr) {
724
- VALUE fiber = (VALUE)event->data.ptr;
725
- VALUE result = INT2NUM(event->events);
726
-
727
- IO_Event_Selector_fiber_transfer(fiber, 1, &result);
965
+ if (event->data.fd >= 0) {
966
+ IO_Event_Selector_EPoll_handle(selector, event);
728
967
  } else {
729
- IO_Event_Interrupt_clear(&data->interrupt);
968
+ IO_Event_Interrupt_clear(&selector->interrupt);
730
969
  }
731
970
  }
732
971
 
@@ -734,12 +973,12 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
734
973
  }
735
974
 
736
975
  VALUE IO_Event_Selector_EPoll_wakeup(VALUE self) {
737
- struct IO_Event_Selector_EPoll *data = NULL;
738
- TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
976
+ struct IO_Event_Selector_EPoll *selector = NULL;
977
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
739
978
 
740
979
  // If we are blocking, we can schedule a nop event to wake up the selector:
741
- if (data->blocked) {
742
- IO_Event_Interrupt_signal(&data->interrupt);
980
+ if (selector->blocked) {
981
+ IO_Event_Interrupt_signal(&selector->interrupt);
743
982
 
744
983
  return Qtrue;
745
984
  }