io-wait 0.2.3 → 0.3.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/ext/io/wait/wait.c +98 -69
  3. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 43e7f91045efd73e51af1a6e055afe646fc95d1b7c1a154453d915e6a213d223
4
- data.tar.gz: 4d542bfb7bde6053c4069f451d41f39e05b77d0ebab5514532f601466ca57bba
3
+ metadata.gz: 630936f8af6e2cf9265ebff0794cab1daf10048933460b71306486aecb92a85a
4
+ data.tar.gz: 153bc0301fdb8fce6f4983d45879364509bb6534a81775d98e5f61b5ffe1923e
5
5
  SHA512:
6
- metadata.gz: f78dc92e4500c196b69d87fb47f13f426f4a2d9b8532e69027d3c96a8dd93514d08c77adc421b8d3cac2e0aaf2f80d92327c98d95969a9816111b41c373fe10a
7
- data.tar.gz: 4b2b4af88c93ddc7d12d1060f6f638aab6fc75178a32fe9810478a5b95e27575cbe1054c1e46964b7ca1eec1269f47b64bf823a990472363cb97c75236b4a438
6
+ metadata.gz: 07e0a9997d9e8dd84368feb0fdcd681282d7c583aea8d03d90abf031d6474224aa7a6f61050de11a03750cc0e20ba5759ac4eca28aae07891a778ef82cef24c6
7
+ data.tar.gz: 7294e823b4536cded39faead19916b437e4a8a4d398e35917c81e84d4618d5f99bd414aa9f6989cfad4bfb8bf0721fb7934b083a72576a7e95a60d7fcf35e853
data/ext/io/wait/wait.c CHANGED
@@ -41,22 +41,17 @@
41
41
  #endif
42
42
 
43
43
  #ifndef HAVE_RB_IO_WAIT
44
- static VALUE io_ready_p _((VALUE io));
45
- static VALUE io_wait_readable _((int argc, VALUE *argv, VALUE io));
46
- static VALUE io_wait_writable _((int argc, VALUE *argv, VALUE io));
47
- void Init_wait _((void));
48
-
49
44
  static struct timeval *
50
45
  get_timeout(int argc, VALUE *argv, struct timeval *timerec)
51
46
  {
52
47
  VALUE timeout = Qnil;
53
48
  rb_check_arity(argc, 0, 1);
54
49
  if (!argc || NIL_P(timeout = argv[0])) {
55
- return NULL;
50
+ return NULL;
56
51
  }
57
52
  else {
58
- *timerec = rb_time_interval(timeout);
59
- return timerec;
53
+ *timerec = rb_time_interval(timeout);
54
+ return timerec;
60
55
  }
61
56
  }
62
57
 
@@ -65,7 +60,7 @@ wait_for_single_fd(rb_io_t *fptr, int events, struct timeval *tv)
65
60
  {
66
61
  int i = rb_wait_for_single_fd(fptr->fd, events, tv);
67
62
  if (i < 0)
68
- rb_sys_fail(0);
63
+ rb_sys_fail(0);
69
64
  rb_io_check_closed(fptr);
70
65
  return (i & events);
71
66
  }
@@ -100,21 +95,24 @@ io_nread(VALUE io)
100
95
 
101
96
  #ifdef HAVE_RB_IO_WAIT
102
97
  static VALUE
103
- io_wait_event(VALUE io, int event, VALUE timeout)
98
+ io_wait_event(VALUE io, int event, VALUE timeout, int return_io)
104
99
  {
105
100
  VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
106
101
 
107
102
  if (!RB_TEST(result)) {
108
- return Qnil;
103
+ return Qnil;
109
104
  }
110
105
 
111
106
  int mask = RB_NUM2INT(result);
112
107
 
113
108
  if (mask & event) {
114
- return io;
109
+ if (return_io)
110
+ return io;
111
+ else
112
+ return result;
115
113
  }
116
114
  else {
117
- return Qfalse;
115
+ return Qfalse;
118
116
  }
119
117
  }
120
118
  #endif
@@ -142,15 +140,15 @@ io_ready_p(VALUE io)
142
140
  if (rb_io_read_pending(fptr)) return Qtrue;
143
141
 
144
142
  #ifndef HAVE_RB_IO_WAIT
145
- if (wait_for_single_fd(fptr, RB_WAITFD_IN, &tv))
146
- return Qtrue;
143
+ return wait_for_single_fd(fptr, RB_WAITFD_IN, &tv) ? Qtrue : Qfalse;
147
144
  #else
148
- if (RTEST(io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0))))
149
- return Qtrue;
145
+ return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0), 1);
150
146
  #endif
151
- return Qfalse;
152
147
  }
153
148
 
