event 0.5.0 → 0.8.1

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,64 +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
-
23
- #if HAVE_RB_FIBER_TRANSFER_KW
24
- #define HAVE_RB_FIBER_TRANSFER 1
25
- #else
26
- #define HAVE_RB_FIBER_TRANSFER 0
27
- #endif
28
-
29
- static ID id_transfer, id_wait;
30
- static VALUE rb_Process_Status = Qnil;
31
-
32
- void Init_Event_Backend(VALUE Event_Backend) {
33
- id_transfer = rb_intern("transfer");
34
- id_wait = rb_intern("wait");
35
- // id_alive_p = rb_intern("alive?");
36
- rb_Process_Status = rb_const_get_at(rb_mProcess, rb_intern("Status"));
37
- }
38
-
39
- VALUE
40
- Event_Backend_transfer(VALUE fiber) {
41
- #if HAVE_RB_FIBER_TRANSFER
42
- return rb_fiber_transfer(fiber, 0, NULL);
43
- #else
44
- return rb_funcall(fiber, id_transfer, 0);
45
- #endif
46
- }
47
-
48
- VALUE
49
- Event_Backend_transfer_result(VALUE fiber, VALUE result) {
50
- // if (!RTEST(rb_fiber_alive_p(fiber))) {
51
- // return Qnil;
52
- // }
53
-
54
- #if HAVE_RB_FIBER_TRANSFER
55
- return rb_fiber_transfer(fiber, 1, &result);
56
- #else
57
- return rb_funcall(fiber, id_transfer, 1, result);
58
- #endif
59
- }
60
-
61
- VALUE Event_Backend_process_status_wait(rb_pid_t pid)
62
- {
63
- return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), INT2NUM(WNOHANG));
64
- }
@@ -1,38 +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);
@@ -1,365 +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 "kqueue.h"
22
- #include "backend.h"
23
-
24
- #include <sys/epoll.h>
25
- #include <time.h>
26
- #include <errno.h>
27
-
28
- #include "pidfd.c"
29
-
30
- static VALUE Event_Backend_EPoll = Qnil;
31
- static ID id_fileno;
32
-
33
- enum {EPOLL_MAX_EVENTS = 64};
34
-
35
- struct Event_Backend_EPoll {
36
- VALUE loop;
37
- int descriptor;
38
- };
39
-
40
- void Event_Backend_EPoll_Type_mark(void *_data)
41
- {
42
- struct Event_Backend_EPoll *data = _data;
43
- rb_gc_mark(data->loop);
44
- }
45
-
46
- static
47
- void close_internal(struct Event_Backend_EPoll *data) {
48
- if (data->descriptor >= 0) {
49
- close(data->descriptor);
50
- data->descriptor = -1;
51
- }
52
- }
53
-
54
- void Event_Backend_EPoll_Type_free(void *_data)
55
- {
56
- struct Event_Backend_EPoll *data = _data;
57
-
58
- close_internal(data);
59
-
60
- free(data);
61
- }
62
-
63
- size_t Event_Backend_EPoll_Type_size(const void *data)
64
- {
65
- return sizeof(struct Event_Backend_EPoll);
66
- }
67
-
68
- static const rb_data_type_t Event_Backend_EPoll_Type = {
69
- .wrap_struct_name = "Event::Backend::EPoll",
70
- .function = {
71
- .dmark = Event_Backend_EPoll_Type_mark,
72
- .dfree = Event_Backend_EPoll_Type_free,
73
- .dsize = Event_Backend_EPoll_Type_size,
74
- },
75
- .data = NULL,
76
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
77
- };
78
-
79
- VALUE Event_Backend_EPoll_allocate(VALUE self) {
80
- struct Event_Backend_EPoll *data = NULL;
81
- VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
82
-
83
- data->loop = Qnil;
84
- data->descriptor = -1;
85
-
86
- return instance;
87
- }
88
-
89
- VALUE Event_Backend_EPoll_initialize(VALUE self, VALUE loop) {
90
- struct Event_Backend_EPoll *data = NULL;
91
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
92
-
93
- data->loop = loop;
94
- int result = epoll_create1(EPOLL_CLOEXEC);
95
-
96
- if (result == -1) {
97
- rb_sys_fail("epoll_create");
98
- } else {
99
- data->descriptor = result;
100
-
101
- rb_update_max_fd(data->descriptor);
102
- }
103
-
104
- return self;
105
- }
106
-
107
- VALUE Event_Backend_EPoll_close(VALUE self) {
108
- struct Event_Backend_EPoll *data = NULL;
109
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
110
-
111
- close_internal(data);
112
-
113
- return Qnil;
114
- }
115
-
116
- struct process_wait_arguments {
117
- struct Event_Backend_EPoll *data;
118
- pid_t pid;
119
- int flags;
120
- int descriptor;
121
- };
122
-
123
- static
124
- VALUE process_wait_transfer(VALUE _arguments) {
125
- struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
126
-
127
- Event_Backend_transfer(arguments->data->loop);
128
-
129
- return Event_Backend_process_status_wait(arguments->pid);
130
- }
131
-
132
- static
133
- VALUE process_wait_ensure(VALUE _arguments) {
134
- struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
135
-
136
- // epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);
137
-
138
- close(arguments->descriptor);
139
-
140
- return Qnil;
141
- }
142
-
143
- VALUE Event_Backend_EPoll_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
144
- struct Event_Backend_EPoll *data = NULL;
145
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
146
-
147
- struct process_wait_arguments process_wait_arguments = {
148
- .data = data,
149
- .pid = NUM2PIDT(pid),
150
- .flags = NUM2INT(flags),
151
- };
152
-
153
- process_wait_arguments.descriptor = pidfd_open(process_wait_arguments.pid, 0);
154
- rb_update_max_fd(process_wait_arguments.descriptor);
155
-
156
- struct epoll_event event = {
157
- .events = EPOLLIN|EPOLLRDHUP|EPOLLONESHOT,
158
- .data = {.ptr = (void*)fiber},
159
- };
160
-
161
- int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, process_wait_arguments.descriptor, &event);
162
-
163
- if (result == -1) {
164
- rb_sys_fail("epoll_ctl(process_wait)");
165
- }
166
-
167
- return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
168
- }
169
-
170
- static inline
171
- uint32_t epoll_flags_from_events(int events) {
172
- uint32_t flags = 0;
173
-
174
- if (events & READABLE) flags |= EPOLLIN;
175
- if (events & PRIORITY) flags |= EPOLLPRI;
176
- if (events & WRITABLE) flags |= EPOLLOUT;
177
-
178
- flags |= EPOLLRDHUP;
179
- flags |= EPOLLONESHOT;
180
-
181
- return flags;
182
- }
183
-
184
- static inline
185
- int events_from_epoll_flags(uint32_t flags) {
186
- int events = 0;
187
-
188
- if (flags & EPOLLIN) events |= READABLE;
189
- if (flags & EPOLLPRI) events |= PRIORITY;
190
- if (flags & EPOLLOUT) events |= WRITABLE;
191
-
192
- return events;
193
- }
194
-
195
- struct io_wait_arguments {
196
- struct Event_Backend_EPoll *data;
197
- int descriptor;
198
- int duplicate;
199
- };
200
-
201
- static
202
- VALUE io_wait_ensure(VALUE _arguments) {
203
- struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
204
-
205
- if (arguments->duplicate >= 0) {
206
- epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->duplicate, NULL);
207
-
208
- close(arguments->duplicate);
209
- } else {
210
- epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);
211
- }
212
-
213
- return Qnil;
214
- };
215
-
216
- static
217
- VALUE io_wait_transfer(VALUE _arguments) {
218
- struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
219
-
220
- VALUE result = Event_Backend_transfer(arguments->data->loop);
221
-
222
- return INT2NUM(events_from_epoll_flags(NUM2INT(result)));
223
- };
224
-
225
- VALUE Event_Backend_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
226
- struct Event_Backend_EPoll *data = NULL;
227
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
228
-
229
- struct epoll_event event = {0};
230
-
231
- int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
232
- int duplicate = -1;
233
-
234
- event.events = epoll_flags_from_events(NUM2INT(events));
235
- event.data.ptr = (void*)fiber;
236
-
237
- // fprintf(stderr, "<- fiber=%p descriptor=%d\n", (void*)fiber, descriptor);
238
-
239
- // A better approach is to batch all changes:
240
- int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
241
-
242
- if (result == -1 && errno == EEXIST) {
243
- // The file descriptor was already inserted into epoll.
244
- duplicate = descriptor = dup(descriptor);
245
-
246
- rb_update_max_fd(duplicate);
247
-
248
- if (descriptor == -1)
249
- rb_sys_fail("dup");
250
-
251
- result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
252
- }
253
-
254
- if (result == -1) {
255
- rb_sys_fail("epoll_ctl");
256
- }
257
-
258
- struct io_wait_arguments io_wait_arguments = {
259
- .data = data,
260
- .descriptor = descriptor,
261
- .duplicate = duplicate
262
- };
263
-
264
- return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
265
- }
266
-
267
- static
268
- int make_timeout(VALUE duration) {
269
- if (duration == Qnil) {
270
- return -1;
271
- }
272
-
273
- if (FIXNUM_P(duration)) {
274
- return NUM2LONG(duration) * 1000L;
275
- }
276
-
277
- else if (RB_FLOAT_TYPE_P(duration)) {
278
- double value = RFLOAT_VALUE(duration);
279
-
280
- return value * 1000;
281
- }
282
-
283
- rb_raise(rb_eRuntimeError, "unable to convert timeout");
284
- }
285
-
286
- struct select_arguments {
287
- struct Event_Backend_EPoll *data;
288
-
289
- int count;
290
- struct epoll_event events[EPOLL_MAX_EVENTS];
291
-
292
- int timeout;
293
- };
294
-
295
- static
296
- void * select_internal(void *_arguments) {
297
- struct select_arguments * arguments = (struct select_arguments *)_arguments;
298
-
299
- arguments->count = epoll_wait(arguments->data->descriptor, arguments->events, EPOLL_MAX_EVENTS, arguments->timeout);
300
-
301
- return NULL;
302
- }
303
-
304
- static
305
- void select_internal_without_gvl(struct select_arguments *arguments) {
306
- rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
307
-
308
- if (arguments->count == -1) {
309
- rb_sys_fail("select_internal_without_gvl:epoll_wait");
310
- }
311
- }
312
-
313
- static
314
- void select_internal_with_gvl(struct select_arguments *arguments) {
315
- select_internal((void *)arguments);
316
-
317
- if (arguments->count == -1) {
318
- rb_sys_fail("select_internal_with_gvl:epoll_wait");
319
- }
320
- }
321
-
322
- VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
323
- struct Event_Backend_EPoll *data = NULL;
324
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
325
-
326
- struct select_arguments arguments = {
327
- .data = data,
328
- .timeout = 0
329
- };
330
-
331
- select_internal_with_gvl(&arguments);
332
-
333
- if (arguments.count == 0) {
334
- arguments.timeout = make_timeout(duration);
335
-
336
- if (arguments.timeout != 0) {
337
- select_internal_without_gvl(&arguments);
338
- }
339
- }
340
-
341
- for (int i = 0; i < arguments.count; i += 1) {
342
- VALUE fiber = (VALUE)arguments.events[i].data.ptr;
343
- VALUE result = INT2NUM(arguments.events[i].events);
344
-
345
- // fprintf(stderr, "-> fiber=%p descriptor=%d\n", (void*)fiber, events[i].data.fd);
346
-
347
- Event_Backend_transfer_result(fiber, result);
348
- }
349
-
350
- return INT2NUM(arguments.count);
351
- }
352
-
353
- void Init_Event_Backend_EPoll(VALUE Event_Backend) {
354
- id_fileno = rb_intern("fileno");
355
-
356
- Event_Backend_EPoll = rb_define_class_under(Event_Backend, "EPoll", rb_cObject);
357
-
358
- rb_define_alloc_func(Event_Backend_EPoll, Event_Backend_EPoll_allocate);
359
- rb_define_method(Event_Backend_EPoll, "initialize", Event_Backend_EPoll_initialize, 1);
360
- rb_define_method(Event_Backend_EPoll, "close", Event_Backend_EPoll_close, 0);
361
-
362
- rb_define_method(Event_Backend_EPoll, "io_wait", Event_Backend_EPoll_io_wait, 3);
363
- rb_define_method(Event_Backend_EPoll, "select", Event_Backend_EPoll_select, 1);
364
- rb_define_method(Event_Backend_EPoll, "process_wait", Event_Backend_EPoll_process_wait, 3);
365
- }