io-event 1.0.9 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9f83ab57c44b58bfd257acaa093dddf3f2b2b9ee444b64abacd2a872a741d429
4
- data.tar.gz: 85e665f83983f2796001f84a9199a7f285c7e641920d647762785b6cd5e7253e
3
+ metadata.gz: 336b8a299fe9de0466ef4453f9cde52f1820ec94c10b30033b9d79f30e2ee7a5
4
+ data.tar.gz: 6c32fd8b43caeecbf400e19f1cc33b7c8fd3fd70d9db3e08e622fb596ba185b3
5
5
  SHA512:
6
- metadata.gz: f73a3744ed94bec2a42c0ef405d7bf14c1f58d3f2ac04edc28c4fc97de21a6cb7f8e6c142ef8477f93a044b17a6d5c27fc372b8b8f7545228e9e0885ef0f4fc6
7
- data.tar.gz: 555b411452da5fc65a425d37fae32af486bdcf3c4e9d5721c48a927847420eb1d5bdf0c668fdd13d25ac7551d7b127d7d050b540d580d5db689b2ff04d8130f0
6
+ metadata.gz: ed7d828a65a678598559cb55738dd0832cd6633d5ea15d743962a0b44210ae5e68c4704015f75cc2294f64b30eeff57332a8f5993a6ad91ffffe7204edbf7ca6
7
+ data.tar.gz: 22343d4aed5285e1a0c2435d7f3f93fa9ff086c67dce8cf27616ad599df81622eb936ba7fcf8a7acf48d505f98834aca8a963f50895bcf0d28596fd26687e36f
checksums.yaml.gz.sig CHANGED
Binary file
data/design.md ADDED
@@ -0,0 +1,63 @@
1
+ ## Dual `_select` without GVL:
2
+
3
+ Always release GVL:
4
+
5
+ ```
6
+ Warming up --------------------------------------
7
+ KQueue 55.896k i/100ms
8
+ Select 17.023k i/100ms
9
+ Calculating -------------------------------------
10
+ KQueue 532.515k (± 8.0%) i/s - 2.683M in 5.071193s
11
+ Select 177.956k (± 3.4%) i/s - 902.219k in 5.075817s
12
+
13
+ Comparison:
14
+ KQueue: 532515.3 i/s
15
+ Select: 177956.1 i/s - 2.99x (± 0.00) slower
16
+ ```
17
+
18
+ Only release GVL with non-zero timeout, with selector.elect(1) (so always hitting slow path):
19
+
20
+ ```
21
+ Warming up --------------------------------------
22
+ KQueue 39.628k i/100ms
23
+ Select 18.330k i/100ms
24
+ Calculating -------------------------------------
25
+ KQueue 381.868k (± 6.5%) i/s - 1.902M in 5.004267s
26
+ Select 171.623k (± 3.0%) i/s - 861.510k in 5.024308s
27
+
28
+ Comparison:
29
+ KQueue: 381867.8 i/s
30
+ Select: 171622.5 i/s - 2.23x (± 0.00) slower
31
+ ```
32
+
33
+ Only release GVL with non-zero timeout, with selector.select(0) so always hitting fast path:
34
+
35
+ ```
36
+ Warming up --------------------------------------
37
+ KQueue 56.240k i/100ms
38
+ Select 17.888k i/100ms
39
+ Calculating -------------------------------------
40
+ KQueue 543.042k (± 7.8%) i/s - 2.700M in 5.003790s
41
+ Select 171.866k (± 4.3%) i/s - 858.624k in 5.005785s
42
+
43
+ Comparison:
44
+ KQueue: 543041.5 i/s
45
+ Select: 171866.2 i/s - 3.16x (± 0.00) slower
46
+ ```
47
+
48
+ Only release GVL when no events are ready and non-zero timeout, with selector.select(1):
49
+
50
+ ```
51
+ Warming up --------------------------------------
52
+ KQueue 53.401k i/100ms
53
+ Select 16.691k i/100ms
54
+ Calculating -------------------------------------
55
+ KQueue 524.564k (± 6.1%) i/s - 2.617M in 5.006996s
56
+ Select 179.329k (± 2.4%) i/s - 901.314k in 5.029136s
57
+
58
+ Comparison:
59
+ KQueue: 524564.0 i/s
60
+ Select: 179329.1 i/s - 2.93x (± 0.00) slower
61
+ ```
62
+
63
+ So this approach seems to be a net win of about 1.5x throughput.
data/ext/extconf.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Released under the MIT License.
5
+ # Copyright, 2021, by Samuel Williams.
2
6
 
3
7
  # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
4
8
  #
@@ -53,7 +57,7 @@ $srcs << "io/event/interrupt.c"
53
57
 
54
58
  have_func("rb_io_descriptor")
55
59
  have_func("&rb_process_status_wait")
56
- have_func('rb_fiber_current')
60
+ have_func("rb_fiber_current")
57
61
  have_func("&rb_fiber_raise")
58
62
 
