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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/design.md +63 -0
- data/ext/extconf.rb +5 -1
- data/ext/io/event/selector/epoll.c +42 -6
- data/ext/io/event/selector/kqueue.c +38 -6
- data/ext/io/event/selector/selector.c +48 -7
- data/ext/io/event/selector/selector.h +4 -0
- data/ext/io/event/selector/uring.c +34 -7
- data/lib/io/event/debug/selector.rb +16 -27
- data/lib/io/event/interrupt.rb +4 -19
- data/lib/io/event/selector/nonblock.rb +14 -0
- data/lib/io/event/selector/select.rb +98 -51
- data/lib/io/event/selector.rb +11 -23
- data/lib/io/event/support.rb +22 -0
- data/lib/io/event/version.rb +8 -21
- data/lib/io/event.rb +5 -20
- data/license.md +25 -0
- data/readme.md +23 -0
- data.tar.gz.sig +0 -0
- metadata +33 -27
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 336b8a299fe9de0466ef4453f9cde52f1820ec94c10b30033b9d79f30e2ee7a5
|
4
|
+
data.tar.gz: 6c32fd8b43caeecbf400e19f1cc33b7c8fd3fd70d9db3e08e622fb596ba185b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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(
|
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",
|
689
|
-
rb_define_method(IO_Event_Selector_EPoll, "io_write",
|
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",
|
738
|
-
rb_define_method(IO_Event_Selector_KQueue, "io_write",
|
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),
|
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
|
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 {
|
@@ -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, (
|
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",
|
716
|
-
rb_define_method(IO_Event_Selector_URing, "io_write",
|
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
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
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
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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)
|
data/lib/io/event/interrupt.rb
CHANGED
@@ -1,22 +1,7 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
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,10 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
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
|
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
|
-
|
152
|
-
|
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
|
155
|
-
|
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
|
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
|
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
|
232
|
+
return total
|
186
233
|
end
|
187
234
|
|
188
|
-
def io_write(fiber,
|
189
|
-
|
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
|
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
|
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
|
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
|
-
|
221
|
-
|
222
|
-
thread = Thread.new do
|
274
|
+
Thread.new do
|
223
275
|
Process::Status.wait(pid, flags)
|
224
|
-
|
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,
|
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
|
data/lib/io/event/selector.rb
CHANGED
@@ -1,25 +1,11 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
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?(:
|
36
|
-
|
21
|
+
if self.const_defined?(:URing)
|
22
|
+
URing
|
23
|
+
elsif self.const_defined?(:EPoll)
|
24
|
+
EPoll
|
37
25
|
elsif self.const_defined?(:KQueue)
|
38
|
-
|
26
|
+
KQueue
|
39
27
|
else
|
40
|
-
|
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
|
data/lib/io/event/version.rb
CHANGED
@@ -1,23 +1,10 @@
|
|
1
|
-
#
|
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
|
-
|
22
|
-
|
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
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
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
|
-
|
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
|
+
# 
|
2
|
+
|
3
|
+
Provides low level cross-platform primitives for constructing event loops, with support for `select`, `kqueue`, `epoll` and `io_uring`.
|
4
|
+
|
5
|
+
[](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.
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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-
|
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
|