event 0.4.4 → 0.8.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.
@@ -22,7 +22,7 @@
22
22
 
23
23
  #include <ruby.h>
24
24
 
25
- #define EVENT_BACKEND_URING
25
+ #define EVENT_SELECTOR_URING
26
26
 
27
- void Init_Event_Backend_URing(VALUE Event_Backend);
28
- VALUE Event_Backend_URing_select(VALUE self, VALUE duration);
27
+ void Init_Event_Selector_URing(VALUE Event_Selector);
28
+ VALUE Event_Selector_URing_select(VALUE self, VALUE duration);
data/lib/event.rb CHANGED
@@ -19,7 +19,8 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require_relative 'event/version'
22
- require_relative 'event/backend'
22
+ require_relative 'event/selector'
23
+ require_relative 'event/selector'
23
24
 
24
25
  module Event
25
26
  # These constants are the same as those defined in IO.
@@ -0,0 +1,126 @@
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
+ require "event/version"
22
+
23
+ module Event
24
+ class Debug
25
+ def initialize(selector)
26
+ @selector = selector
27
+
28
+ @readable = {}
29
+ @writable = {}
30
+ @priority = {}
31
+ end
32
+
33
+ def close
34
+ if @selector.nil?
35
+ raise "Selector already closed!"
36
+ end
37
+
38
+ @selector.close
39
+ @selector = nil
40
+ end
41
+
42
+ def transfer(fiber, *arguments)
43
+ @selector.transfer(fiber, *arguments)
44
+ end
45
+
46
+ def yield
47
+ @selector.yield
48
+ end
49
+
50
+ def push(fiber)
51
+ @selector.push(fiber)
52
+ end
53
+
54
+ def raise(fiber, *arguments)
55
+ @selector.raise(fiber, *arguments)
56
+ end
57
+
58
+ def ready?
59
+ @selector.ready?
60
+ end
61
+
62
+ def io_wait(fiber, io, events)
63
+ register_readable(fiber, io, events)
64
+ end
65
+
66
+ def select(duration = nil)
67
+ @selector.select(duration)
68
+ end
69
+
70
+ private
71
+
72
+ def register_readable(fiber, io, events)
73
+ if (events & READABLE) > 0
74
+ if @readable.key?(io)
75
+ raise "Cannot wait for #{io} to become readable from multiple fibers."
76
+ end
77
+
78
+ begin
79
+ @readable[io] = fiber
80
+
81
+ register_writable(fiber, io, events)
82
+ ensure
83
+ @readable.delete(io)
84
+ end
85
+ else
86
+ register_writable(fiber, io, events)
87
+ end
88
+ end
89
+
90
+ def register_writable(fiber, io, events)
91
+ if (events & WRITABLE) > 0
92
+ if @writable.key?(io)
93
+ raise "Cannot wait for #{io} to become writable from multiple fibers."
94
+ end
95
+
96
+ begin
97
+ @writable[io] = fiber
98
+
99
+ register_priority(fiber, io, events)
100
+ ensure
101
+ @writable.delete(io)
102
+ end
103
+ else
104
+ register_priority(fiber, io, events)
105
+ end
106
+ end
107
+
108
+ def register_priority(fiber, io, events)
109
+ if (events & PRIORITY) > 0
110
+ if @priority.key?(io)
111
+ raise "Cannot wait for #{io} to become priority from multiple fibers."
112
+ end
113
+
114
+ begin
115
+ @priority[io] = fiber
116
+
117
+ @selector.io_wait(fiber, io, events)
118
+ ensure
119
+ @priority.delete(io)
120
+ end
121
+ else
122
+ @selector.io_wait(fiber, io, events)
123
+ end
124
+ end
125
+ end
126
+ end
@@ -18,9 +18,32 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
- require "event/version"
21
+ require_relative 'selector/select'
22
22
 
23
23
  module Event
