io-event 1.1.0 → 1.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 529ab26d211811182c1ac8b7b292431533c830eddcfd8781185c9ea4ff623c93
4
- data.tar.gz: cef3ea8d930d3f3f92e0c814c0f89405a78e3da1d4ebd6c0d1e73bd32f6839a6
3
+ metadata.gz: dd5603ed5cc26eaa2f9d4261d7462ec1d435c169c36c2770af80c0d27fe2c4e2
4
+ data.tar.gz: 1ce4d895bfc5618e97bf84702e2591aa9b3aa947678e5eae8b1b42c0c4119607
5
5
  SHA512:
6
- metadata.gz: 77cd0725f41f507e391f54dae4071c9b2721a1fc4ce1c4dbcbf7b4dac8a7453c0e4867679b9f9c615d82ce06af2b3f77745b0d1526f0c6bb02cf06a60c84f763
7
- data.tar.gz: 6d9a389303af3b13540ff2761d8e35762e3af975c7e1defddf8765088129f43dc4584029947bafd2a6eb35c60f8206b0dc184d425c52163d1652392e62bb9333
6
+ metadata.gz: c5924e3108f8c731a55d36f5329519870931aaa16e14fab81ca7b56418afb77cc6bab395c10751b628ce2668ef5c570141af6237cc07c7a62bf8fc8a4b53c71a
7
+ data.tar.gz: a5e8281833ac2f7476ca298fc0446ad4479dd0f08cb7764c5f0940fd235446b903e03909acc669869b2847eab50e92c1ef80e6c77acef62b35525d39a48a5351
checksums.yaml.gz.sig CHANGED
Binary file
data/ext/extconf.rb CHANGED
@@ -57,7 +57,7 @@ $srcs << "io/event/interrupt.c"
57
57
 
58
58
  have_func("rb_io_descriptor")
59
59
  have_func("&rb_process_status_wait")
60
- have_func('rb_fiber_current')
60
+ have_func("rb_fiber_current")
61
61
  have_func("&rb_fiber_raise")
62
62
 
63
63
  have_header('ruby/io/buffer.h')
@@ -385,7 +385,7 @@ VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
385
385
  return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
386
386
  }
387
387
 
388
- #ifdef RUBY_FIBER_SCHEDULER_VERSION
388
+ #ifdef HAVE_RUBY_IO_BUFFER_H
389
389
 
390
390
  struct io_read_arguments {
391
391
  VALUE self;
@@ -715,9 +715,11 @@ void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
715
715
  rb_define_method(IO_Event_Selector_EPoll, "close", IO_Event_Selector_EPoll_close, 0);
716
716
 
717
717
  rb_define_method(IO_Event_Selector_EPoll, "io_wait", IO_Event_Selector_EPoll_io_wait, 3);
718
-
718
+
719
+ #ifdef HAVE_RUBY_IO_BUFFER_H
719
720
  rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read_compatible, -1);
720
721
  rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write_compatible, -1);
722
+ #endif
721
723
 
722
724
  // Once compatibility isn't a concern, we can do this:
723
725
  // rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read, 5);
@@ -380,7 +380,7 @@ VALUE IO_Event_Selector_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE
380
380
  return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
381
381
  }
382
382
 
383
- #ifdef RUBY_FIBER_SCHEDULER_VERSION
383
+ #ifdef HAVE_RUBY_IO_BUFFER_H
384
384
 
385
385
  struct io_read_arguments {
386
386
  VALUE self;
@@ -764,9 +764,11 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
764
764
  rb_define_method(IO_Event_Selector_KQueue, "close", IO_Event_Selector_KQueue_close, 0);
765
765
 
766
766
  rb_define_method(IO_Event_Selector_KQueue, "io_wait", IO_Event_Selector_KQueue_io_wait, 3);
767
-
767
+
768
+ #ifdef HAVE_RUBY_IO_BUFFER_H
768
769
  rb_define_method(IO_Event_Selector_KQueue, "io_read", IO_Event_Selector_KQueue_io_read_compatible, -1);
769
770
  rb_define_method(IO_Event_Selector_KQueue, "io_write", IO_Event_Selector_KQueue_io_write_compatible, -1);
771
+ #endif
770
772
 
771
773
  rb_define_method(IO_Event_Selector_KQueue, "process_wait", IO_Event_Selector_KQueue_process_wait, 3);
772
774
  }
@@ -21,15 +21,14 @@
21
21
  #include "selector.h"
22
22
  #include <fcntl.h>
23
23
 
