io-event 1.0.7 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d99060107bec74ecdf3c86668fc61deea4d28bdcd9978511b5697ed33cf138d
4
- data.tar.gz: 5bf171bc3b6ffe9d0884b722b1b6d63d74ef8612b4d7e0a71257fc7fd7956f80
3
+ metadata.gz: 529ab26d211811182c1ac8b7b292431533c830eddcfd8781185c9ea4ff623c93
4
+ data.tar.gz: cef3ea8d930d3f3f92e0c814c0f89405a78e3da1d4ebd6c0d1e73bd32f6839a6
5
5
  SHA512:
6
- metadata.gz: 724ed197eeba22fd9ac7cb044ce287d34ba8a3a5a920dd84e990dd8627260c8d4266fae9f36f168859d9f6497efdefbb178f6d216cce16eabdf08f3d9e12d2e2
7
- data.tar.gz: a28bad4426fdb19d261565fe1363a3ce3a5cb6d29f7d70419bda678dbf414f483455b669cdca0f49c0400ba6ec01ece4f2b536fd1a90af01e7eb519277532756
6
+ metadata.gz: 77cd0725f41f507e391f54dae4071c9b2721a1fc4ce1c4dbcbf7b4dac8a7453c0e4867679b9f9c615d82ce06af2b3f77745b0d1526f0c6bb02cf06a60c84f763
7
+ data.tar.gz: 6d9a389303af3b13540ff2761d8e35762e3af975c7e1defddf8765088129f43dc4584029947bafd2a6eb35c60f8206b0dc184d425c52163d1652392e62bb9333
checksums.yaml.gz.sig ADDED
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
  #
@@ -241,7 +241,7 @@ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE pid, V
241
241
  rb_update_max_fd(process_wait_arguments.descriptor);
242
242
 
243
243
  struct epoll_event event = {
244
- .events = EPOLLIN|EPOLLRDHUP|EPOLLONESHOT,
244
+ .events = EPOLLIN|EPOLLERR|EPOLLHUP|EPOLLONESHOT,
245
245
  .data = {.ptr = (void*)fiber},
246
246
  };
247
247
 
@@ -385,7 +385,7 @@ VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
385
385
  return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
386
386
  }
387
387
 
388
- #ifdef HAVE_RUBY_IO_BUFFER_H
388
+ #ifdef RUBY_FIBER_SCHEDULER_VERSION
389
389
 
390
390
  struct io_read_arguments {
391
391
  VALUE self;
@@ -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
@@ -683,11 +715,13 @@ void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
683
715
  rb_define_method(IO_Event_Selector_EPoll, "close", IO_Event_Selector_EPoll_close, 0);
684
716
 
685
717
  rb_define_method(IO_Event_Selector_EPoll, "io_wait", IO_Event_Selector_EPoll_io_wait, 3);
718
+
719
+ rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read_compatible, -1);
720
+ rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write_compatible, -1);
686
721
 
687
- #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);
690
- #endif
722
+ // Once compatibility isn't a concern, we can do this:
723
+ // rb_define_method(IO_Event_Selector_EPoll, "io_read", IO_Event_Selector_EPoll_io_read, 5);
724
+ // rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write, 5);
691
725
 
692
726
  rb_define_method(IO_Event_Selector_EPoll, "process_wait", IO_Event_Selector_EPoll_process_wait, 3);
693
727
  }
@@ -380,7 +380,7 @@ VALUE IO_Event_Selector_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE
380
380
  return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
381
381
  }
382
382
 
383
- #ifdef HAVE_RUBY_IO_BUFFER_H
383
+ #ifdef RUBY_FIBER_SCHEDULER_VERSION
384
384
 
385
385
  struct io_read_arguments {
386
386
  VALUE self;
@@ -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
@@ -732,11 +764,9 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
732
764
  rb_define_method(IO_Event_Selector_KQueue, "close", IO_Event_Selector_KQueue_close, 0);
733
765
 
734
766
  rb_define_method(IO_Event_Selector_KQueue, "io_wait", IO_Event_Selector_KQueue_io_wait, 3);
735
-
736
- #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);
739
- #endif
767
+
768
+ rb_define_method(IO_Event_Selector_KQueue, "io_read", IO_Event_Selector_KQueue_io_read_compatible, -1);
769
+ rb_define_method(IO_Event_Selector_KQueue, "io_write", IO_Event_Selector_KQueue_io_write_compatible, -1);
740
770
 
741
771
  rb_define_method(IO_Event_Selector_KQueue, "process_wait", IO_Event_Selector_KQueue_process_wait, 3);
742
772
  }