24
- class Selector
24
+ module Selector
25
+ def self.default(env = ENV)
26
+ if name = env['EVENT_SELECTOR']&.to_sym
27
+ if Event::Selector.const_defined?(name)
28
+ return Event::Selector.const_get(name)
29
+ else
30
+ warn "Could not find EVENT_SELECTOR=#{name}!"
31
+ end
32
+ end
33
+
34
+ if self.const_defined?(:URing)
35
+ return Event::Selector::URing
36
+ elsif self.const_defined?(:KQueue)
37
+ return Event::Selector::KQueue
38
+ elsif self.const_defined?(:EPoll)
39
+ return Event::Selector::EPoll
40
+ else
41
+ return Event::Selector::Select
42
+ end
43
+ end
44
+
45
+ def self.new(...)
46
+ default.new(...)
47
+ end
25
48
  end
26
49
  end
@@ -19,13 +19,15 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Event
22
- module Backend
22
+ module Selector
23
23
  class Select
24
24
  def initialize(loop)
25
25
  @loop = loop
26
26
 
27
27
  @readable = {}
28
28
  @writable = {}
29
+
30
+ @ready = []
29
31
  end
30
32
 
31
33
  def close
@@ -34,6 +36,36 @@ module Event
34
36
  @writable = nil
35
37
  end
36
38
 
39
+ def transfer(fiber, *arguments)
40
+ @ready.push(Fiber.current)
41
+ fiber.transfer(*arguments)
42
+ ensure
43
+ @ready.delete(fiber)
44
+ end
45
+
46
+ def yield
47
+ fiber = Fiber.current
48
+ @ready.push(fiber)
49
+ @loop.transfer
50
+ ensure
51
+ @ready.delete(fiber)
52
+ end
53
+
54
+ def push(fiber)
55
+ @ready.push(fiber)
56
+ end
57
+
58
+ def raise(fiber, *arguments)
59
+ @ready.push(Fiber.current)
60
+ @fiber.raise(*arguments)
61
+ ensure
62
+ @ready.delete(fiber)
63
+ end
64
+
65
+ def ready?
66
+ @ready.any?
67
+ end
68
+
37
69
  def io_wait(fiber, io, events)
38
70
  remove_readable = remove_writable = false
39
71
 
@@ -53,7 +85,81 @@ module Event
53
85
  @writable.delete(io) if remove_writable
54
86
  end
55
87
 
88
+ if IO.const_defined?(:Buffer)
89
+ def io_read(fiber, io, buffer, length)
90
+ offset = 0
91
+
92
+ while length > 0
93
+ # The maximum size we can read:
94
+ maximum_size = buffer.size - offset
95
+
96
+ case result = io.read_nonblock(maximum_size, exception: false)
97
+ when :wait_readable
98
+ self.io_wait(fiber, io, READABLE)
99
+ when :wait_writable
100
+ self.io_wait(fiber, io, WRITABLE)
101
+ else
102
+ break if result.empty?
103
+
104
+ buffer.copy(result, offset)
105
+
106
+ offset += result.bytesize
107
+ length -= result.bytesize
108
+ end
109
+ end
110
+
111
+ return offset
112
+ end
113
+
114
+ def io_write(fiber, io, buffer, length)
115
+ offset = 0
116
+
117
+ while length > 0
118
+ # From offset until the end:
119
+ chunk = buffer.to_str(offset, length)
120
+ case result = io.write_nonblock(chunk, exception: false)
121
+ when :wait_readable
122
+ self.io_wait(fiber, io, READABLE)
123
+ when :wait_writable
124
+ self.io_wait(fiber, io, WRITABLE)
125
+ else
126
+ offset += result
127
+ length -= result
128
+ end
129
+ end
130
+
131
+ return offset
132
+ end
133
+ end
134
+
135
+ def process_wait(fiber, pid, flags)
136
+ r, w = IO.pipe
137
+
138
+ thread = Thread.new do
139
+ Process::Status.wait(pid, flags)
140
+ ensure
141
+ w.close
142
+ end
143
+
144
+ self.io_wait(fiber, r, READABLE)
145
+
146
+ return thread.value
147
+ ensure
148
+ r.close
149
+ w.close
150
+ thread&.kill
151
+ end
152
+
56
153
  def select(duration = nil)