59
63
  have_header('ruby/io/buffer.h')
@@ -398,6 +398,7 @@ struct io_read_arguments {
398
398
 
399
399
  VALUE buffer;
400
400
  size_t length;
401
+ size_t offset;
401
402
  };
402
403
 
403
404
  static
@@ -408,8 +409,8 @@ VALUE io_read_loop(VALUE _arguments) {
408
409
  size_t size;
409
410
  rb_io_buffer_get_bytes_for_writing(arguments->buffer, &base, &size);
410
411
 
411
- size_t offset = 0;
412
412
  size_t length = arguments->length;
413
+ size_t offset = arguments->offset;
413
414
 
414
415
  while (true) {
415
416
  size_t maximum_size = size - offset;
@@ -440,9 +441,10 @@ VALUE io_read_ensure(VALUE _arguments) {
440
441
  return Qnil;
441
442
  }
442
443
 
443
- VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
444
+ VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
444
445
  int descriptor = IO_Event_Selector_io_descriptor(io);
445
446
 
447
+ size_t offset = NUM2SIZET(_offset);
446
448
  size_t length = NUM2SIZET(_length);
447
449
 
448
450
  struct io_read_arguments io_read_arguments = {
@@ -454,11 +456,25 @@ VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
454
456
  .descriptor = descriptor,
455
457
  .buffer = buffer,
456
458
  .length = length,
459
+ .offset = offset,
457
460
  };
458
461
 
459
462
  return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
460
463
  }
461
464
 
465
+ VALUE IO_Event_Selector_EPoll_io_read_compatible(int argc, VALUE *argv, VALUE self)
466
+ {
467
+ rb_check_arity(argc, 4, 5);
468
+
469
+ VALUE _offset = SIZET2NUM(0);
470
+
471
+ if (argc == 5) {
472
+ _offset = argv[4];
473
+ }
474
+
475
+ return IO_Event_Selector_EPoll_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
476
+ }
477
+
462
478
  struct io_write_arguments {
463
479
  VALUE self;
464
480
  VALUE fiber;
@@ -470,6 +486,7 @@ struct io_write_arguments {
470
486
 
471
487
  VALUE buffer;
472
488
  size_t length;
489
+ size_t offset;
473
490
  };
474
491
 
475
492
  static
@@ -480,8 +497,8 @@ VALUE io_write_loop(VALUE _arguments) {
480
497
  size_t size;
481
498
  rb_io_buffer_get_bytes_for_reading(arguments->buffer, &base, &size);
482
499
 
483
- size_t offset = 0;
484
500
  size_t length = arguments->length;
501
+ size_t offset = arguments->offset;
485
502
 
486
503
  if (length > size) {
487
504
  rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
@@ -516,10 +533,11 @@ VALUE io_write_ensure(VALUE _arguments) {
516
533
  return Qnil;
517
534
  };
518
535
 
519
- VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
536
+ VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
520
537
  int descriptor = IO_Event_Selector_io_descriptor(io);
521
538
 
522
539
  size_t length = NUM2SIZET(_length);
540
+ size_t offset = NUM2SIZET(_offset);
523
541
 
524
542
  struct io_write_arguments io_write_arguments = {
525
543
  .self = self,
@@ -530,11 +548,25 @@ VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
530
548
  .descriptor = descriptor,
531
549
  .buffer = buffer,
532
550
  .length = length,
551
+ .offset = offset,
533
552
  };
534
553
 
535
554
  return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
536
555
  }
537
556
 
557
+ VALUE IO_Event_Selector_EPoll_io_write_compatible(int argc, VALUE *argv, VALUE self)
558
+ {
559
+ rb_check_arity(argc, 4, 5);
560
+
561
+ VALUE _offset = SIZET2NUM(0);
562
+
563
+ if (argc == 5) {
564
+ _offset = argv[4];
565
+ }
566
+
567
+ return IO_Event_Selector_EPoll_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
568
+ }
569
+
538
570
  #endif
539
571
 
540
572
  static
@@ -685,9 +717,13 @@ void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
685
717
  rb_define_method(IO_Event_Selector_EPoll, "io_wait", IO_Event_Selector_EPoll_io_wait, 3);
686
718
 
687
719
  #ifdef HAVE_RUBY_IO_BUFFER_H
688
- rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read, 4);
689
- rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write, 4);
720
+ rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read_compatible, -1);
721
+ rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write_compatible, -1);
690
722
  #endif
691
723
 
724
+ // Once compatibility isn't a concern, we can do this:
725
+ // rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read, 5);
726
+ // rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write, 5);
727
+
692
728
  rb_define_method(IO_Event_Selector_EPoll, "process_wait", IO_Event_Selector_EPoll_process_wait, 3);
693
729
  }
@@ -393,6 +393,7 @@ struct io_read_arguments {
393
393
 
394
394
  VALUE buffer;
395
395
  size_t length;
396
+ size_t offset;
396
397
  };
397
398
 
398
399
  static