@@ -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);
@@ -375,7 +376,7 @@ VALUE IO_Event_Selector_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
375
376
  return rb_rescue(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_rescue, (VALUE)&io_wait_arguments);
376
377
  }
377
378
 
378
- #ifdef HAVE_RUBY_IO_BUFFER_H
379
+ #ifdef RUBY_FIBER_SCHEDULER_VERSION
379
380
 
380
381
  #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,16,0)
381
382
  static inline off_t io_seekable(int descriptor) {
@@ -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;
@@ -710,11 +737,9 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
710
737
  rb_define_method(IO_Event_Selector_URing, "close", IO_Event_Selector_URing_close, 0);
711
738
 
712
739
  rb_define_method(IO_Event_Selector_URing, "io_wait", IO_Event_Selector_URing_io_wait, 3);
713
-
714
- #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);
717
- #endif
740
+
741
+ rb_define_method(IO_Event_Selector_URing, "io_read", IO_Event_Selector_URing_io_read_compatible, -1);
742
+ rb_define_method(IO_Event_Selector_URing, "io_write", IO_Event_Selector_URing_io_write_compatible, -1);
718
743
 
719
744
  rb_define_method(IO_Event_Selector_URing, "io_close", IO_Event_Selector_URing_io_close, 1);
720
745
 
@@ -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.
@@ -1,24 +1,12 @@
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'
8
+
9
+ require 'io/nonblock'
22
10
 
23
11
  module IO::Event
24
12
  module Selector
@@ -36,7 +24,7 @@ module IO::Event
36
24
 
37
25
  attr :loop
38
26
 
39
- # If the event loop is currently blocked,
27
+ # If the event loop is currently sleeping, wake it up.
40
28
  def wakeup
41
29
  if @blocked
42
30
  @interrupt.signal
@@ -148,11 +136,65 @@ module IO::Event
148
136
  waiter&.invalidate
149
137
  end
150
138
 
151
- if IO.const_defined?(:Buffer)
139
+ if Support.fiber_scheduler_v2?
152
140
  EAGAIN = Errno::EAGAIN::Errno
153
141
 
154
- def io_read(fiber, io, buffer, length)
155
- offset = 0
142
+ def io_read(fiber, io, buffer, length, offset = 0)
143
+ total = 0
144
+ io.nonblock = true
145
+
146
+ while true
147
+ maximum_size = buffer.size - offset
148
+ result = Fiber.blocking{buffer.read(io, maximum_size, offset)}
149
+
150
+ if result == -EAGAIN
151
+ if length > 0
152
+ self.io_wait(fiber, io, IO::READABLE)
153
+ else
154
+ return result
155
+ end
156
+ elsif result < 0
157
+ return result
158
+ else
159
+ total += result
160
+ offset += result
161
+ break if total >= length
162
+ end
163
+ end
164
+
165
+ return total
166
+ end
167
+
168
+ def io_write(fiber, io, buffer, length, offset = 0)
169
+ total = 0
170
+ io.nonblock = true
171
+
172
+ while true
173
+ maximum_size = buffer.size - offset
174
+ result = Fiber.blocking{buffer.write(io, maximum_size, offset)}
175
+
176
+ if result == -EAGAIN
177
+ if length > 0
178
+ self.io_wait(fiber, io, IO::READABLE)
179
+ else
180
+ return result
181
+ end
182
+ elsif result < 0
183
+ return result
184
+ else
185
+ total += result
186
+ offset += result
187
+ break if total >= length
188
+ end
189
+ end
190
+
191
+ return offset
192
+ end
193
+ elsif Support.fiber_scheduler_v1?
194
+ EAGAIN = Errno::EAGAIN::Errno
195
+
196
+ def io_read(fiber, _io, buffer, length, offset = 0)
197
+ io = IO.for_fd(_io.fileno, autoclose: false)
156
198
 
157
199
  while true
158
200
  maximum_size = buffer.size - offset
@@ -185,8 +227,8 @@ module IO::Event
185
227
  return offset
186
228
  end
187
229
 
188
- def io_write(fiber, io, buffer, length)
189
- offset = 0
230
+ def io_write(fiber, _io, buffer, length, offset = 0)
231
+ io = IO.for_fd(_io.fileno, autoclose: false)
190
232
 
191
233
  while true
192
234
  maximum_size = buffer.size - offset
@@ -214,24 +256,17 @@ module IO::Event
214
256
 
215
257
  return offset
216
258
  end
259
+
260
+ def blocking(&block)
261
+ fiber = Fiber.new(blocking: true, &block)
262
+ return fiber.resume(fiber)
263
+ end
217
264
  end
218
265
 
219
266
  def process_wait(fiber, pid, flags)
220
- r, w = IO.pipe
221
-
222
- thread = Thread.new do
267
+ Thread.new do
223
268
  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
269
+ end.value
235
270
  end
236
271
 
237
272
  private def pop_ready
@@ -255,6 +290,7 @@ module IO::Event
255
290
 
256
291
  readable = Array.new
257
292
  writable = Array.new
293
+ priority = Array.new
258
294
 
259
295
  @waiting.each do |io, waiter|
260
296
  waiter.each do |fiber, events|
@@ -265,12 +301,16 @@ module IO::Event
265
301
  if (events & IO::WRITABLE) > 0
266
302
  writable << io
267
303
  end
304
+
305
+ if (events & IO::PRIORITY) > 0
306
+ priority << io
307
+ end
268
308
  end
269
309
  end
270
310
 
271
311
  @blocked = true
272
312
  duration = 0 unless @ready.empty?
273
- readable, writable, _ = ::IO.select(readable, writable, nil, duration)
313
+ readable, writable, priority = ::IO.select(readable, writable, priority, duration)
274
314
  @blocked = false
275
315
 
276
316
  ready = Hash.new(0)
@@ -283,16 +323,16 @@ module IO::Event
283
323
  ready[io] |= IO::WRITABLE
284
324
  end
285
325
 
326
+ priority&.each do |io|
327
+ ready[io] |= IO::PRIORITY
328
+ end
329
+
286
330
  ready.each do |io, events|
287
331
  @waiting.delete(io).transfer(events)
288
332
  end
289
333
 
290
334
  return ready.size
291
335
  end
292
-
293
- private def blocking(&block)
294
- Fiber.new(blocking: true, &block).resume
295
- end
296
336
  end
297
337
  end
298
338
  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.7"
3
+ # Released under the MIT License.
4
+ # Copyright, 2021-2022, by Samuel Williams.
5
+
6
+ class IO
7
+ module Event
8
+ VERSION = "1.1.0"
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'
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 ADDED
Binary file
metadata CHANGED
@@ -1,17 +1,47 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-event
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
- - machty
8
+ - Bruno Sutic
9
9
  - Benoit Daloze
10
10
  - Delton Ding
11
+ - machty
11
12
  autorequire:
12
13
  bindir: bin
13
- cert_chain: []
14
- date: 2022-05-02 00:00:00.000000000 Z
14
+ cert_chain:
15
+ - |
16
+ -----BEGIN CERTIFICATE-----
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=
43
+ -----END CERTIFICATE-----
44
+ date: 2022-10-13 00:00:00.000000000 Z
15
45
  dependencies:
16
46
  - !ruby/object:Gem::Dependency
17
47
  name: bake
@@ -76,6 +106,7 @@ extensions:
76
106
  - ext/extconf.rb
77
107
  extra_rdoc_files: []
78
108
  files:
109
+ - design.md
79
110
  - ext/extconf.rb
80
111
  - ext/io/event/event.c
81
112
  - ext/io/event/event.h
@@ -95,7 +126,10 @@ files:
95
126
  - lib/io/event/interrupt.rb
96
127
  - lib/io/event/selector.rb
97
128
  - lib/io/event/selector/select.rb
129
+ - lib/io/event/support.rb
98
130
  - lib/io/event/version.rb
131
+ - license.md
132
+ - readme.md
99
133
  homepage: https://github.com/socketry/io-event
100
134
  licenses:
101
135
  - MIT
@@ -115,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
149
  - !ruby/object:Gem::Version
116
150
  version: '0'
117
151
  requirements: []
118
- rubygems_version: 3.4.0.dev
152
+ rubygems_version: 3.3.7
119
153
  signing_key:
120
154
  specification_version: 4
121
155
  summary: An event loop.
metadata.gz.sig ADDED
Binary file