149
+ /* Ruby 3.2+ can define these methods. This macro indicates that case. */
150
+ #ifndef RUBY_IO_WAIT_METHODS
151
+
154
152
  /*
155
153
  * call-seq:
156
154
  * io.wait_readable -> truthy or falsy
@@ -182,14 +180,14 @@ io_wait_readable(int argc, VALUE *argv, VALUE io)
182
180
 
183
181
  #ifndef HAVE_RB_IO_WAIT
184
182
  if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
185
- return io;
183
+ return io;
186
184
  }
187
185
  return Qnil;
188
186
  #else
189
187
  rb_check_arity(argc, 0, 1);
190
188
  VALUE timeout = (argc == 1 ? argv[0] : Qnil);
191
189
 
192
- return io_wait_event(io, RUBY_IO_READABLE, timeout);
190
+ return io_wait_event(io, RUBY_IO_READABLE, timeout, 1);
193
191
  #endif
194
192
  }
195
193
 
@@ -218,14 +216,14 @@ io_wait_writable(int argc, VALUE *argv, VALUE io)
218
216
  #ifndef HAVE_RB_IO_WAIT
219
217
  tv = get_timeout(argc, argv, &timerec);
220
218
  if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
221
- return io;
219
+ return io;
222
220
  }
223
221
  return Qnil;
224
222
  #else
225
223
  rb_check_arity(argc, 0, 1);
226
224
  VALUE timeout = (argc == 1 ? argv[0] : Qnil);
227
225
 
228
- return io_wait_event(io, RUBY_IO_WRITABLE, timeout);
226
+ return io_wait_event(io, RUBY_IO_WRITABLE, timeout, 1);
229
227
  #endif
230
228
  }
231
229
 
@@ -236,7 +234,8 @@ io_wait_writable(int argc, VALUE *argv, VALUE io)
236
234
  * io.wait_priority(timeout) -> truthy or falsy
237
235
  *
238
236
  * Waits until IO is priority and returns a truthy value or a falsy
239
- * value when times out.
237
+ * value when times out. Priority data is sent and received using
238
+ * the Socket::MSG_OOB flag and is typically limited to streams.
240
239
  *
241
240
  * You must require 'io/wait' to use this method.
242
241
  */
@@ -253,7 +252,7 @@ io_wait_priority(int argc, VALUE *argv, VALUE io)
253
252
  rb_check_arity(argc, 0, 1);
254
253
  VALUE timeout = argc == 1 ? argv[0] : Qnil;
255
254
 
256
- return io_wait_event(io, RUBY_IO_PRIORITY, timeout);
255
+ return io_wait_event(io, RUBY_IO_PRIORITY, timeout, 1);
257
256
  }
258
257
  #endif
259
258
 
@@ -261,40 +260,52 @@ static int
261
260
  wait_mode_sym(VALUE mode)
262
261
  {
263
262
  if (mode == ID2SYM(rb_intern("r"))) {
264
- return RB_WAITFD_IN;
263
+ return RB_WAITFD_IN;
265
264
  }
266
265
  if (mode == ID2SYM(rb_intern("read"))) {
267
- return RB_WAITFD_IN;
266
+ return RB_WAITFD_IN;
268
267
  }
269
268
  if (mode == ID2SYM(rb_intern("readable"))) {
270
- return RB_WAITFD_IN;
269
+ return RB_WAITFD_IN;
271
270
  }
272
271
  if (mode == ID2SYM(rb_intern("w"))) {
273
- return RB_WAITFD_OUT;
272
+ return RB_WAITFD_OUT;
274
273
  }
275
274
  if (mode == ID2SYM(rb_intern("write"))) {
276
- return RB_WAITFD_OUT;
275
+ return RB_WAITFD_OUT;
277
276
  }
278
277
  if (mode == ID2SYM(rb_intern("writable"))) {
279
- return RB_WAITFD_OUT;
278
+ return RB_WAITFD_OUT;
280
279
  }
281
280
  if (mode == ID2SYM(rb_intern("rw"))) {
282
- return RB_WAITFD_IN|RB_WAITFD_OUT;
281
+ return RB_WAITFD_IN|RB_WAITFD_OUT;
283
282
  }
284
283
  if (mode == ID2SYM(rb_intern("read_write"))) {
285
- return RB_WAITFD_IN|RB_WAITFD_OUT;
284
+ return RB_WAITFD_IN|RB_WAITFD_OUT;
286
285
  }
287
286
  if (mode == ID2SYM(rb_intern("readable_writable"))) {
288
- return RB_WAITFD_IN|RB_WAITFD_OUT;
287
+ return RB_WAITFD_IN|RB_WAITFD_OUT;
289
288
  }
290
289
  rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
291
290
  return 0;
292
291
  }
293
292
 
