event 0.6.0 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
data/ext/event/backend.o DELETED
Binary file
@@ -1,108 +0,0 @@
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
- #include "backend.h"
22
- #include <fcntl.h>
23
-
24
- static ID id_transfer, id_wait;
25
- static VALUE rb_Process_Status = Qnil;
26
-
27
- void Init_Event_Backend(VALUE Event_Backend) {
28
- id_transfer = rb_intern("transfer");
29
- id_wait = rb_intern("wait");
30
- // id_alive_p = rb_intern("alive?");
31
- rb_Process_Status = rb_const_get_at(rb_mProcess, rb_intern("Status"));
32
- }
33
-
34
- VALUE
35
- Event_Backend_transfer(VALUE fiber) {
36
- #ifdef HAVE__RB_FIBER_TRANSFER
37
- return rb_fiber_transfer(fiber, 0, NULL);
38
- #else
39
- return rb_funcall(fiber, id_transfer, 0);
40
- #endif
41
- }
42
-
43
- VALUE
44
- Event_Backend_transfer_result(VALUE fiber, VALUE result) {
45
- // if (!RTEST(rb_fiber_alive_p(fiber))) {
46
- // return Qnil;
47
- // }
48
-
49
- #ifdef HAVE__RB_FIBER_TRANSFER
50
- return rb_fiber_transfer(fiber, 1, &result);
51
- #else
52
- return rb_funcall(fiber, id_transfer, 1, result);
53
- #endif
54
- }
55
-
56
- VALUE Event_Backend_process_status_wait(rb_pid_t pid)
57
- {
58
- return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), INT2NUM(WNOHANG));
59
- }
60
-
61
- char* Event_Backend_verify_size(VALUE buffer, size_t offset, size_t length) {
62
- if ((size_t)RSTRING_LEN(buffer) < offset + length) {
63
- rb_raise(rb_eRuntimeError, "invalid offset/length exceeds bounds of buffer");
64
- }
65
-
66
- return RSTRING_PTR(buffer);
67
- }
68
-
69
- char* Event_Backend_resize_to_capacity(VALUE string, size_t offset, size_t length) {
70
- size_t current_length = RSTRING_LEN(string);
71
- long difference = (long)(offset + length) - (long)current_length;
72
-
73
- difference += 1;
74
-
75
- if (difference > 0) {
76
- rb_str_modify_expand(string, difference);
77
- } else {
78
- rb_str_modify(string);
79
- }
80
-
81
- return RSTRING_PTR(string);
82
- }
83
-
84
- void Event_Backend_resize_to_fit(VALUE string, size_t offset, size_t length) {
85
- size_t current_length = RSTRING_LEN(string);
86
-
87
- if (current_length < (offset + length)) {
88
- rb_str_set_len(string, offset + length);
89
- }
90
- }
91
-
92
- int Event_Backend_nonblock_set(int file_descriptor)
93
- {
94
- int flags = fcntl(file_descriptor, F_GETFL, 0);
95
-
96
- if (!(flags & O_NONBLOCK)) {
97
- fcntl(file_descriptor, F_SETFL, flags | O_NONBLOCK);
98
- }
99
-
100
- return flags;
101
- }
102
-
103
- void Event_Backend_nonblock_restore(int file_descriptor, int flags)
104
- {
105
- if (!(flags & O_NONBLOCK)) {
106
- fcntl(file_descriptor, F_SETFL, flags & ~flags);
107
- }
108
- }
@@ -1,45 +0,0 @@
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
- #include <ruby.h>
22
- #include <ruby/thread.h>
23
-
24
- enum Event {
25
- READABLE = 1,
26
- PRIORITY = 2,
27
- WRITABLE = 4,
28
- ERROR = 8,
29
- HANGUP = 16
30
- };
31
-
32
- void
33
- Init_Event_Backend();
34
-
35
- VALUE Event_Backend_transfer(VALUE fiber);
36
- VALUE Event_Backend_transfer_result(VALUE fiber, VALUE argument);
37
-
38
- VALUE Event_Backend_process_status_wait(rb_pid_t pid);
39
-
40
- char* Event_Backend_verify_size(VALUE buffer, size_t offset, size_t length);
41
- char* Event_Backend_resize_to_capacity(VALUE string, size_t offset, size_t length);
42
- void Event_Backend_resize_to_fit(VALUE string, size_t offset, size_t length);
43
-
44
- int Event_Backend_nonblock_set(int file_descriptor);
45
- void Event_Backend_nonblock_restore(int file_descriptor, int flags);
@@ -1,498 +0,0 @@
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
- #include "uring.h"
22
- #include "backend.h"
23
-
24
- #include <liburing.h>
25
- #include <poll.h>
26
- #include <time.h>
27
-
28
- #include "pidfd.c"
29
-
30
- static VALUE Event_Backend_URing = Qnil;
31
- static ID id_fileno;
32
-
33
- enum {URING_ENTRIES = 128};
34
- enum {URING_MAX_EVENTS = 128};
35
-
36
- struct Event_Backend_URing {
37
- VALUE loop;
38
- struct io_uring ring;
39
- };
40
-
41
- void Event_Backend_URing_Type_mark(void *_data)
42
- {
43
- struct Event_Backend_URing *data = _data;
44
- rb_gc_mark(data->loop);
45
- }
46
-
47
- static
48
- void close_internal(struct Event_Backend_URing *data) {
49
- if (data->ring.ring_fd >= 0) {
50
- io_uring_queue_exit(&data->ring);
51
- data->ring.ring_fd = -1;
52
- }
53
- }
54
-
55
- void Event_Backend_URing_Type_free(void *_data)
56
- {
57
- struct Event_Backend_URing *data = _data;
58
-
59
- close_internal(data);
60
-
61
- free(data);
62
- }
63
-
64
- size_t Event_Backend_URing_Type_size(const void *data)
65
- {
66
- return sizeof(struct Event_Backend_URing);
67
- }
68
-
69
- static const rb_data_type_t Event_Backend_URing_Type = {
70
- .wrap_struct_name = "Event::Backend::URing",
71
- .function = {
72
- .dmark = Event_Backend_URing_Type_mark,
73
- .dfree = Event_Backend_URing_Type_free,
74
- .dsize = Event_Backend_URing_Type_size,
75
- },
76
- .data = NULL,
77
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
78
- };
79
-
80
- VALUE Event_Backend_URing_allocate(VALUE self) {
81
- struct Event_Backend_URing *data = NULL;
82
- VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
83
-
84
- data->loop = Qnil;
85
- data->ring.ring_fd = -1;
86
-
87
- return instance;
88
- }
89
-
90
- VALUE Event_Backend_URing_initialize(VALUE self, VALUE loop) {
91
- struct Event_Backend_URing *data = NULL;
92
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
93
-
94
- data->loop = loop;
95
-
96
- int result = io_uring_queue_init(URING_ENTRIES, &data->ring, 0);
97
-
98
- if (result < 0) {
99
- rb_syserr_fail(-result, "io_uring_queue_init");
100
- }
101
-
102
- rb_update_max_fd(data->ring.ring_fd);
103
-
104
- return self;
105
- }
106
-
107
- VALUE Event_Backend_URing_close(VALUE self) {
108
- struct Event_Backend_URing *data = NULL;
109
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
110
-
111
- close_internal(data);
112
-
113
- return Qnil;
114
- }
115
-
116
- struct io_uring_sqe * io_get_sqe(struct Event_Backend_URing *data) {
117
- struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
118
-
119
- while (sqe == NULL) {
120
- io_uring_submit(&data->ring);
121
- sqe = io_uring_get_sqe(&data->ring);
122
- }
123
-
124
- // fprintf(stderr, "io_get_sqe -> %p\n", sqe);
125
-
126
- return sqe;
127
- }
128
-
129
- struct process_wait_arguments {
130
- struct Event_Backend_URing *data;
131
- pid_t pid;
132
- int flags;
133
- int descriptor;
134
- };
135
-
136
- static
137
- VALUE process_wait_transfer(VALUE _arguments) {
138
- struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
139
-
140
- Event_Backend_transfer(arguments->data->loop);
141
-
142
- return Event_Backend_process_status_wait(arguments->pid);
143
- }
144
-
145
- static
146
- VALUE process_wait_ensure(VALUE _arguments) {
147
- struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
148
-
149
- close(arguments->descriptor);
150
-
151
- return Qnil;
152
- }
153
-
154
- VALUE Event_Backend_URing_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
155
- struct Event_Backend_URing *data = NULL;
156
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
157
-
158
- struct process_wait_arguments process_wait_arguments = {
159
- .data = data,
160
- .pid = NUM2PIDT(pid),
161
- .flags = NUM2INT(flags),
162
- };
163
-
164
- process_wait_arguments.descriptor = pidfd_open(process_wait_arguments.pid, 0);
165
- rb_update_max_fd(process_wait_arguments.descriptor);
166
-
167
- struct io_uring_sqe *sqe = io_get_sqe(data);
168
- assert(sqe);
169
-
170
- io_uring_prep_poll_add(sqe, process_wait_arguments.descriptor, POLLIN|POLLHUP|POLLERR);
171
- io_uring_sqe_set_data(sqe, (void*)fiber);
172
-
173
- return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
174
- }
175
-
176
- static inline
177
- short poll_flags_from_events(int events) {
178
- short flags = 0;
179
-
180
- if (events & READABLE) flags |= POLLIN;
181
- if (events & PRIORITY) flags |= POLLPRI;
182
- if (events & WRITABLE) flags |= POLLOUT;
183
-
184
- flags |= POLLERR;
185
- flags |= POLLHUP;
186
-
187
- return flags;
188
- }
189
-
190
- static inline
191
- int events_from_poll_flags(short flags) {
192
- int events = 0;
193
-
194
- if (flags & POLLIN) events |= READABLE;
195
- if (flags & POLLPRI) events |= PRIORITY;
196
- if (flags & POLLOUT) events |= WRITABLE;
197
-
198
- return events;
199
- }
200
-
201
- struct io_wait_arguments {
202
- struct Event_Backend_URing *data;
203
- VALUE fiber;
204
- short flags;
205
- };
206
-
207
- static
208
- VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
209
- struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
210
- struct Event_Backend_URing *data = arguments->data;
211
-
212
- struct io_uring_sqe *sqe = io_get_sqe(data);
213
- assert(sqe);
214
-
215
- // fprintf(stderr, "poll_remove(%p, %p)\n", sqe, (void*)arguments->fiber);
216
-
217
- io_uring_prep_poll_remove(sqe, (void*)arguments->fiber);
218
- io_uring_submit(&data->ring);
219
-
220
- rb_exc_raise(exception);
221
- };
222
-
223
- static
224
- VALUE io_wait_transfer(VALUE _arguments) {
225
- struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
226
- struct Event_Backend_URing *data = arguments->data;
227
-
228
- VALUE result = Event_Backend_transfer(data->loop);
229
-
230
- // We explicitly filter the resulting events based on the requested events.
231
- // In some cases, poll will report events we didn't ask for.
232
- short flags = arguments->flags & NUM2INT(result);
233
-
234
- return INT2NUM(events_from_poll_flags(flags));
235
- };
236
-
237
- VALUE Event_Backend_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
238
- struct Event_Backend_URing *data = NULL;
239
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
240
-
241
- int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
242
- struct io_uring_sqe *sqe = io_get_sqe(data);
243
- assert(sqe);
244
-
245
- short flags = poll_flags_from_events(NUM2INT(events));
246
-
247
- // fprintf(stderr, "poll_add(%p, %d, %d, %p)\n", sqe, descriptor, flags, (void*)fiber);
248
-
249
- io_uring_prep_poll_add(sqe, descriptor, flags);
250
- io_uring_sqe_set_data(sqe, (void*)fiber);
251
- // fprintf(stderr, "io_uring_submit\n");
252
- // io_uring_submit(&data->ring);
253
-
254
- struct io_wait_arguments io_wait_arguments = {
255
- .data = data,
256
- .fiber = fiber,
257
- .flags = flags
258
- };
259
-
260
- return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
261
- }
262
-
263
- static
264
- int io_read(struct Event_Backend_URing *data, VALUE fiber, int descriptor, char *buffer, size_t length) {
265
- struct io_uring_sqe *sqe = io_get_sqe(data);
266
- assert(sqe);
267
-
268
- struct iovec iovecs[1];
269
- iovecs[0].iov_base = buffer;
270
- iovecs[0].iov_len = length;
271
-
272
- io_uring_prep_readv(sqe, descriptor, iovecs, 1, 0);
273
- io_uring_sqe_set_data(sqe, (void*)fiber);
274
- io_uring_submit(&data->ring);
275
-
276
- return NUM2INT(Event_Backend_transfer(data->loop));
277
- }
278
-
279
- VALUE Event_Backend_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE _buffer, VALUE _offset, VALUE _length) {
280
- struct Event_Backend_URing *data = NULL;
281
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
282
-
283
- int descriptor = RB_NUM2INT(rb_funcall(io, id_fileno, 0));
284
-
285
- size_t offset = NUM2SIZET(_offset);
286
- size_t length = NUM2SIZET(_length);
287
-
288
- size_t start = offset;
289
- size_t total = 0;
290
-
291
- while (length > 0) {
292
- char *buffer = Event_Backend_resize_to_capacity(_buffer, offset, length);
293
- int result = io_read(data, fiber, descriptor, buffer+offset, length);
294
-
295
- if (result >= 0) {
296
- offset += result;
297
- length -= result;
298
- total += result;
299
- } else if (-result == EAGAIN || -result == EWOULDBLOCK) {
300
- Event_Backend_URing_io_wait(self, fiber, io, RB_INT2NUM(READABLE));
301
- } else {
302
- rb_syserr_fail(-result, strerror(-result));
303
- }
304
- }
305
-
306
- Event_Backend_resize_to_fit(_buffer, start, total);
307
-
308
- return SIZET2NUM(total);
309
- }
310
-
311
- static
312
- int io_write(struct Event_Backend_URing *data, VALUE fiber, int descriptor, char *buffer, size_t length) {
313
- struct io_uring_sqe *sqe = io_get_sqe(data);
314
- assert(sqe);
315
-
316
- struct iovec iovecs[1];
317
- iovecs[0].iov_base = buffer;
318
- iovecs[0].iov_len = length;
319
-
320
- io_uring_prep_writev(sqe, descriptor, iovecs, 1, 0);
321
- io_uring_sqe_set_data(sqe, (void*)fiber);
322
- io_uring_submit(&data->ring);
323
-
324
- return NUM2INT(Event_Backend_transfer(data->loop));
325
- }
326
-
327
- VALUE Event_Backend_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE _buffer, VALUE _offset, VALUE _length) {
328
- struct Event_Backend_URing *data = NULL;
329
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
330
-
331
- int descriptor = RB_NUM2INT(rb_funcall(io, id_fileno, 0));
332
-
333
- size_t offset = NUM2SIZET(_offset);
334
- size_t length = NUM2SIZET(_length);
335
-
336
- char *buffer = Event_Backend_verify_size(_buffer, offset, length);
337
-
338
- size_t total = 0;
339
-
340
- while (length > 0) {
341
- int result = io_write(data, fiber, descriptor, buffer+offset, length);
342
-
343
- if (result >= 0) {
344
- length -= result;
345
- offset += result;
346
- total += result;
347
- } else if (-result == EAGAIN || -result == EWOULDBLOCK) {
348
- Event_Backend_URing_io_wait(self, fiber, io, RB_INT2NUM(WRITABLE));
349
- } else {
350
- rb_syserr_fail(-result, strerror(-result));
351
- }
352
- }
353
-
354
- return SIZET2NUM(total);
355
- }
356
-
357
- static
358
- struct __kernel_timespec * make_timeout(VALUE duration, struct __kernel_timespec *storage) {
359
- if (duration == Qnil) {
360
- return NULL;
361
- }
362
-
363
- if (FIXNUM_P(duration)) {
364
- storage->tv_sec = NUM2TIMET(duration);
365
- storage->tv_nsec = 0;
366
-
367
- return storage;
368
- }
369
-
370
- else if (RB_FLOAT_TYPE_P(duration)) {
371
- double value = RFLOAT_VALUE(duration);
372
- time_t seconds = value;
373
-
374
- storage->tv_sec = seconds;
375
- storage->tv_nsec = (value - seconds) * 1000000000L;
376
-
377
- return storage;
378
- }
379
-
380
- rb_raise(rb_eRuntimeError, "unable to convert timeout");
381
- }
382
-
383
- static
384
- int timeout_nonblocking(struct __kernel_timespec *timespec) {
385
- return timespec && timespec->tv_sec == 0 && timespec->tv_nsec == 0;
386
- }
387
-
388
- struct select_arguments {
389
- struct Event_Backend_URing *data;
390
-
391
- int result;
392
-
393
- struct __kernel_timespec storage;
394
- struct __kernel_timespec *timeout;
395
- };
396
-
397
- static
398
- void * select_internal(void *_arguments) {
399
- struct select_arguments * arguments = (struct select_arguments *)_arguments;
400
-
401
- io_uring_submit(&arguments->data->ring);
402
-
403
- struct io_uring_cqe *cqe = NULL;
404
- arguments->result = io_uring_wait_cqe_timeout(&arguments->data->ring, &cqe, arguments->timeout);
405
-
406
- return NULL;
407
- }
408
-
409
- static
410
- int select_internal_without_gvl(struct select_arguments *arguments) {
411
- rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
412
-
413
- if (arguments->result == -ETIME) {
414
- arguments->result = 0;
415
- } else if (arguments->result < 0) {
416
- rb_syserr_fail(-arguments->result, "select_internal_without_gvl:io_uring_wait_cqes");
417
- } else {
418
- // At least 1 event is waiting:
419
- arguments->result = 1;
420
- }
421
-
422
- return arguments->result;
423
- }
424
-
425
- static inline
426
- unsigned select_process_completions(struct io_uring *ring) {
427
- unsigned completed = 0;
428
- unsigned head;
429
- struct io_uring_cqe *cqe;
430
-
431
- io_uring_for_each_cqe(ring, head, cqe) {
432
- ++completed;
433
-
434
- // If the operation was cancelled, or the operation has no user data (fiber):
435
- if (cqe->res == -ECANCELED || cqe->user_data == 0 || cqe->user_data == LIBURING_UDATA_TIMEOUT) {
436
- continue;
437
- }
438
-
439
- VALUE fiber = (VALUE)cqe->user_data;
440
- VALUE result = INT2NUM(cqe->res);
441
-
442
- // fprintf(stderr, "cqe res=%d user_data=%p\n", cqe->res, (void*)cqe->user_data);
443
-
444
- Event_Backend_transfer_result(fiber, result);
445
- }
446
-
447
- if (completed) {
448
- io_uring_cq_advance(ring, completed);
449
- }
450
-
451
- return completed;
452
- }
453
-
454
- VALUE Event_Backend_URing_select(VALUE self, VALUE duration) {
455
- struct Event_Backend_URing *data = NULL;
456
- TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
457
-
458
- int result = select_process_completions(&data->ring);
459
-
460
- if (result < 0) {
461
- rb_syserr_fail(-result, strerror(-result));
462
- } else if (result == 0) {
463
- // We might need to wait for events:
464
- struct select_arguments arguments = {
465
- .data = data,
466
- .timeout = NULL,
467
- };
468
-
469
- arguments.timeout = make_timeout(duration, &arguments.storage);
470
-
471
- if (!timeout_nonblocking(arguments.timeout)) {
472
- result = select_internal_without_gvl(&arguments);
473
- } else {
474
- io_uring_submit(&data->ring);
475
- }
476
- }
477
-
478
- result = select_process_completions(&data->ring);
479
-
480
- return INT2NUM(result);
481
- }
482
-
483
- void Init_Event_Backend_URing(VALUE Event_Backend) {
484
- id_fileno = rb_intern("fileno");
485
-
486
- Event_Backend_URing = rb_define_class_under(Event_Backend, "URing", rb_cObject);
487
-
488
- rb_define_alloc_func(Event_Backend_URing, Event_Backend_URing_allocate);
489
- rb_define_method(Event_Backend_URing, "initialize", Event_Backend_URing_initialize, 1);
490
- rb_define_method(Event_Backend_URing, "select", Event_Backend_URing_select, 1);
491
- rb_define_method(Event_Backend_URing, "close", Event_Backend_URing_close, 0);
492
-
493
- rb_define_method(Event_Backend_URing, "io_wait", Event_Backend_URing_io_wait, 3);
494
- rb_define_method(Event_Backend_URing, "io_read", Event_Backend_URing_io_read, 5);
495
- rb_define_method(Event_Backend_URing, "io_write", Event_Backend_URing_io_write, 5);
496
-
497
- rb_define_method(Event_Backend_URing, "process_wait", Event_Backend_URing_process_wait, 3);
498
- }