io-event 1.0.9 → 1.1.1

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: 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