io-event 1.0.9 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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 +37 -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: dd5603ed5cc26eaa2f9d4261d7462ec1d435c169c36c2770af80c0d27fe2c4e2
|
4
|
+
data.tar.gz: 1ce4d895bfc5618e97bf84702e2591aa9b3aa947678e5eae8b1b42c0c4119607
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5924e3108f8c731a55d36f5329519870931aaa16e14fab81ca7b56418afb77cc6bab395c10751b628ce2668ef5c570141af6237cc07c7a62bf8fc8a4b53c71a
|
7
|
+
data.tar.gz: a5e8281833ac2f7476ca298fc0446ad4479dd0f08cb7764c5f0940fd235446b903e03909acc669869b2847eab50e92c1ef80e6c77acef62b35525d39a48a5351
|
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,8 @@ 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);
|
329
|
+
io_uring_sqe_set_data(sqe, NULL);
|
328
330
|
io_uring_submit_now(data);
|
329
331
|
|
330
332
|
rb_exc_raise(exception);
|
@@ -408,7 +410,7 @@ static int io_read(struct IO_Event_Selector_URing *data, VALUE fiber, int descri
|
|
408
410
|
return RB_NUM2INT(result);
|
409
411
|
}
|
410
412
|
|
411
|
-
VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
413
|
+
VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
|
412
414
|
struct IO_Event_Selector_URing *data = NULL;
|
413
415
|
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
|
414
416
|
|
@@ -418,8 +420,8 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
|
|
418
420
|
size_t size;
|
419
421
|
rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
|
420
422
|
|
421
|
-
size_t offset = 0;
|
422
423
|
size_t length = NUM2SIZET(_length);
|
424
|
+
size_t offset = NUM2SIZET(_offset);
|
423
425
|
|
424
426
|
while (true) {
|
425
427
|
size_t maximum_size = size - offset;
|
@@ -443,6 +445,19 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
|
|
443
445
|
return rb_fiber_scheduler_io_result(offset, 0);
|
444
446
|
}
|
445
447
|
|
448
|
+
static VALUE IO_Event_Selector_URing_io_read_compatible(int argc, VALUE *argv, VALUE self)
|
449
|
+
{
|
450
|
+
rb_check_arity(argc, 4, 5);
|
451
|
+
|
452
|
+
VALUE _offset = SIZET2NUM(0);
|
453
|
+
|
454
|
+
if (argc == 5) {
|
455
|
+
_offset = argv[4];
|
456
|
+
}
|
457
|
+
|
458
|
+
return IO_Event_Selector_URing_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
|
459
|
+
}
|
460
|
+
|
446
461
|
static
|
447
462
|
int io_write(struct IO_Event_Selector_URing *data, VALUE fiber, int descriptor, char *buffer, size_t length) {
|
448
463
|
struct io_uring_sqe *sqe = io_get_sqe(data);
|
@@ -459,7 +474,7 @@ int io_write(struct IO_Event_Selector_URing *data, VALUE fiber, int descriptor,
|
|
459
474
|
return result;
|
460
475
|
}
|
461
476
|
|
462
|
-
VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length) {
|
477
|
+
VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
|
463
478
|
struct IO_Event_Selector_URing *data = NULL;
|
464
479
|
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
|
465
480
|
|
@@ -469,8 +484,8 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
469
484
|
size_t size;
|
470
485
|
rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
|
471
486
|
|
472
|
-
size_t offset = 0;
|
473
487
|
size_t length = NUM2SIZET(_length);
|
488
|
+
size_t offset = NUM2SIZET(_offset);
|
474
489
|
|
475
490
|
if (length > size) {
|
476
491
|
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
@@ -496,6 +511,19 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
496
511
|
return rb_fiber_scheduler_io_result(offset, 0);
|
497
512
|
}
|
498
513
|
|
514
|
+
static VALUE IO_Event_Selector_URing_io_write_compatible(int argc, VALUE *argv, VALUE self)
|
515
|
+
{
|
516
|
+
rb_check_arity(argc, 4, 5);
|
517
|
+
|
518
|
+
VALUE _offset = SIZET2NUM(0);
|
519
|
+
|
520
|
+
if (argc == 5) {
|
521
|
+
_offset = argv[4];
|
522
|
+
}
|
523
|
+
|
524
|
+
return IO_Event_Selector_URing_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
|
525
|
+
}
|
526
|
+
|
499
527
|
#endif
|
500
528
|
|
501
529
|
static const int ASYNC_CLOSE = 1;
|
@@ -680,6 +708,8 @@ VALUE IO_Event_Selector_URing_wakeup(VALUE self) {
|
|
680
708
|
}
|
681
709
|
|
682
710
|
io_uring_prep_nop(sqe);
|
711
|
+
// If you don't set this line, the SQE will eventually be recycled and have valid user data which can cause odd behaviour:
|
712
|
+
io_uring_sqe_set_data(sqe, NULL);
|
683
713
|
io_uring_submit(&data->ring);
|
684
714
|
|
685
715
|
return Qtrue;
|
@@ -712,8 +742,8 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
|
|
712
742
|
rb_define_method(IO_Event_Selector_URing, "io_wait", IO_Event_Selector_URing_io_wait, 3);
|
713
743
|
|
714
744
|
#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",
|
745
|
+
rb_define_method(IO_Event_Selector_URing, "io_read", IO_Event_Selector_URing_io_read_compatible, -1);
|
746
|
+
rb_define_method(IO_Event_Selector_URing, "io_write", IO_Event_Selector_URing_io_write_compatible, -1);
|
717
747
|
#endif
|
718
748
|
|
719
749
|
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.2"
|
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
|
+
# ![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.
|
4
|
+
version: 1.1.2
|
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-19 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
|