event 0.4.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- }