293
+ #ifdef HAVE_RB_IO_WAIT
294
+ static inline rb_io_event_t
295
+ io_event_from_value(VALUE value)
296
+ {
297
+ int events = RB_NUM2INT(value);
298
+
299
+ if (events <= 0) rb_raise(rb_eArgError, "Events must be positive integer!");
300
+
301
+ return events;
302
+ }
303
+ #endif
304
+
294
305
  /*
295
306
  * call-seq:
296
- * io.wait(events, timeout) -> truthy or falsy
297
- * io.wait(timeout = nil, mode = :read) -> truthy or falsy.
307
+ * io.wait(events, timeout) -> event mask, false or nil
308
+ * io.wait(timeout = nil, mode = :read) -> self, true, or false
298
309
  *
299
310
  * Waits until the IO becomes ready for the specified events and returns the
300
311
  * subset of events that become ready, or a falsy value when times out.
@@ -322,61 +333,77 @@ io_wait(int argc, VALUE *argv, VALUE io)
322
333
 
323
334
  GetOpenFile(io, fptr);
324
335
  for (i = 0; i < argc; ++i) {
325
- if (SYMBOL_P(argv[i])) {
326
- event |= wait_mode_sym(argv[i]);
327
- }
328
- else {
329
- *(tv = &timerec) = rb_time_interval(argv[i]);
330
- }
336
+ if (SYMBOL_P(argv[i])) {
337
+ event |= wait_mode_sym(argv[i]);
338
+ }
339
+ else {
340
+ *(tv = &timerec) = rb_time_interval(argv[i]);
341
+ }
331
342
  }
332
343
  /* rb_time_interval() and might_mode() might convert the argument */
333
344
  rb_io_check_closed(fptr);
334
345
  if (!event) event = RB_WAITFD_IN;
335
346
  if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
336
- return Qtrue;
347
+ return Qtrue;
337
348
  if (wait_for_single_fd(fptr, event, tv))
338
- return io;
349
+ return io;
339
350
  return Qnil;
340
351
  #else
341
352
  VALUE timeout = Qundef;
342
353
  rb_io_event_t events = 0;
354
+ int i, return_io = 0;
343
355
 
356
+ /* The documented signature for this method is actually incorrect.
357
+ * A single timeout is allowed in any position, and multiple symbols can be given.
358
+ * Whether this is intentional or not, I don't know, and as such I consider this to
359
+ * be a legacy/slow path. */
344
360
  if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
345
- for (int i = 0; i < argc; i += 1) {
346
- if (RB_SYMBOL_P(argv[i])) {
347
- events |= wait_mode_sym(argv[i]);
348
- }
349
- else if (timeout == Qundef) {
350
- rb_time_interval(timeout = argv[i]);
351
- }
352
- else {
353
- rb_raise(rb_eArgError, "timeout given more than once");
354
- }
355
- }
356
- if (timeout == Qundef) timeout = Qnil;
361
+ /* We'd prefer to return the actual mask, but this form would return the io itself: */
362
+ return_io = 1;
363
+
364
+ /* Slow/messy path: */
365
+ for (i = 0; i < argc; i += 1) {
366
+ if (RB_SYMBOL_P(argv[i])) {
367
+ events |= wait_mode_sym(argv[i]);
368
+ }
369
+ else if (timeout == Qundef) {
370
+ rb_time_interval(timeout = argv[i]);
371
+ }
372
+ else {
373
+ rb_raise(rb_eArgError, "timeout given more than once");
374
+ }
375
+ }
376
+
377
+ if (timeout == Qundef) timeout = Qnil;
378
+
379
+ if (events == 0) {
380
+ events = RUBY_IO_READABLE;
381
+ }
357
382
  }
358
- else /* argc == 2 */ {
359
- events = RB_NUM2UINT(argv[0]);
360
- timeout = argv[1];
361
- }
362
-
363
- if (events == 0) {
364
- events = RUBY_IO_READABLE;
383
+ else /* argc == 2 and neither are symbols */ {
384
+ /* This is the fast path: */
385
+ events = io_event_from_value(argv[0]);
386
+ timeout = argv[1];
365
387
  }
366
388
 
367
389
  if (events & RUBY_IO_READABLE) {
368
- rb_io_t *fptr = NULL;
369
- RB_IO_POINTER(io, fptr);
370
-
371
- if (rb_io_read_pending(fptr)) {
372
- return Qtrue;
373
- }
390
+ rb_io_t *fptr = NULL;
391
+ RB_IO_POINTER(io, fptr);
392
+
393
+ if (rb_io_read_pending(fptr)) {
394
+ /* This was the original behaviour: */
395
+ if (return_io) return Qtrue;
396
+ /* New behaviour always returns an event mask: */
397
+ else return RB_INT2NUM(RUBY_IO_READABLE);
398
+ }
374
399
  }
375
400
 
376
- return io_wait_event(io, events, timeout);
401
+ return io_wait_event(io, events, timeout, return_io);
377
402
  #endif
378
403
  }
379
404
 
405
+ #endif /* RUBY_IO_WAIT_METHODS */
406
+
380
407
  /*
381
408
  * IO wait methods
382
409
  */
@@ -391,6 +418,7 @@ Init_wait(void)
391
418
  rb_define_method(rb_cIO, "nread", io_nread, 0);
392
419
  rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
393
420
 
421
+ #ifndef RUBY_IO_WAIT_METHODS
394
422
  rb_define_method(rb_cIO, "wait", io_wait, -1);
395
423
 
396
424
  rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
@@ -398,4 +426,5 @@ Init_wait(void)
398
426
  #ifdef HAVE_RB_IO_WAIT
399
427
  rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
400
428
  #endif
429
+ #endif
401
430
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-wait
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nobu Nakada
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2022-05-09 00:00:00.000000000 Z
12
+ date: 2022-12-16 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Waits until IO is readable or writable without blocking.
15
15
  email: