io-event 1.2.2 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/ext/extconf.rb +7 -24
- data/ext/io/event/selector/array.h +135 -0
- data/ext/io/event/selector/epoll.c +474 -204
- data/ext/io/event/selector/kqueue.c +513 -222
- data/ext/io/event/selector/list.h +88 -0
- data/ext/io/event/selector/selector.c +16 -21
- data/ext/io/event/selector/selector.h +23 -8
- data/ext/io/event/selector/uring.c +459 -223
- data/lib/io/event/interrupt.rb +1 -1
- data/lib/io/event/selector/nonblock.rb +1 -1
- data/lib/io/event/selector/select.rb +123 -22
- data/lib/io/event/selector.rb +2 -6
- data/lib/io/event/support.rb +11 -0
- data/lib/io/event/version.rb +2 -2
- data/lib/io/event.rb +1 -1
- data/license.md +2 -1
- data/readme.md +13 -5
- data.tar.gz.sig +0 -0
- metadata +8 -61
- metadata.gz.sig +0 -0
data/lib/io/event/interrupt.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-
|
4
|
+
# Copyright, 2021-2023, by Samuel Williams.
|
5
|
+
# Copyright, 2023, by Math Ieu.
|
5
6
|
|
6
7
|
require_relative '../interrupt'
|
7
8
|
require_relative '../support'
|
@@ -103,14 +104,26 @@ module IO::Event
|
|
103
104
|
self.fiber&.alive?
|
104
105
|
end
|
105
106
|
|
106
|
-
|
107
|
+
# Dispatch the given events to the list of waiting fibers. If the fiber was not waiting for the given events, it is reactivated by calling the given block.
|
108
|
+
def dispatch(events, &reactivate)
|
109
|
+
# We capture the tail here, because calling reactivate might modify it:
|
110
|
+
tail = self.tail
|
111
|
+
|
107
112
|
if fiber = self.fiber
|
108
|
-
|
109
|
-
|
110
|
-
|
113
|
+
if fiber.alive?
|
114
|
+
revents = events & self.events
|
115
|
+
if revents.zero?
|
116
|
+
reactivate.call(self)
|
117
|
+
else
|
118
|
+
self.fiber = nil
|
119
|
+
fiber.transfer(revents)
|
120
|
+
end
|
121
|
+
else
|
122
|
+
self.fiber = nil
|
123
|
+
end
|
111
124
|
end
|
112
|
-
|
113
|
-
|
125
|
+
|
126
|
+
tail&.dispatch(events, &reactivate)
|
114
127
|
end
|
115
128
|
|
116
129
|
def invalidate
|
@@ -147,13 +160,72 @@ module IO::Event
|
|
147
160
|
errno == EAGAIN or errno == EWOULDBLOCK
|
148
161
|
end
|
149
162
|
|
150
|
-
if Support.
|
163
|
+
if Support.fiber_scheduler_v3?
|
164
|
+
# Ruby 3.3+, full IO::Buffer support.
|
165
|
+
|
166
|
+
# @parameter length [Integer] The minimum number of bytes to read.
|
167
|
+
# @parameter offset [Integer] The offset into the buffer to read to.
|
151
168
|
def io_read(fiber, io, buffer, length, offset = 0)
|
152
169
|
total = 0
|
153
170
|
|
154
171
|
Selector.nonblock(io) do
|
155
172
|
while true
|
156
|
-
|
173
|
+
result = Fiber.blocking{buffer.read(io, 0, offset)}
|
174
|
+
|
175
|
+
if result < 0
|
176
|
+
if again?(result)
|
177
|
+
self.io_wait(fiber, io, IO::READABLE)
|
178
|
+
else
|
179
|
+
return result
|
180
|
+
end
|
181
|
+
elsif result == 0
|
182
|
+
break
|
183
|
+
else
|
184
|
+
total += result
|
185
|
+
break if total >= length
|
186
|
+
offset += result
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
return total
|
192
|
+
end
|
193
|
+
|
194
|
+
# @parameter length [Integer] The minimum number of bytes to write.
|
195
|
+
# @parameter offset [Integer] The offset into the buffer to write from.
|
196
|
+
def io_write(fiber, io, buffer, length, offset = 0)
|
197
|
+
total = 0
|
198
|
+
|
199
|
+
Selector.nonblock(io) do
|
200
|
+
while true
|
201
|
+
result = Fiber.blocking{buffer.write(io, 0, offset)}
|
202
|
+
|
203
|
+
if result < 0
|
204
|
+
if again?(result)
|
205
|
+
self.io_wait(fiber, io, IO::READABLE)
|
206
|
+
else
|
207
|
+
return result
|
208
|
+
end
|
209
|
+
elsif result == 0
|
210
|
+
break result
|
211
|
+
else
|
212
|
+
total += result
|
213
|
+
break if total >= length
|
214
|
+
offset += result
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
return total
|
220
|
+
end
|
221
|
+
elsif Support.fiber_scheduler_v2?
|
222
|
+
# Ruby 3.2, most IO::Buffer support, but slightly clunky read/write methods.
|
223
|
+
def io_read(fiber, io, buffer, length, offset = 0)
|
224
|
+
total = 0
|
225
|
+
|
226
|
+
Selector.nonblock(io) do
|
227
|
+
maximum_size = buffer.size - offset
|
228
|
+
while maximum_size > 0
|
157
229
|
result = Fiber.blocking{buffer.read(io, maximum_size, offset)}
|
158
230
|
|
159
231
|
if again?(result)
|
@@ -169,6 +241,8 @@ module IO::Event
|
|
169
241
|
offset += result
|
170
242
|
break if total >= length
|
171
243
|
end
|
244
|
+
|
245
|
+
maximum_size = buffer.size - offset
|
172
246
|
end
|
173
247
|
end
|
174
248
|
|
@@ -179,8 +253,8 @@ module IO::Event
|
|
179
253
|
total = 0
|
180
254
|
|
181
255
|
Selector.nonblock(io) do
|
182
|
-
|
183
|
-
|
256
|
+
maximum_size = buffer.size - offset
|
257
|
+
while maximum_size > 0
|
184
258
|
result = Fiber.blocking{buffer.write(io, maximum_size, offset)}
|
185
259
|
|
186
260
|
if again?(result)
|
@@ -196,19 +270,23 @@ module IO::Event
|
|
196
270
|
offset += result
|
197
271
|
break if total >= length
|
198
272
|
end
|
273
|
+
|
274
|
+
maximum_size = buffer.size - offset
|
199
275
|
end
|
200
276
|
end
|
201
277
|
|
202
278
|
return total
|
203
279
|
end
|
204
280
|
elsif Support.fiber_scheduler_v1?
|
281
|
+
# Ruby <= 3.1, limited IO::Buffer support.
|
205
282
|
def io_read(fiber, _io, buffer, length, offset = 0)
|
283
|
+
# We need to avoid any internal buffering, so we use a duplicated IO object:
|
206
284
|
io = IO.for_fd(_io.fileno, autoclose: false)
|
285
|
+
|
207
286
|
total = 0
|
208
287
|
|
209
|
-
|
210
|
-
|
211
|
-
|
288
|
+
maximum_size = buffer.size - offset
|
289
|
+
while maximum_size > 0
|
212
290
|
case result = blocking{io.read_nonblock(maximum_size, exception: false)}
|
213
291
|
when :wait_readable
|
214
292
|
if length > 0
|
@@ -233,6 +311,8 @@ module IO::Event
|
|
233
311
|
break if size >= length
|
234
312
|
length -= size
|
235
313
|
end
|
314
|
+
|
315
|
+
maximum_size = buffer.size - offset
|
236
316
|
end
|
237
317
|
|
238
318
|
return total
|
@@ -243,12 +323,13 @@ module IO::Event
|
|
243
323
|
end
|
244
324
|
|
245
325
|
def io_write(fiber, _io, buffer, length, offset = 0)
|
326
|
+
# We need to avoid any internal buffering, so we use a duplicated IO object:
|
246
327
|
io = IO.for_fd(_io.fileno, autoclose: false)
|
328
|
+
|
247
329
|
total = 0
|
248
330
|
|
249
|
-
|
250
|
-
|
251
|
-
|
331
|
+
maximum_size = buffer.size - offset
|
332
|
+
while maximum_size > 0
|
252
333
|
chunk = buffer.get_string(offset, maximum_size)
|
253
334
|
case result = blocking{io.write_nonblock(chunk, exception: false)}
|
254
335
|
when :wait_readable
|
@@ -269,6 +350,8 @@ module IO::Event
|
|
269
350
|
break if result >= length
|
270
351
|
length -= result
|
271
352
|
end
|
353
|
+
|
354
|
+
maximum_size = buffer.size - offset
|
272
355
|
end
|
273
356
|
|
274
357
|
return total
|
@@ -329,12 +412,26 @@ module IO::Event
|
|
329
412
|
end
|
330
413
|
end
|
331
414
|
|
332
|
-
@blocked = true
|
333
415
|
duration = 0 unless @ready.empty?
|
334
|
-
|
335
|
-
@blocked = false
|
416
|
+
error = nil
|
336
417
|
|
337
|
-
|
418
|
+
# We need to handle interrupts on blocking IO. Every other implementation uses EINTR, but that doesn't work with `::IO.select` as it will retry the call on EINTR.
|
419
|
+
Thread.handle_interrupt(::Exception => :on_blocking) do
|
420
|
+
@blocked = true
|
421
|
+
readable, writable, priority = ::IO.select(readable, writable, priority, duration)
|
422
|
+
rescue ::Exception => error
|
423
|
+
# Requeue below...
|
424
|
+
ensure
|
425
|
+
@blocked = false
|
426
|
+
end
|
427
|
+
|
428
|
+
if error
|
429
|
+
# Requeue the error into the pending exception queue:
|
430
|
+
Thread.current.raise(error)
|
431
|
+
return 0
|
432
|
+
end
|
433
|
+
|
434
|
+
ready = Hash.new(0).compare_by_identity
|
338
435
|
|
339
436
|
readable&.each do |io|
|
340
437
|
ready[io] |= IO::READABLE
|
@@ -349,7 +446,11 @@ module IO::Event
|
|
349
446
|
end
|
350
447
|
|
351
448
|
ready.each do |io, events|
|
352
|
-
@waiting.delete(io).
|
449
|
+
@waiting.delete(io).dispatch(events) do |waiter|
|
450
|
+
# Re-schedule the waiting IO:
|
451
|
+
waiter.tail = @waiting[io]
|
452
|
+
@waiting[io] = waiter
|
453
|
+
end
|
353
454
|
end
|
354
455
|
|
355
456
|
return ready.size
|
data/lib/io/event/selector.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Released under the MIT License.
|
4
|
-
# Copyright, 2021-
|
4
|
+
# Copyright, 2021-2023, by Samuel Williams.
|
5
5
|
|
6
6
|
require_relative 'selector/select'
|
7
7
|
require_relative 'debug/selector'
|
@@ -11,11 +11,7 @@ module IO::Event
|
|
11
11
|
module Selector
|
12
12
|
def self.default(env = ENV)
|
13
13
|
if name = env['IO_EVENT_SELECTOR']&.to_sym
|
14
|
-
|
15
|
-
return const_get(name)
|
16
|
-
else
|
17
|
-
warn "Could not find IO_EVENT_SELECTOR=#{name}!"
|
18
|
-
end
|
14
|
+
return const_get(name)
|
19
15
|
end
|
20
16
|
|
21
17
|
if self.const_defined?(:URing)
|
data/lib/io/event/support.rb
CHANGED
@@ -17,6 +17,17 @@ class IO
|
|
17
17
|
def self.fiber_scheduler_v2?
|
18
18
|
IO.const_defined?(:Buffer) and Fiber.respond_to?(:blocking) and IO::Buffer.instance_method(:read).arity == -1
|
19
19
|
end
|
20
|
+
|
21
|
+
def self.fiber_scheduler_v3?
|
22
|
+
if fiber_scheduler_v2?
|
23
|
+
begin
|
24
|
+
IO::Buffer.new.slice(0, 0).write(STDOUT)
|
25
|
+
return true
|
26
|
+
rescue
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
20
31
|
end
|
21
32
|
end
|
22
33
|
end
|
data/lib/io/event/version.rb
CHANGED
data/lib/io/event.rb
CHANGED
data/license.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# MIT License
|
2
2
|
|
3
|
-
Copyright, 2021-
|
3
|
+
Copyright, 2021-2023, by Samuel Williams.
|
4
4
|
Copyright, 2021, by Delton Ding.
|
5
5
|
Copyright, 2021, by Benoit Daloze.
|
6
6
|
Copyright, 2022, by Alex Matchneer.
|
7
7
|
Copyright, 2022, by Bruno Sutic.
|
8
|
+
Copyright, 2023, by Math Ieu.
|
8
9
|
|
9
10
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
10
11
|
of this software and associated documentation files (the "Software"), to deal
|
data/readme.md
CHANGED
@@ -16,8 +16,16 @@ Please see the [project documentation](https://socketry.github.io/io-event/).
|
|
16
16
|
|
17
17
|
We welcome contributions to this project.
|
18
18
|
|
19
|
-
1. Fork it
|
20
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
21
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
22
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
23
|
-
5. Create new Pull Request
|
19
|
+
1. Fork it.
|
20
|
+
2. Create your feature branch (`git checkout -b my-new-feature`).
|
21
|
+
3. Commit your changes (`git commit -am 'Add some feature'`).
|
22
|
+
4. Push to the branch (`git push origin my-new-feature`).
|
23
|
+
5. Create new Pull Request.
|
24
|
+
|
25
|
+
### Developer Certificate of Origin
|
26
|
+
|
27
|
+
This project uses the [Developer Certificate of Origin](https://developercertificate.org/). All contributors to this project must agree to this document to have their contributions accepted.
|
28
|
+
|
29
|
+
### Contributor Covenant
|
30
|
+
|
31
|
+
This project is governed by [Contributor Covenant](https://www.contributor-covenant.org/). All contributors and participants agree to abide by its terms.
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-event
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
+
- Math Ieu
|
8
9
|
- Bruno Sutic
|
10
|
+
- Alex Matchneer
|
9
11
|
- Benoit Daloze
|
10
12
|
- Delton Ding
|
11
|
-
- machty
|
12
13
|
autorequire:
|
13
14
|
bindir: bin
|
14
15
|
cert_chain:
|
@@ -41,64 +42,8 @@ cert_chain:
|
|
41
42
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
42
43
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
43
44
|
-----END CERTIFICATE-----
|
44
|
-
date: 2023-
|
45
|
-
dependencies:
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: bake
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
requirements:
|
50
|
-
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: '0'
|
53
|
-
type: :development
|
54
|
-
prerelease: false
|
55
|
-
version_requirements: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - ">="
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '0'
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: bundler
|
62
|
-
requirement: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - ">="
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '0'
|
67
|
-
type: :development
|
68
|
-
prerelease: false
|
69
|
-
version_requirements: !ruby/object:Gem::Requirement
|
70
|
-
requirements:
|
71
|
-
- - ">="
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
version: '0'
|
74
|
-
- !ruby/object:Gem::Dependency
|
75
|
-
name: covered
|
76
|
-
requirement: !ruby/object:Gem::Requirement
|
77
|
-
requirements:
|
78
|
-
- - ">="
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: '0'
|
81
|
-
type: :development
|
82
|
-
prerelease: false
|
83
|
-
version_requirements: !ruby/object:Gem::Requirement
|
84
|
-
requirements:
|
85
|
-
- - ">="
|
86
|
-
- !ruby/object:Gem::Version
|
87
|
-
version: '0'
|
88
|
-
- !ruby/object:Gem::Dependency
|
89
|
-
name: sus
|
90
|
-
requirement: !ruby/object:Gem::Requirement
|
91
|
-
requirements:
|
92
|
-
- - "~>"
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
version: '0.6'
|
95
|
-
type: :development
|
96
|
-
prerelease: false
|
97
|
-
version_requirements: !ruby/object:Gem::Requirement
|
98
|
-
requirements:
|
99
|
-
- - "~>"
|
100
|
-
- !ruby/object:Gem::Version
|
101
|
-
version: '0.6'
|
45
|
+
date: 2023-10-24 00:00:00.000000000 Z
|
46
|
+
dependencies: []
|
102
47
|
description:
|
103
48
|
email:
|
104
49
|
executables: []
|
@@ -112,10 +57,12 @@ files:
|
|
112
57
|
- ext/io/event/event.h
|
113
58
|
- ext/io/event/interrupt.c
|
114
59
|
- ext/io/event/interrupt.h
|
60
|
+
- ext/io/event/selector/array.h
|
115
61
|
- ext/io/event/selector/epoll.c
|
116
62
|
- ext/io/event/selector/epoll.h
|
117
63
|
- ext/io/event/selector/kqueue.c
|
118
64
|
- ext/io/event/selector/kqueue.h
|
65
|
+
- ext/io/event/selector/list.h
|
119
66
|
- ext/io/event/selector/pidfd.c
|
120
67
|
- ext/io/event/selector/selector.c
|
121
68
|
- ext/io/event/selector/selector.h
|
@@ -150,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
97
|
- !ruby/object:Gem::Version
|
151
98
|
version: '0'
|
152
99
|
requirements: []
|
153
|
-
rubygems_version: 3.4.
|
100
|
+
rubygems_version: 3.4.10
|
154
101
|
signing_key:
|
155
102
|
specification_version: 4
|
156
103
|
summary: An event loop.
|
metadata.gz.sig
CHANGED
Binary file
|