154
+ if @ready.any?
155
+ ready = @ready
156
+ @ready = Array.new
157
+
158
+ ready.each do |fiber|
159
+ fiber.transfer if fiber.alive?
160
+ end
161
+ end
162
+
57
163
  readable, writable, _ = ::IO.select(@readable.keys, @writable.keys, nil, duration)
58
164
 
59
165
  ready = Hash.new(0)
data/lib/event/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Event
2
- VERSION = "0.4.4"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-11 00:00:00.000000000 Z
11
+ date: 2021-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bake
@@ -74,29 +74,28 @@ extensions:
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ext/event/Makefile
77
- - ext/event/backend.o
78
- - ext/event/backend/backend.c
79
- - ext/event/backend/backend.h
80
- - ext/event/backend/epoll.c
81
- - ext/event/backend/epoll.h
82
- - ext/event/backend/kqueue.c
83
- - ext/event/backend/kqueue.h
84
- - ext/event/backend/uring.c
85
- - ext/event/backend/uring.h
86
- - ext/event/epoll.o
77
+ - ext/event/event.bundle
87
78
  - ext/event/event.c
88
79
  - ext/event/event.h
89
80
  - ext/event/event.o
90
- - ext/event/event.so
91
81
  - ext/event/extconf.h
92
82
  - ext/event/extconf.rb
83
+ - ext/event/kqueue.o
93
84
  - ext/event/mkmf.log
94
- - ext/event/uring.o
85
+ - ext/event/selector.o
86
+ - ext/event/selector/epoll.c
87
+ - ext/event/selector/epoll.h
88
+ - ext/event/selector/kqueue.c
89
+ - ext/event/selector/kqueue.h
90
+ - ext/event/selector/pidfd.c
91
+ - ext/event/selector/selector.c
92
+ - ext/event/selector/selector.h
93
+ - ext/event/selector/uring.c
94
+ - ext/event/selector/uring.h
95
95
  - lib/event.rb
96
- - lib/event/backend.rb
97
- - lib/event/backend/select.rb
98
- - lib/event/debug/selector.rb
96
+ - lib/event/debug.rb
99
97
  - lib/event/selector.rb
98
+ - lib/event/selector/select.rb
100
99
  - lib/event/version.rb
101
100
  homepage: https://github.com/socketry/event
102
101
  licenses:
@@ -117,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
116
  - !ruby/object:Gem::Version
118
117
  version: '0'
119
118
  requirements: []
120
- rubygems_version: 3.3.0.dev
119
+ rubygems_version: 3.2.15
121
120
  signing_key:
122
121
  specification_version: 4
123
122
  summary: An event loop.
