io-event 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021, by Samuel Williams.
4
+ # Copyright, 2021-2023, by Samuel Williams.
5
5
 
6
6
  module IO::Event
7
7
  # A thread safe synchronisation primative.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2022, by Samuel Williams.
4
+ # Copyright, 2022-2023, by Samuel Williams.
5
5
 
6
6
  require 'io/nonblock'
7
7
 
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2022, by Samuel Williams.
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
- def transfer(events)
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
- self.fiber = nil
109
-
110
- fiber.transfer(events & self.events) if fiber.alive?
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
- self.tail&.transfer(events)
125
+
126
+ tail&.dispatch(events, &reactivate)
114
127
  end
115
128
 
116
129
  def invalidate
@@ -152,8 +165,8 @@ module IO::Event
152
165
  total = 0
153
166
 
154
167
  Selector.nonblock(io) do
155
- while true
156
- maximum_size = buffer.size - offset
168
+ maximum_size = buffer.size - offset
169
+ while maximum_size > 0
157
170
  result = Fiber.blocking{buffer.read(io, maximum_size, offset)}
158
171
 
159
172
  if again?(result)
@@ -169,6 +182,8 @@ module IO::Event
169
182
  offset += result
170
183
  break if total >= length
171
184
  end
185
+
186
+ maximum_size = buffer.size - offset
172
187
  end
173
188
  end
174
189
 
@@ -179,8 +194,8 @@ module IO::Event
179
194
  total = 0
180
195
 
181
196
  Selector.nonblock(io) do
182
- while true
183
- maximum_size = buffer.size - offset
197
+ maximum_size = buffer.size - offset
198
+ while maximum_size > 0
184
199
  result = Fiber.blocking{buffer.write(io, maximum_size, offset)}
185
200
 
186
201
  if again?(result)
@@ -196,6 +211,8 @@ module IO::Event
196
211
  offset += result
197
212
  break if total >= length
198
213
  end
214
+
215
+ maximum_size = buffer.size - offset
199
216
  end
200
217
  end
201
218
 
@@ -206,9 +223,8 @@ module IO::Event
206
223
  io = IO.for_fd(_io.fileno, autoclose: false)
207
224
  total = 0
208
225
 
209
- while true
210
- maximum_size = buffer.size - offset
211
-
226
+ maximum_size = buffer.size - offset
227
+ while maximum_size > 0
212
228
  case result = blocking{io.read_nonblock(maximum_size, exception: false)}
213
229
  when :wait_readable
214
230
  if length > 0
@@ -233,6 +249,8 @@ module IO::Event
233
249
  break if size >= length
234
250
  length -= size
235
251
  end
252
+
253
+ maximum_size = buffer.size - offset
236
254
  end
237
255
 
238
256
  return total
@@ -246,9 +264,8 @@ module IO::Event
246
264
  io = IO.for_fd(_io.fileno, autoclose: false)
247
265
  total = 0
248
266
 
249
- while true
250
- maximum_size = buffer.size - offset
251
-
267
+ maximum_size = buffer.size - offset
268
+ while maximum_size > 0
252
269
  chunk = buffer.get_string(offset, maximum_size)
253
270
  case result = blocking{io.write_nonblock(chunk, exception: false)}
254
271
  when :wait_readable
@@ -269,6 +286,8 @@ module IO::Event
269
286
  break if result >= length
270
287
  length -= result
271
288
  end
289
+
290
+ maximum_size = buffer.size - offset
272
291
  end
273
292
 
274
293
  return total
@@ -329,12 +348,26 @@ module IO::Event
329
348
  end
330
349
  end
331
350
 
332
- @blocked = true
333
351
  duration = 0 unless @ready.empty?
334
- readable, writable, priority = ::IO.select(readable, writable, priority, duration)
335
- @blocked = false
352
+ error = nil
336
353
 
337
- ready = Hash.new(0)
354
+ # 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.
355
+ Thread.handle_interrupt(::Exception => :on_blocking) do
356
+ @blocked = true
357
+ readable, writable, priority = ::IO.select(readable, writable, priority, duration)
358
+ rescue ::Exception => error
359
+ # Requeue below...
360
+ ensure
361
+ @blocked = false
362
+ end
363
+
364
+ if error
365
+ # Requeue the error into the pending exception queue:
366
+ Thread.current.raise(error)
367
+ return 0
368
+ end
369
+
370
+ ready = Hash.new(0).compare_by_identity
338
371
 
339
372
  readable&.each do |io|
340
373
  ready[io] |= IO::READABLE
@@ -349,7 +382,11 @@ module IO::Event
349
382
  end
350
383
 
351
384
  ready.each do |io, events|
352
- @waiting.delete(io).transfer(events)
385
+ @waiting.delete(io).dispatch(events) do |waiter|
386
+ # Re-schedule the waiting IO:
387
+ waiter.tail = @waiting[io]
388
+ @waiting[io] = waiter
389
+ end
353
390
  end
354
391
 
355
392
  return ready.size
@@ -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
- if const_defined?(name)
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)
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021-2022, by Samuel Williams.
4
+ # Copyright, 2021-2023, by Samuel Williams.
5
5
 
6
6
  class IO
7
7
  module Event
8
- VERSION = "1.2.2"
8
+ VERSION = "1.3.0"
9
9
  end
10
10
  end
data/lib/io/event.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2021, by Samuel Williams.
4
+ # Copyright, 2021-2023, by Samuel Williams.
5
5
 
6
6
  require_relative 'event/version'
7
7
  require_relative 'event/selector'
data/license.md CHANGED
@@ -1,10 +1,11 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2021-2022, by Samuel Williams.
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.2.2
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  - Bruno Sutic
9
+ - Math Ieu
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-05-14 00:00:00.000000000 Z
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-08-23 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.7
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