@@ -403,8 +404,8 @@ VALUE io_read_loop(VALUE _arguments) {
403
404
  size_t size;
404
405
  rb_io_buffer_get_bytes_for_writing(arguments->buffer, &base, &size);
405
406
 
406
- size_t offset = 0;
407
407
  size_t length = arguments->length;
408
+ size_t offset = arguments->offset;
408
409
 
409
410
  if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu)\n", arguments->descriptor, length);
410
411
 
@@ -442,13 +443,14 @@ VALUE io_read_ensure(VALUE _arguments) {
442
443
  return Qnil;
443
444
  }
444
445
 
445
- VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
446
+ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
446
447
  struct IO_Event_Selector_KQueue *data = NULL;
447
448
  TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, data);
448
449
 
449
450
  int descriptor = IO_Event_Selector_io_descriptor(io);
450
451
 
451
452
  size_t length = NUM2SIZET(_length);
453
+ size_t offset = NUM2SIZET(_offset);
452
454
 
453
455
  struct io_read_arguments io_read_arguments = {
454
456
  .self = self,
@@ -459,11 +461,25 @@ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
459
461
  .descriptor = descriptor,
460
462
  .buffer = buffer,
461
463
  .length = length,
464
+ .offset = offset,
462
465
  };
463
466
 
464
467
  return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
465
468
  }
466
469
 