24
- #ifndef HAVE_RB_PROCESS_STATUS_WAIT
25
- // Pull in WNOHANG.
26
- #include <sys/wait.h>
27
- #endif
28
-
29
24
  static const int DEBUG = 0;
30
25
 
31
26
  static ID id_transfer, id_alive_p;
32
27
 
28
+ #ifndef HAVE_RB_PROCESS_STATUS_WAIT
29
+ static VALUE process_wnohang;
30
+ #endif
31
+
33
32
  VALUE IO_Event_Selector_fiber_transfer(VALUE fiber, int argc, VALUE *argv) {
34
33
  // TODO Consider introducing something like `rb_fiber_scheduler_transfer(...)`.
35
34
  #ifdef HAVE__RB_FIBER_TRANSFER
@@ -79,26 +78,65 @@ static VALUE rb_Process_Status = Qnil;
79
78
 
80
79
  VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid)
81
80
  {
82
- return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), INT2NUM(WNOHANG));
81
+ return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), process_wnohang);
83
82
  }
84
83
  #endif
85
84
 
86
85
  int IO_Event_Selector_nonblock_set(int file_descriptor)
87
86
  {
87
+ #ifdef _WIN32
88
+ u_long nonblock = 1;
89
+ int result = ioctlsocket(file_descriptor, FIONBIO, &nonblock);
90
+ // Windows does not provide any way to know this, so we always restore it back to unset:
91
+ return 0;
92
+ #else
93
+ // Get the current mode:
88
94
  int flags = fcntl(file_descriptor, F_GETFL, 0);
89
95
 
96
+ // Set the non-blocking flag if it isn't already:
90
97
  if (!(flags & O_NONBLOCK)) {
91
98
  fcntl(file_descriptor, F_SETFL, flags | O_NONBLOCK);
92
99
  }
93
100
 
94
101
  return flags;
102
+ #endif
95
103
  }
96
104
 
97
105
  void IO_Event_Selector_nonblock_restore(int file_descriptor, int flags)
98
106
  {
107
+ #ifdef _WIN32
108
+ // Yolo...
109
+ u_long nonblock = flags;
110
+ int result = ioctlsocket(file_descriptor, FIONBIO, &nonblock);
111
+ #else
112
+ // The flags didn't have O_NONBLOCK set, so it would have been set, so we need to restore it:
99
113
  if (!(flags & O_NONBLOCK)) {
100
- fcntl(file_descriptor, F_SETFL, flags & ~flags);
114
+ fcntl(file_descriptor, F_SETFL, flags);
101
115
  }
116
+ #endif
117
+ }
118
+
119
+ struct IO_Event_Selector_nonblock_arguments {
120
+ int file_descriptor;
121
+ int flags;
122
+ };
123
+
124
+ static VALUE IO_Event_Selector_nonblock_ensure(VALUE _arguments) {
125
+ struct IO_Event_Selector_nonblock_arguments *arguments = (struct IO_Event_Selector_nonblock_arguments *)_arguments;
126
+
127
+ IO_Event_Selector_nonblock_restore(arguments->file_descriptor, arguments->flags);
128
+
129
+ return Qnil;
130
+ }
131
+
132
+ static VALUE IO_Event_Selector_nonblock(VALUE class, VALUE io)
133
+ {
134
+ struct IO_Event_Selector_nonblock_arguments arguments = {
135
+ .file_descriptor = IO_Event_Selector_io_descriptor(io),
136
+ .flags = IO_Event_Selector_nonblock_set(arguments.file_descriptor)
137
+ };
138
+
139
+ return rb_ensure(rb_yield, io, IO_Event_Selector_nonblock_ensure, (VALUE)&arguments);
102
140
  }
103
141
 
104
142
  void Init_IO_Event_Selector(VALUE IO_Event_Selector) {
@@ -119,9 +157,12 @@ void Init_IO_Event_Selector(VALUE IO_Event_Selector) {
119
157
 
120
158
  #ifndef HAVE_RB_PROCESS_STATUS_WAIT
121
159
  id_wait = rb_intern("wait");
160
+ process_wnohang = rb_const_get(rb_mProcess, rb_intern("WNOHANG"));
122
161
  rb_Process_Status = rb_const_get_at(rb_mProcess, rb_intern("Status"));
123
162
  rb_gc_register_mark_object(rb_Process_Status);
124
163
  #endif
164
+
165
+ rb_define_singleton_method(IO_Event_Selector, "nonblock", IO_Event_Selector_nonblock, 1);
125
166
  }
126
167
 
127
168
  struct wait_and_transfer_arguments {
@@ -326,6 +326,7 @@ VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
326
326
  if (DEBUG) fprintf(stderr, "io_wait_rescue:io_uring_prep_poll_remove(%p)\n", (void*)arguments->fiber);
327
327
 
328
328
  io_uring_prep_poll_remove(sqe, (uintptr_t)arguments->fiber);
329
+ io_uring_sqe_set_data(sqe, NULL);
329
330
  io_uring_submit_now(data);
330
331
 
331
332
  rb_exc_raise(exception);
@@ -376,7 +377,7 @@ VALUE IO_Event_Selector_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
376
377
  return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
377
378
  }
378
379
 
379
- #ifdef RUBY_FIBER_SCHEDULER_VERSION
380
+ #ifdef HAVE_RUBY_IO_BUFFER_H
380
381
 
381
382
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)
382
383
  static inline off_t io_seekable(int descriptor) {
@@ -707,6 +708,8 @@ VALUE IO_Event_Selector_URing_wakeup(VALUE self) {
707
708
  }
708
709
 
709
710
  io_uring_prep_nop(sqe);
711
+ // If you don't set this line, the SQE will eventually be recycled and have valid user data which can cause odd behaviour:
712
+ io_uring_sqe_set_data(sqe, NULL);
710
713
  io_uring_submit(&data->ring);
711
714
 
712
715
  return Qtrue;
@@ -737,9 +740,11 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
737
740
  rb_define_method(IO_Event_Selector_URing, "close", IO_Event_Selector_URing_close, 0);
738
741
 
739
742
  rb_define_method(IO_Event_Selector_URing, "io_wait", IO_Event_Selector_URing_io_wait, 3);
740
-
743
+
744
+ #ifdef HAVE_RUBY_IO_BUFFER_H
741
745
  rb_define_method(IO_Event_Selector_URing, "io_read", IO_Event_Selector_URing_io_read_compatible, -1);
742
746
  rb_define_method(IO_Event_Selector_URing, "io_write", IO_Event_Selector_URing_io_write_compatible, -1);
747
+ #endif
743
748
 
744
749
  rb_define_method(IO_Event_Selector_URing, "io_close", IO_Event_Selector_URing_io_close, 1);
745
750
 
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2022, by Samuel Williams.
5
+
6
+ require 'io/nonblock'
7
+
8
+ module IO::Event
9
+ module Selector
10
+ def self.nonblock(io, &block)
11
+ io.nonblock(&block)
12
+ end
13
+ end
14
+ end
@@ -6,8 +6,6 @@
6
6
  require_relative '../interrupt'
7
7
  require_relative '../support'
8
8
 
9
- require 'io/nonblock'
10
-
11
9
  module IO::Event
12
10
  module Selector
13
11
  class Select
@@ -136,29 +134,35 @@ module IO::Event
136
134
  waiter&.invalidate
137
135
  end
138
136
 
137
+ EAGAIN = -Errno::EAGAIN::Errno
138
+ EWOULDBLOCK = -Errno::EWOULDBLOCK::Errno
139
+
140
+ def again?(errno)
141
+ errno == EAGAIN or errno == EWOULDBLOCK
142
+ end
143
+
139
144
  if Support.fiber_scheduler_v2?
140
- EAGAIN = Errno::EAGAIN::Errno
141
-
142
145
  def io_read(fiber, io, buffer, length, offset = 0)
143
146
  total = 0
144
- io.nonblock = true
145
147
 
146
- while true
147
- maximum_size = buffer.size - offset
148
- result = Fiber.blocking{buffer.read(io, maximum_size, offset)}
149
-
150
- if result == -EAGAIN
151
- if length > 0
152
- self.io_wait(fiber, io, IO::READABLE)
153
- else
148
+ Selector.nonblock(io) do
149
+ while true
150
+ maximum_size = buffer.size - offset
151
+ result = Fiber.blocking{buffer.read(io, maximum_size, offset)}
152
+
153
+ if again?(result)
154
+ if length > 0
155
+ self.io_wait(fiber, io, IO::READABLE)
156
+ else
157
+ return result
158
+ end
159
+ elsif result < 0
154
160
  return result
161
+ else
162
+ total += result
163
+ offset += result
164
+ break if total >= length
155
165
  end
156
- elsif result < 0
157
- return result
158
- else
159
- total += result
160
- offset += result
161
- break if total >= length
162
166
  end
163
167
  end
164
168
 
@@ -167,34 +171,34 @@ module IO::Event
167
171
 
168
172
  def io_write(fiber, io, buffer, length, offset = 0)
169
173
  total = 0
170
- io.nonblock = true
171
174
 
172
- while true
173
- maximum_size = buffer.size - offset
174
- result = Fiber.blocking{buffer.write(io, maximum_size, offset)}
175
-
176
- if result == -EAGAIN
177
- if length > 0
178
- self.io_wait(fiber, io, IO::READABLE)
179
- else
175
+ Selector.nonblock(io) do
176
+ while true
177
+ maximum_size = buffer.size - offset
178
+ result = Fiber.blocking{buffer.write(io, maximum_size, offset)}
179
+
180
+ if again?(result)
181
+ if length > 0
182
+ self.io_wait(fiber, io, IO::READABLE)
183
+ else
184
+ return result
185
+ end
186
+ elsif result < 0
180
187
  return result
188
+ else
189
+ total += result
190
+ offset += result
191
+ break if total >= length
181
192
  end
182
- elsif result < 0
183
- return result
184
- else
185
- total += result
186
- offset += result
187
- break if total >= length
188
193
  end
189
194
  end
190
195
 
191
- return offset
196
+ return total
192
197
  end
193
198
  elsif Support.fiber_scheduler_v1?
194
- EAGAIN = Errno::EAGAIN::Errno
195
-
196
199
  def io_read(fiber, _io, buffer, length, offset = 0)
197
200
  io = IO.for_fd(_io.fileno, autoclose: false)
201
+ total = 0
198
202
 
199
203
  while true
200
204
  maximum_size = buffer.size - offset
@@ -204,13 +208,13 @@ module IO::Event
204
208
  if length > 0
205
209
  self.io_wait(fiber, io, IO::READABLE)
206
210
  else
207
- return -EAGAIN
211
+ return EWOULDBLOCK
208
212
  end
209
213
  when :wait_writable
210
214
  if length > 0
211
215
  self.io_wait(fiber, io, IO::WRITABLE)
212
216
  else
213
- return -EAGAIN
217
+ return EWOULDBLOCK
214
218
  end
215
219
  when nil
216
220
  break
@@ -218,17 +222,19 @@ module IO::Event
218
222
  buffer.set_string(result, offset)
219
223
 
220
224
  size = result.bytesize
225
+ total += size
221
226
  offset += size
222
227
  break if size >= length
223
228
  length -= size
224
229
  end
225
230
  end
226
231
 
227
- return offset
232
+ return total
228
233
  end
229
234
 
230
235
  def io_write(fiber, _io, buffer, length, offset = 0)
231
236
  io = IO.for_fd(_io.fileno, autoclose: false)
237
+ total = 0
232
238
 
233
239
  while true
234
240
  maximum_size = buffer.size - offset
@@ -239,22 +245,23 @@ module IO::Event
239
245
  if length > 0
240
246
  self.io_wait(fiber, io, IO::READABLE)
241
247
  else
242
- return -EAGAIN
248
+ return EWOULDBLOCK
243
249
  end
244
250
  when :wait_writable
245
251
  if length > 0
246
252
  self.io_wait(fiber, io, IO::WRITABLE)
247
253
  else
248
- return -EAGAIN
254
+ return EWOULDBLOCK
249
255
  end
250
256
  else
257
+ total += result
251
258
  offset += result
252
259
  break if result >= length
253
260
  length -= result
254
261
  end
255
262
  end
256
263
 
257
- return offset
264
+ return total
258
265
  end
259
266
 
260
267
  def blocking(&block)
@@ -5,6 +5,6 @@
5
5
 
6
6
  class IO
7
7
  module Event
8
- VERSION = "1.1.0"
8
+ VERSION = "1.1.2"
9
9
  end
10
10
  end
data/lib/io/event.rb CHANGED
@@ -10,5 +10,5 @@ begin
10
10
  require 'IO_Event'
11
11
  rescue LoadError => error
12
12
  warn "Could not load native event selector: #{error}"
13
- # Ignore.
13
+ require_relative 'event/selector/nonblock'
14
14
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-event
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -41,7 +41,7 @@ cert_chain:
41
41
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
42
42
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
43
43
  -----END CERTIFICATE-----
44
- date: 2022-10-13 00:00:00.000000000 Z
44
+ date: 2022-10-19 00:00:00.000000000 Z
45
45
  dependencies:
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: bake
@@ -125,6 +125,7 @@ files:
125
125
  - lib/io/event/debug/selector.rb
126
126
  - lib/io/event/interrupt.rb
127
127
  - lib/io/event/selector.rb
128
+ - lib/io/event/selector/nonblock.rb
128
129
  - lib/io/event/selector/select.rb
129
130
  - lib/io/event/support.rb
130
131
  - lib/io/event/version.rb
metadata.gz.sig CHANGED
Binary file