data/ext/event/backend.o DELETED
Binary file
@@ -1,39 +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
- static ID id_transfer, id_alive_p;
24
-
25
- void Init_Event_Backend(VALUE Event_Backend) {
26
- id_transfer = rb_intern("transfer");
27
- id_alive_p = rb_intern("alive?");
28
- }
29
-
30
- VALUE
31
- Event_Backend_resume_safe(VALUE fiber, VALUE result) {
32
- VALUE alive = rb_funcall(fiber, id_alive_p, 0);
33
-
34
- if (RTEST(alive)) {
35
- return rb_funcall(fiber, id_transfer, 1, result);
36
- } else {
37
- return Qnil;
38
- }
39
- }
@@ -1,309 +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
- static VALUE Event_Backend_EPoll = Qnil;
29
- static ID id_fileno, id_transfer;
30
-
31
- enum {EPOLL_MAX_EVENTS = 64};
32
-
33
- struct Event_Backend_EPoll {
34
- VALUE loop;
35
- int descriptor;
36
- };
37
-
38
- void Event_Backend_EPoll_Type_mark(void *_data)
39
- {
40
- struct Event_Backend_EPoll *data = _data;
41
- rb_gc_mark(data->loop);
42
- }
43
-
44
- static
45
- void close_internal(struct Event_Backend_EPoll *data) {
46
- if (data->descriptor >= 0) {
47
- close(data->descriptor);
48
- data->descriptor = -1;
49
- }
50
- }
51
-
52
- void Event_Backend_EPoll_Type_free(void *_data)
53
- {
54
- struct Event_Backend_EPoll *data = _data;
55
-
56
- close_internal(data);
57
-
58
- free(data);
59
- }
60
-
61
- size_t Event_Backend_EPoll_Type_size(const void *data)
62
- {
63
- return sizeof(struct Event_Backend_EPoll);
64
- }
65
-
66
- static const rb_data_type_t Event_Backend_EPoll_Type = {
67
- .wrap_struct_name = "Event::Backend::EPoll",
68
- .function = {
69
- .dmark = Event_Backend_EPoll_Type_mark,
70
- .dfree = Event_Backend_EPoll_Type_free,
71
- .dsize = Event_Backend_EPoll_Type_size,
72
- },
73
- .data = NULL,
74
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
75
- };
76
-
77
- VALUE Event_Backend_EPoll_allocate(VALUE self) {
78
- struct Event_Backend_EPoll *data = NULL;
79
- VALUE instance = TypedData_Make_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
80
-
81
- data->loop = Qnil;
82
- data->descriptor = -1;
83
-
84
- return instance;
85
- }
86
-
87
- VALUE Event_Backend_EPoll_initialize(VALUE self, VALUE loop) {
88
- struct Event_Backend_EPoll *data = NULL;
89
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
90
-
91
- data->loop = loop;
92
- int result = epoll_create1(EPOLL_CLOEXEC);
93
-
94
- if (result == -1) {
95
- rb_sys_fail("epoll_create");
96
- } else {
97
- data->descriptor = result;
98
-
99
- rb_update_max_fd(data->descriptor);
100
- }
101
-
102
- return self;
103
- }
104
-
105
- VALUE Event_Backend_EPoll_close(VALUE self) {
106
- struct Event_Backend_EPoll *data = NULL;
107
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
108
-
109
- close_internal(data);
110
-
111
- return Qnil;
112
- }
113
-
114
- static inline
115
- uint32_t epoll_flags_from_events(int events) {
116
- uint32_t flags = 0;
117
-
118
- if (events & READABLE) flags |= EPOLLIN;
119
- if (events & PRIORITY) flags |= EPOLLPRI;
120
- if (events & WRITABLE) flags |= EPOLLOUT;
121
-
122
- flags |= EPOLLRDHUP;
123
- flags |= EPOLLONESHOT;
124
-
125
- return flags;
126
- }
127
-
128
- static inline
129
- int events_from_epoll_flags(uint32_t flags) {
130
- int events = 0;
131
-
132
- if (flags & EPOLLIN) events |= READABLE;
133
- if (flags & EPOLLPRI) events |= PRIORITY;
134
- if (flags & EPOLLOUT) events |= WRITABLE;
135
-
136
- return events;
137
- }
138
-
139
- struct io_wait_arguments {
140
- struct Event_Backend_EPoll *data;
141
- int descriptor;
142
- int duplicate;
143
- };
144
-
145
- static
146
- VALUE io_wait_ensure(VALUE _arguments) {
147
- struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
148
-
149
- if (arguments->duplicate >= 0) {
150
- epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->duplicate, NULL);
151
-
152
- close(arguments->duplicate);
153
- } else {
154
- epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);
155
- }
156
-
157
- return Qnil;
158
- };
159
-
160
- static
161
- VALUE io_wait_transfer(VALUE _arguments) {
162
- struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
163
-
164
- VALUE result = rb_funcall(arguments->data->loop, id_transfer, 0);
165
-
166
- return INT2NUM(events_from_epoll_flags(NUM2INT(result)));
167
- };
168
-
169
- VALUE Event_Backend_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
170
- struct Event_Backend_EPoll *data = NULL;
171
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
172
-
173
- struct epoll_event event = {0};
174
-
175
- int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
176
- int duplicate = -1;
177
-
178
- event.events = epoll_flags_from_events(NUM2INT(events));
179
- event.data.ptr = (void*)fiber;
180
-
181
- // fprintf(stderr, "<- fiber=%p descriptor=%d\n", (void*)fiber, descriptor);
182
-
183
- // A better approach is to batch all changes:
184
- int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
185
-
186
- if (result == -1 && errno == EEXIST) {
187
- // The file descriptor was already inserted into epoll.
188
- duplicate = descriptor = dup(descriptor);
189
-
190
- rb_update_max_fd(duplicate);
191
-
192
- if (descriptor == -1)
193
- rb_sys_fail("dup");
194
-
195
- result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
196
- }
197
-
198
- if (result == -1) {
199
- rb_sys_fail("epoll_ctl");
200
- }
201
-
202
- struct io_wait_arguments io_wait_arguments = {
203
- .data = data,
204
- .descriptor = descriptor,
205
- .duplicate = duplicate
206
- };
207
-
208
- return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
209
- }
210
-
211
- static
212
- int make_timeout(VALUE duration) {
213
- if (duration == Qnil) {
214
- return -1;
215
- }
216
-
217
- if (FIXNUM_P(duration)) {
218
- return NUM2LONG(duration) * 1000L;
219
- }
220
-
221
- else if (RB_FLOAT_TYPE_P(duration)) {
222
- double value = RFLOAT_VALUE(duration);
223
-
224
- return value * 1000;
225
- }
226
-
227
- rb_raise(rb_eRuntimeError, "unable to convert timeout");
228
- }
229
-
230
- struct select_arguments {
231
- struct Event_Backend_EPoll *data;
232
-
233
- int count;
234
- struct epoll_event events[EPOLL_MAX_EVENTS];
235
-
236
- int timeout;
237
- };
238
-
239
- static
240
- void * select_internal(void *_arguments) {
241
- struct select_arguments * arguments = (struct select_arguments *)_arguments;
242
-
243
- arguments->count = epoll_wait(arguments->data->descriptor, arguments->events, EPOLL_MAX_EVENTS, arguments->timeout);
244
-
245
- return NULL;
246
- }
247
-
248
- static
249
- void select_internal_without_gvl(struct select_arguments *arguments) {
250
- rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
251
-
252
- if (arguments->count == -1) {
253
- rb_sys_fail("select_internal_without_gvl:epoll_wait");
254
- }
255
- }
256
-
257
- static
258
- void select_internal_with_gvl(struct select_arguments *arguments) {
259
- select_internal((void *)arguments);
260
-
261
- if (arguments->count == -1) {
262
- rb_sys_fail("select_internal_with_gvl:epoll_wait");
263
- }
264
- }
265
-
266
- VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
267
- struct Event_Backend_EPoll *data = NULL;
268
- TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
269
-
270
- struct select_arguments arguments = {
271
- .data = data,
272
- .timeout = 0
273
- };
274
-
275
- select_internal_with_gvl(&arguments);
276
-
277
- if (arguments.count == 0) {
278
- arguments.timeout = make_timeout(duration);
279
-
280
- if (arguments.timeout != 0) {
281
- select_internal_without_gvl(&arguments);
282
- }
283
- }
284
-
285
- for (int i = 0; i < arguments.count; i += 1) {
286
- VALUE fiber = (VALUE)arguments.events[i].data.ptr;
287
- VALUE result = INT2NUM(arguments.events[i].events);
288
-
289
- // fprintf(stderr, "-> fiber=%p descriptor=%d\n", (void*)fiber, events[i].data.fd);
290
-
291
- Event_Backend_resume_safe(fiber, result);
292
- }
293
-
294
- return INT2NUM(arguments.count);
295
- }
296
-
297
- void Init_Event_Backend_EPoll(VALUE Event_Backend) {
298
- id_fileno = rb_intern("fileno");
299
- id_transfer = rb_intern("transfer");
300
-
301
- Event_Backend_EPoll = rb_define_class_under(Event_Backend, "EPoll", rb_cObject);
302
-
303
- rb_define_alloc_func(Event_Backend_EPoll, Event_Backend_EPoll_allocate);
304
- rb_define_method(Event_Backend_EPoll, "initialize", Event_Backend_EPoll_initialize, 1);
305
- rb_define_method(Event_Backend_EPoll, "close", Event_Backend_EPoll_close, 0);
306
-
307
- rb_define_method(Event_Backend_EPoll, "io_wait", Event_Backend_EPoll_io_wait, 3);
308
- rb_define_method(Event_Backend_EPoll, "select", Event_Backend_EPoll_select, 1);
309
- }