470
+ static VALUE IO_Event_Selector_KQueue_io_read_compatible(int argc, VALUE *argv, VALUE self)
471
+ {
472
+ rb_check_arity(argc, 4, 5);
473
+
474
+ VALUE _offset = SIZET2NUM(0);
475
+
476
+ if (argc == 5) {
477
+ _offset = argv[4];
478
+ }
479
+
480
+ return IO_Event_Selector_KQueue_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
481
+ }
482
+
467
483
  struct io_write_arguments {
468
484
  VALUE self;
469
485
  VALUE fiber;
@@ -475,6 +491,7 @@ struct io_write_arguments {
475
491
 
476
492
  VALUE buffer;
477
493
  size_t length;
494
+ size_t offset;
478
495
  };
479
496
 
480
497
  static
@@ -485,8 +502,8 @@ VALUE io_write_loop(VALUE _arguments) {
485
502
  size_t size;
486
503
  rb_io_buffer_get_bytes_for_reading(arguments->buffer, &base, &size);
487
504
 
488
- size_t offset = 0;
489
505
  size_t length = arguments->length;
506
+ size_t offset = arguments->offset;
490
507
 
491
508
  if (length > size) {
492
509
  rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
@@ -528,13 +545,14 @@ VALUE io_write_ensure(VALUE _arguments) {
528
545
  return Qnil;
529
546
  };
530
547
 
531
- VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
548
+ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
532
549
  struct IO_Event_Selector_KQueue *data = NULL;
533
550
  TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, data);
534
551
 
535
552
  int descriptor = IO_Event_Selector_io_descriptor(io);
536
553
 
537
554
  size_t length = NUM2SIZET(_length);
555
+ size_t offset = NUM2SIZET(_offset);
538
556
 
539
557
  struct io_write_arguments io_write_arguments = {
540
558
  .self = self,
@@ -545,11 +563,25 @@ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
545
563
  .descriptor = descriptor,
546
564
  .buffer = buffer,
547
565
  .length = length,
566
+ .offset = offset,
548
567
  };
549
568
 
550
569
  return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
551
570
  }
552
571
 
572
+ static VALUE IO_Event_Selector_KQueue_io_write_compatible(int argc, VALUE *argv, VALUE self)
573
+ {
574
+ rb_check_arity(argc, 4, 5);
575
+
576
+ VALUE _offset = SIZET2NUM(0);
577
+
578
+ if (argc == 5) {
579
+ _offset = argv[4];
580
+ }
581
+
582
+ return IO_Event_Selector_KQueue_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
583
+ }
584
+
553
585
  #endif
554
586
 
555
587
  static
@@ -734,8 +766,8 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
734
766
  rb_define_method(IO_Event_Selector_KQueue, "io_wait", IO_Event_Selector_KQueue_io_wait, 3);
735
767
 
736
768
  #ifdef HAVE_RUBY_IO_BUFFER_H
737
- rb_define_method(IO_Event_Selector_KQueue, "io_read", IO_Event_Selector_KQueue_io_read, 4);
738
- rb_define_method(IO_Event_Selector_KQueue, "io_write", IO_Event_Selector_KQueue_io_write, 4);
769
+ rb_define_method(IO_Event_Selector_KQueue, "io_read", IO_Event_Selector_KQueue_io_read_compatible, -1);
770
+ rb_define_method(IO_Event_Selector_KQueue, "io_write", IO_Event_Selector_KQueue_io_write_compatible, -1);
739
771
  #endif
740
772
 
741
773
  rb_define_method(IO_Event_Selector_KQueue, "process_wait", IO_Event_Selector_KQueue_process_wait, 3);
@@ -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 {
@@ -29,6 +29,10 @@
29
29
  #include <ruby/fiber/scheduler.h>
30
30
  #endif
31
31
 
32
+ #ifndef RUBY_FIBER_SCHEDULER_VERSION
33
+ #define RUBY_FIBER_SCHEDULER_VERSION 1
34
+ #endif
35
+
32
36
  #include <time.h>
33
37
 
34
38
  enum IO_Event {
@@ -23,6 +23,7 @@
23
23
 
24
24
  #include <liburing.h>
25
25
  #include <poll.h>
26
+ #include <stdint.h>
26
27
  #include <time.h>
27
28
 
28
29
  #include "pidfd.c"
@@ -324,7 +325,7 @@ VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
324
325
 
325
326
  if (DEBUG) fprintf(stderr, "io_wait_rescue:io_uring_prep_poll_remove(%p)\n", (void*)arguments->fiber);
326
327
 
327
- io_uring_prep_poll_remove(sqe, (void*)arguments->fiber);
328
+ io_uring_prep_poll_remove(sqe, (uintptr_t)arguments->fiber);
328
329
  io_uring_submit_now(data);
329
330
 
330
331
  rb_exc_raise(exception);
@@ -408,7 +409,7 @@ static int io_read(struct IO_Event_Selector_URing *data, VALUE fiber, int descri
408
409
  return RB_NUM2INT(result);
409
410
  }
410
411
 
411
- VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
412
+ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
412
413
  struct IO_Event_Selector_URing *data = NULL;
413
414
  TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
414
415
 
@@ -418,8 +419,8 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
418
419
  size_t size;
419
420
  rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
420
421
 
421
- size_t offset = 0;
422
422
  size_t length = NUM2SIZET(_length);
423
+ size_t offset = NUM2SIZET(_offset);
423
424
 
424
425
  while (true) {
425
426
  size_t maximum_size = size - offset;
@@ -443,6 +444,19 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
443
444
  return rb_fiber_scheduler_io_result(offset, 0);
444
445
  }
445
446
 
447
+ static VALUE IO_Event_Selector_URing_io_read_compatible(int argc, VALUE *argv, VALUE self)
448
+ {
449
+ rb_check_arity(argc, 4, 5);
450
+
451
+ VALUE _offset = SIZET2NUM(0);
452
+
453
+ if (argc == 5) {
454
+ _offset = argv[4];
455
+ }
456
+
457
+ return IO_Event_Selector_URing_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
458
+ }
459
+
446
460
  static
447
461
  int io_write(struct IO_Event_Selector_URing *data, VALUE fiber, int descriptor, char *buffer, size_t length) {
448
462
  struct io_uring_sqe *sqe = io_get_sqe(data);
@@ -459,7 +473,7 @@ int io_write(struct IO_Event_Selector_URing *data, VALUE fiber, int descriptor,
459
473
  return result;
460
474
  }
461
475
 
462
- VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
476
+ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
463
477
  struct IO_Event_Selector_URing *data = NULL;
464
478
  TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
465
479
 
@@ -469,8 +483,8 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
469
483
  size_t size;
470
484
  rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
471
485
 
472
- size_t offset = 0;
473
486
  size_t length = NUM2SIZET(_length);
487
+ size_t offset = NUM2SIZET(_offset);
474
488
 
475
489
  if (length > size) {
476
490
  rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
@@ -496,6 +510,19 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
496
510
  return rb_fiber_scheduler_io_result(offset, 0);
497
511
  }
498
512
 
513
+ static VALUE IO_Event_Selector_URing_io_write_compatible(int argc, VALUE *argv, VALUE self)
514
+ {
515
+ rb_check_arity(argc, 4, 5);
516
+
517
+ VALUE _offset = SIZET2NUM(0);
518
+
519
+ if (argc == 5) {
520
+ _offset = argv[4];
521
+ }
522
+
523
+ return IO_Event_Selector_URing_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
524
+ }
525
+
499
526
  #endif
500
527
 
501
528
  static const int ASYNC_CLOSE = 1;
@@ -712,8 +739,8 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
712
739
  rb_define_method(IO_Event_Selector_URing, "io_wait", IO_Event_Selector_URing_io_wait, 3);
713
740
 
714
741
  #ifdef HAVE_RUBY_IO_BUFFER_H
715
- rb_define_method(IO_Event_Selector_URing, "io_read", IO_Event_Selector_URing_io_read, 4);
716
- rb_define_method(IO_Event_Selector_URing, "io_write", IO_Event_Selector_URing_io_write, 4);
742
+ rb_define_method(IO_Event_Selector_URing, "io_read", IO_Event_Selector_URing_io_read_compatible, -1);
743
+ rb_define_method(IO_Event_Selector_URing, "io_write", IO_Event_Selector_URing_io_write_compatible, -1);
717
744
  #endif
718
745
 
719
746
  rb_define_method(IO_Event_Selector_URing, "io_close", IO_Event_Selector_URing_io_close, 1);
@@ -1,22 +1,9 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2021-2022, by Samuel Williams.
5
+
6
+ require_relative '../support'
20
7
 
21
8
  module IO::Event
22
9
  module Debug
@@ -80,14 +67,16 @@ module IO::Event
80
67
  @selector.io_wait(fiber, io, events)
81
68
  end
82
69
 
83
- if IO.const_defined?(:Buffer)
84
- def io_read(fiber, io, buffer, length)
85
- @selector.io_read(fiber, io, buffer, length)
86
- end
87
-
88
- def io_write(fiber, io, buffer, length)
89
- @selector.io_write(fiber, io, buffer, length)
90
- end
70
+ def io_read(...)
71
+ @selector.io_read(...)
72
+ end
73
+
74
+ def io_write(...)
75
+ @selector.io_write(...)
76
+ end
77
+
78
+ def respond_to?(name, include_private = false)
79
+ @selector.respond_to?(name, include_private)
91
80
  end
92
81
 
93
82
  def select(duration = nil)
@@ -1,22 +1,7 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2021, by Samuel Williams.
20
5
 
21
6
  module IO::Event
22
7
  # A thread safe synchronisation primative.
@@ -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
@@ -1,24 +1,10 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2021-2022, by Samuel Williams.
20
5
 
21
6
  require_relative '../interrupt'
7
+ require_relative '../support'
22
8
 
23
9
  module IO::Event
24
10
  module Selector
@@ -36,7 +22,7 @@ module IO::Event
36
22
 
37
23
  attr :loop
38
24
 
39
- # If the event loop is currently blocked,
25
+ # If the event loop is currently sleeping, wake it up.
40
26
  def wakeup
41
27
  if @blocked
42
28
  @interrupt.signal
@@ -148,11 +134,71 @@ module IO::Event
148
134
  waiter&.invalidate
149
135
  end
150
136
 
151
- if IO.const_defined?(:Buffer)
152
- EAGAIN = Errno::EAGAIN::Errno
137
+ EAGAIN = -Errno::EAGAIN::Errno
138
+ EWOULDBLOCK = -Errno::EWOULDBLOCK::Errno
139
+
140
+ def again?(errno)
141
+ errno == EAGAIN or errno == EWOULDBLOCK
142
+ end
143
+
144
+ if Support.fiber_scheduler_v2?
145
+ def io_read(fiber, io, buffer, length, offset = 0)
146
+ total = 0
147
+
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
160
+ return result
161
+ else
162
+ total += result
163
+ offset += result
164
+ break if total >= length
165
+ end
166
+ end
167
+ end
168
+
169
+ return total
170
+ end
153
171
 
154
- def io_read(fiber, io, buffer, length)
155
- offset = 0
172
+ def io_write(fiber, io, buffer, length, offset = 0)
173
+ total = 0
174
+
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
187
+ return result
188
+ else
189
+ total += result
190
+ offset += result
191
+ break if total >= length
192
+ end
193
+ end
194
+ end
195
+
196
+ return total
197
+ end
198
+ elsif Support.fiber_scheduler_v1?
199
+ def io_read(fiber, _io, buffer, length, offset = 0)
200
+ io = IO.for_fd(_io.fileno, autoclose: false)
201
+ total = 0
156
202
 
157
203
  while true
158
204
  maximum_size = buffer.size - offset
@@ -162,13 +208,13 @@ module IO::Event
162
208
  if length > 0
163
209
  self.io_wait(fiber, io, IO::READABLE)
164
210
  else
165
- return -EAGAIN
211
+ return EWOULDBLOCK
166
212
  end
167
213
  when :wait_writable
168
214
  if length > 0
169
215
  self.io_wait(fiber, io, IO::WRITABLE)
170
216
  else
171
- return -EAGAIN
217
+ return EWOULDBLOCK
172
218
  end
173
219
  when nil
174
220
  break
@@ -176,17 +222,19 @@ module IO::Event
176
222
  buffer.set_string(result, offset)
177
223
 
178
224
  size = result.bytesize
225
+ total += size
179
226
  offset += size
180
227
  break if size >= length
181
228
  length -= size
182
229
  end
183
230
  end
184
231
 
185
- return offset
232
+ return total
186
233
  end
187
234
 
188
- def io_write(fiber, io, buffer, length)
189
- offset = 0
235
+ def io_write(fiber, _io, buffer, length, offset = 0)
236
+ io = IO.for_fd(_io.fileno, autoclose: false)
237
+ total = 0
190
238
 
191
239
  while true
192
240
  maximum_size = buffer.size - offset
@@ -197,41 +245,35 @@ module IO::Event
197
245
  if length > 0
198
246
  self.io_wait(fiber, io, IO::READABLE)
199
247
  else
200
- return -EAGAIN
248
+ return EWOULDBLOCK
201
249
  end
202
250
  when :wait_writable
203
251
  if length > 0
204
252
  self.io_wait(fiber, io, IO::WRITABLE)
205
253
  else
206
- return -EAGAIN
254
+ return EWOULDBLOCK
207
255
  end
208
256
  else
257
+ total += result
209
258
  offset += result
210
259
  break if result >= length
211
260
  length -= result
212
261
  end
213
262
  end
214
263
 
215
- return offset
264
+ return total
265
+ end
266
+
267
+ def blocking(&block)
268
+ fiber = Fiber.new(blocking: true, &block)
269
+ return fiber.resume(fiber)
216
270
  end
217
271
  end
218
272
 
219
273
  def process_wait(fiber, pid, flags)
220
- r, w = IO.pipe
221
-
222
- thread = Thread.new do
274
+ Thread.new do
223
275
  Process::Status.wait(pid, flags)
224
- ensure
225
- w.close
226
- end
227
-
228
- self.io_wait(fiber, r, IO::READABLE)
229
-
230
- return thread.value
231
- ensure
232
- r.close
233
- w.close
234
- thread&.kill
276
+ end.value
235
277
  end
236
278
 
237
279
  private def pop_ready
@@ -255,6 +297,7 @@ module IO::Event
255
297
 
256
298
  readable = Array.new
257
299
  writable = Array.new
300
+ priority = Array.new
258
301
 
259
302
  @waiting.each do |io, waiter|
260
303
  waiter.each do |fiber, events|
@@ -265,12 +308,16 @@ module IO::Event
265
308
  if (events & IO::WRITABLE) > 0
266
309
  writable << io
267
310
  end
311
+
312
+ if (events & IO::PRIORITY) > 0
313
+ priority << io
314
+ end
268
315
  end
269
316
  end
270
317
 
271
318
  @blocked = true
272
319
  duration = 0 unless @ready.empty?
273
- readable, writable, _ = ::IO.select(readable, writable, nil, duration)
320
+ readable, writable, priority = ::IO.select(readable, writable, priority, duration)
274
321
  @blocked = false
275
322
 
276
323
  ready = Hash.new(0)
@@ -283,16 +330,16 @@ module IO::Event
283
330
  ready[io] |= IO::WRITABLE
284
331
  end
285
332
 
333
+ priority&.each do |io|
334
+ ready[io] |= IO::PRIORITY
335
+ end
336
+
286
337
  ready.each do |io, events|
287
338
  @waiting.delete(io).transfer(events)
288
339
  end
289
340
 
290
341
  return ready.size
291
342
  end
292
-
293
- private def blocking(&block)
294
- Fiber.new(blocking: true, &block).resume
295
- end
296
343
  end
297
344
  end
298
345
  end
@@ -1,25 +1,11 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2021-2022, by Samuel Williams.
20
5
 
21
6
  require_relative 'selector/select'
22
7
  require_relative 'debug/selector'
8
+ require_relative 'support'
23
9
 
24
10
  module IO::Event
25
11
  module Selector
@@ -32,12 +18,14 @@ module IO::Event
32
18
  end
33
19
  end
34
20
 
35
- if self.const_defined?(:EPoll)
36
- return EPoll
21
+ if self.const_defined?(:URing)
22
+ URing
23
+ elsif self.const_defined?(:EPoll)
24
+ EPoll
37
25
  elsif self.const_defined?(:KQueue)
38
- return KQueue
26
+ KQueue
39
27
  else
40
- return Select
28
+ Select
41
29
  end
42
30
  end
43
31
 
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2022, by Samuel Williams.
5
+
6
+ class IO
7
+ module Event
8
+ module Support
9
+ def self.buffer?
10
+ IO.const_defined?(:Buffer)
11
+ end
12
+
13
+ def self.fiber_scheduler_v1?
14
+ IO.const_defined?(:Buffer) and !Fiber.respond_to?(:blocking)
15
+ end
16
+
17
+ def self.fiber_scheduler_v2?
18
+ IO.const_defined?(:Buffer) and Fiber.respond_to?(:blocking) and IO::Buffer.instance_method(:read).arity == -1
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,23 +1,10 @@
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.
1
+ # frozen_string_literal: true
20
2
 
21
- module IO::Event
22
- VERSION = "1.0.9"
3
+ # Released under the MIT License.
4
+ # Copyright, 2021-2022, by Samuel Williams.
5
+
6
+ class IO
7
+ module Event
8
+ VERSION = "1.1.1"
9
+ end
23
10
  end
data/lib/io/event.rb CHANGED
@@ -1,22 +1,7 @@
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.
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2021, by Samuel Williams.
20
5
 
21
6
  require_relative 'event/version'
22
7
  require_relative 'event/selector'
@@ -25,5 +10,5 @@ begin
25
10
  require 'IO_Event'
26
11
  rescue LoadError => error
27
12
  warn "Could not load native event selector: #{error}"
28
- # Ignore.
13
+ require_relative 'event/selector/nonblock'
29
14
  end
data/license.md ADDED
@@ -0,0 +1,25 @@
1
+ # MIT License
2
+
3
+ Copyright, 2021-2022, by Samuel Williams.
4
+ Copyright, 2021, by Delton Ding.
5
+ Copyright, 2021, by Benoit Daloze.
6
+ Copyright, 2022, by Alex Matchneer.
7
+ Copyright, 2022, by Bruno Sutic.
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in all
17
+ copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
+ SOFTWARE.
data/readme.md ADDED
@@ -0,0 +1,23 @@
1
+ # ![Event](logo.svg)
2
+
3
+ Provides low level cross-platform primitives for constructing event loops, with support for `select`, `kqueue`, `epoll` and `io_uring`.
4
+
5
+ [![Development Status](https://github.com/socketry/io-event/workflows/Test/badge.svg)](https://github.com/socketry/io-event/actions?workflow=Test)
6
+
7
+ ## Motivation
8
+
9
+ The initial proof-of-concept [Async](https://github.com/socketry/async) was built on [NIO4r](https://github.com/socketry/nio4r). It was perfectly acceptable and well tested in production, however being built on `libev` was a little bit limiting. I wanted to directly built my fiber scheduler into the fabric of the event loop, which is what this gem exposes - it is specifically implemented to support building event loops beneath the fiber scheduler interface, providing an efficient C implementation of all the core operations.
10
+
11
+ ## Usage
12
+
13
+ Please see the [project documentation](https://socketry.github.io/io-event/).
14
+
15
+ ## Contributing
16
+
17
+ We welcome contributions to this project.
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
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.0.9
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -14,33 +14,34 @@ bindir: bin
14
14
  cert_chain:
15
15
  - |
16
16
  -----BEGIN CERTIFICATE-----
17
- MIIEhDCCAuygAwIBAgIBATANBgkqhkiG9w0BAQsFADA3MTUwMwYDVQQDDCxzYW11
18
- ZWwud2lsbGlhbXMvREM9b3Jpb250cmFuc2Zlci9EQz1jby9EQz1uejAeFw0yMTA4
19
- MTYwNjMzNDRaFw0yMjA4MTYwNjMzNDRaMDcxNTAzBgNVBAMMLHNhbXVlbC53aWxs
20
- aWFtcy9EQz1vcmlvbnRyYW5zZmVyL0RDPWNvL0RDPW56MIIBojANBgkqhkiG9w0B
21
- AQEFAAOCAY8AMIIBigKCAYEAyXLSS/cw+fXJ5e7hi+U/TeChPWeYdwJojDsFY1xr
22
- xvtqbTTL8gbLHz5LW3QD2nfwCv3qTlw0qI3Ie7a9VMJMbSvgVEGEfQirqIgJXWMj
23
- eNMDgKsMJtC7u/43abRKx7TCURW3iWyR19NRngsJJmaR51yGGGm2Kfsr+JtKKLtL
24
- L188Wm3f13KAx7QJU8qyuBnj1/gWem076hzdA7xi1DbrZrch9GCRz62xymJlrJHn
25
- 9iZEZ7AxrS7vokhMlzSr/XMUihx/8aFKtk+tMLClqxZSmBWIErWdicCGTULXCBNb
26
- E/mljo4zEVKhlTWpJklMIhr55ZRrSarKFuW7en0+tpJrfsYiAmXMJNi4XAYJH7uL
27
- rgJuJwSaa/dMz+VmUoo7VKtSfCoOI+6v5/z0sK3oT6sG6ZwyI47DBq2XqNC6tnAj
28
- w+XmCywiTQrFzMMAvcA7rPI4F0nU1rZId51rOvvfxaONp+wgTi4P8owZLw0/j0m4
29
- 8C20DYi6EYx4AHDXiLpElWh3AgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8E
30
- BAMCBLAwHQYDVR0OBBYEFB6ZaeWKxQjGTI+pmz7cKRmMIywwMC4GA1UdEQQnMCWB
31
- I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWB
32
- I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEB
33
- CwUAA4IBgQBVoM+pu3dpdUhZM1w051iw5GfiqclAr1Psypf16Tiod/ho//4oAu6T
34
- 9fj3DPX/acWV9P/FScvqo4Qgv6g4VWO5ZU7z2JmPoTXZtYMunRAmQPFL/gSUc6aK
35
- vszMHIyhtyzRc6DnfW2AiVOjMBjaYv8xXZc9bduniRVPrLR4J7ozmGLh4o4uJp7w
36
- x9KCFaR8Lvn/r0oJWJOqb/DMAYI83YeN2Dlt3jpwrsmsONrtC5S3gOUle5afSGos
37
- bYt5ocnEpKSomR9ZtnCGljds/aeO1Xgpn2r9HHcjwnH346iNrnHmMlC7BtHUFPDg
38
- Ts92S47PTOXzwPBDsrFiq3VLbRjHSwf8rpqybQBH9MfzxGGxTaETQYOd6b4e4Ag6
39
- y92abGna0bmIEb4+Tx9rQ10Uijh1POzvr/VTH4bbIPy9FbKrRsIQ24qDbNJRtOpE
40
- RAOsIl+HOBTb252nx1kIRN5hqQx272AJCbCjKx8egcUQKffFVVCI0nye09v5CK+a
41
- HiLJ8VOFx6w=
17
+ MIIE2DCCA0CgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMRgwFgYDVQQDDA9zYW11
18
+ ZWwud2lsbGlhbXMxHTAbBgoJkiaJk/IsZAEZFg1vcmlvbnRyYW5zZmVyMRIwEAYK
19
+ CZImiZPyLGQBGRYCY28xEjAQBgoJkiaJk/IsZAEZFgJuejAeFw0yMjA4MDYwNDUz
20
+ MjRaFw0zMjA4MDMwNDUzMjRaMGExGDAWBgNVBAMMD3NhbXVlbC53aWxsaWFtczEd
21
+ MBsGCgmSJomT8ixkARkWDW9yaW9udHJhbnNmZXIxEjAQBgoJkiaJk/IsZAEZFgJj
22
+ bzESMBAGCgmSJomT8ixkARkWAm56MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIB
23
+ igKCAYEAomvSopQXQ24+9DBB6I6jxRI2auu3VVb4nOjmmHq7XWM4u3HL+pni63X2
24
+ 9qZdoq9xt7H+RPbwL28LDpDNflYQXoOhoVhQ37Pjn9YDjl8/4/9xa9+NUpl9XDIW
25
+ sGkaOY0eqsQm1pEWkHJr3zn/fxoKPZPfaJOglovdxf7dgsHz67Xgd/ka+Wo1YqoE
26
+ e5AUKRwUuvaUaumAKgPH+4E4oiLXI4T1Ff5Q7xxv6yXvHuYtlMHhYfgNn8iiW8WN
27
+ XibYXPNP7NtieSQqwR/xM6IRSoyXKuS+ZNGDPUUGk8RoiV/xvVN4LrVm9upSc0ss
28
+ RZ6qwOQmXCo/lLcDUxJAgG95cPw//sI00tZan75VgsGzSWAOdjQpFM0l4dxvKwHn
29
+ tUeT3ZsAgt0JnGqNm2Bkz81kG4A2hSyFZTFA8vZGhp+hz+8Q573tAR89y9YJBdYM
30
+ zp0FM4zwMNEUwgfRzv1tEVVUEXmoFCyhzonUUw4nE4CFu/sE3ffhjKcXcY//qiSW
31
+ xm4erY3XAgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAwHQYDVR0O
32
+ BBYEFO9t7XWuFf2SKLmuijgqR4sGDlRsMC4GA1UdEQQnMCWBI3NhbXVlbC53aWxs
33
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWBI3NhbXVlbC53aWxs
34
+ aWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEBCwUAA4IBgQB5sxkE
35
+ cBsSYwK6fYpM+hA5B5yZY2+L0Z+27jF1pWGgbhPH8/FjjBLVn+VFok3CDpRqwXCl
36
+ xCO40JEkKdznNy2avOMra6PFiQyOE74kCtv7P+Fdc+FhgqI5lMon6tt9rNeXmnW/
37
+ c1NaMRdxy999hmRGzUSFjozcCwxpy/LwabxtdXwXgSay4mQ32EDjqR1TixS1+smp
38
+ 8C/NCWgpIfzpHGJsjvmH2wAfKtTTqB9CVKLCWEnCHyCaRVuKkrKjqhYCdmMBqCws
39
+ JkxfQWC+jBVeG9ZtPhQgZpfhvh+6hMhraUYRQ6XGyvBqEUe+yo6DKIT3MtGE2+CP
40
+ eX9i9ZWBydWb8/rvmwmX2kkcBbX0hZS1rcR593hGc61JR6lvkGYQ2MYskBveyaxt
41
+ Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
42
+ voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
42
43
  -----END CERTIFICATE-----
43
- date: 2022-05-03 00:00:00.000000000 Z
44
+ date: 2022-10-14 00:00:00.000000000 Z
44
45
  dependencies:
45
46
  - !ruby/object:Gem::Dependency
46
47
  name: bake
@@ -105,6 +106,7 @@ extensions:
105
106
  - ext/extconf.rb
106
107
  extra_rdoc_files: []
107
108
  files:
109
+ - design.md
108
110
  - ext/extconf.rb
109
111
  - ext/io/event/event.c
110
112
  - ext/io/event/event.h
@@ -123,8 +125,12 @@ files:
123
125
  - lib/io/event/debug/selector.rb
124
126
  - lib/io/event/interrupt.rb
125
127
  - lib/io/event/selector.rb
128
+ - lib/io/event/selector/nonblock.rb
126
129
  - lib/io/event/selector/select.rb
130
+ - lib/io/event/support.rb
127
131
  - lib/io/event/version.rb
132
+ - license.md
133
+ - readme.md
128
134
  homepage: https://github.com/socketry/io-event
129
135
  licenses:
130
136
  - MIT
metadata.gz.sig CHANGED
Binary file