io-event 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/IO_Event.bundle +0 -0
- data/ext/Makefile +2 -2
- data/ext/extconf.rb +3 -0
- data/ext/interrupt.o +0 -0
- data/ext/io/event/interrupt.c +84 -0
- data/ext/io/event/interrupt.h +43 -0
- data/ext/io/event/selector/epoll.c +53 -0
- data/ext/io/event/selector/epoll.h +2 -0
- data/ext/io/event/selector/kqueue.c +44 -4
- data/ext/io/event/selector/uring.c +61 -11
- data/ext/io/event/selector/uring.h +0 -1
- data/ext/kqueue.o +0 -0
- data/ext/mkmf.log +17 -1
- data/lib/io/event/debug/selector.rb +12 -0
- data/lib/io/event/interrupt.rb +59 -0
- data/lib/io/event/selector/select.rb +23 -2
- data/lib/io/event/selector.rb +3 -3
- data/lib/io/event/version.rb +1 -1
- metadata +6 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9138d171a26780a13bfb5e983488d743de8e891112e976d02f10a73fedace606
|
4
|
+
data.tar.gz: 0e4c44a7f8f1379fc8de5dd3fa8ffde0bd4f6bffc1bdb25a0fb7cfb0dfd45bc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 733f4341efdf63775b2faac16609a3f8574a2d17a77db919375afd04bbaa0730acca6fd6dc9849a4aa4177fbe8b9d2855afabbf64e5e31e8ce09ae8f0f6e46bc
|
7
|
+
data.tar.gz: a207ab4ef7a2097189f2e59fe4838a5aa877856a0b3ac9732b19340ffbd8ef73460aca159794dfaa3e488b9436fb614fccabd94151290a02e70e6f43281a754f
|
data/ext/IO_Event.bundle
CHANGED
Binary file
|
data/ext/Makefile
CHANGED
@@ -139,8 +139,8 @@ target_prefix =
|
|
139
139
|
LOCAL_LIBS =
|
140
140
|
LIBS =
|
141
141
|
ORIG_SRCS =
|
142
|
-
SRCS = $(ORIG_SRCS) event.c selector.c kqueue.c
|
143
|
-
OBJS = event.o selector.o kqueue.o
|
142
|
+
SRCS = $(ORIG_SRCS) event.c selector.c kqueue.c interrupt.c
|
143
|
+
OBJS = event.o selector.o kqueue.o interrupt.o
|
144
144
|
HDRS = $(srcdir)/extconf.h
|
145
145
|
LOCAL_HDRS =
|
146
146
|
TARGET = IO_Event
|
data/ext/extconf.rb
CHANGED
data/ext/interrupt.o
ADDED
Binary file
|
@@ -0,0 +1,84 @@
|
|
1
|
+
// Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
//
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
8
|
+
// furnished to do so, subject to the following conditions:
|
9
|
+
//
|
10
|
+
// The above copyright notice and this permission notice shall be included in
|
11
|
+
// all copies or substantial portions of the Software.
|
12
|
+
//
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
// THE SOFTWARE.
|
20
|
+
|
21
|
+
// static const int DEBUG = 0;
|
22
|
+
|
23
|
+
#include "interrupt.h"
|
24
|
+
#include <fcntl.h>
|
25
|
+
#include <unistd.h>
|
26
|
+
|
27
|
+
#ifdef HAVE_SYS_EVENTFD_H
|
28
|
+
#include <sys/eventfd.h>
|
29
|
+
#endif
|
30
|
+
|
31
|
+
#include "selector/selector.h"
|
32
|
+
|
33
|
+
#ifdef HAVE_SYS_EVENTFD_H
|
34
|
+
void IO_Event_Interrupt_open(struct IO_Event_Interrupt *interrupt)
|
35
|
+
{
|
36
|
+
interrupt->descriptor = eventfd2(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
37
|
+
rb_update_max_fd(interrupt->descriptor);
|
38
|
+
}
|
39
|
+
|
40
|
+
void IO_Event_Interrupt_close(struct IO_Event_Interrupt *interrupt)
|
41
|
+
{
|
42
|
+
close(interrupt->descriptor);
|
43
|
+
}
|
44
|
+
|
45
|
+
void IO_Event_Interrupt_signal(struct IO_Event_Interrupt *interrupt)
|
46
|
+
{
|
47
|
+
uint64_t value = 1;
|
48
|
+
write(interrupt->descriptor, &value, sizeof(value));
|
49
|
+
}
|
50
|
+
|
51
|
+
void IO_Event_Interrupt_clear(struct IO_Event_Interrupt *interrupt)
|
52
|
+
{
|
53
|
+
uint64_t value = 0;
|
54
|
+
read(interrupt->descriptor, &value, sizeof(value));
|
55
|
+
}
|
56
|
+
#else
|
57
|
+
void IO_Event_Interrupt_open(struct IO_Event_Interrupt *interrupt)
|
58
|
+
{
|
59
|
+
#ifdef __linux__
|
60
|
+
pipe2(interrupt->descriptor, O_CLOEXEC | O_NONBLOCK);
|
61
|
+
#else
|
62
|
+
pipe(interrupt->descriptor);
|
63
|
+
IO_Event_Selector_nonblock_set(interrupt->descriptor[0]);
|
64
|
+
IO_Event_Selector_nonblock_set(interrupt->descriptor[1]);
|
65
|
+
#endif
|
66
|
+
}
|
67
|
+
|
68
|
+
void IO_Event_Interrupt_close(struct IO_Event_Interrupt *interrupt)
|
69
|
+
{
|
70
|
+
close(interrupt->descriptor[0]);
|
71
|
+
close(interrupt->descriptor[1]);
|
72
|
+
}
|
73
|
+
|
74
|
+
void IO_Event_Interrupt_signal(struct IO_Event_Interrupt *interrupt)
|
75
|
+
{
|
76
|
+
write(interrupt->descriptor[1], ".", 1);
|
77
|
+
}
|
78
|
+
|
79
|
+
void IO_Event_Interrupt_clear(struct IO_Event_Interrupt *interrupt)
|
80
|
+
{
|
81
|
+
char buffer[128];
|
82
|
+
read(interrupt->descriptor[0], buffer, sizeof(buffer));
|
83
|
+
}
|
84
|
+
#endif
|
@@ -0,0 +1,43 @@
|
|
1
|
+
// Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
//
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
8
|
+
// furnished to do so, subject to the following conditions:
|
9
|
+
//
|
10
|
+
// The above copyright notice and this permission notice shall be included in
|
11
|
+
// all copies or substantial portions of the Software.
|
12
|
+
//
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
// THE SOFTWARE.
|
20
|
+
|
21
|
+
#ifdef HAVE_SYS_EVENTFD_H
|
22
|
+
struct IO_Event_Interrupt {
|
23
|
+
int descriptor;
|
24
|
+
};
|
25
|
+
|
26
|
+
inline int IO_Event_Interrupt_descriptor(struct IO_Event_Interrupt *interrupt) {
|
27
|
+
return interrupt->descriptor;
|
28
|
+
}
|
29
|
+
#else
|
30
|
+
struct IO_Event_Interrupt {
|
31
|
+
int descriptor[2];
|
32
|
+
};
|
33
|
+
|
34
|
+
inline int IO_Event_Interrupt_descriptor(struct IO_Event_Interrupt *interrupt) {
|
35
|
+
return interrupt->descriptor[0];
|
36
|
+
}
|
37
|
+
#endif
|
38
|
+
|
39
|
+
void IO_Event_Interrupt_open(struct IO_Event_Interrupt *interrupt);
|
40
|
+
void IO_Event_Interrupt_close(struct IO_Event_Interrupt *interrupt);
|
41
|
+
|
42
|
+
void IO_Event_Interrupt_signal(struct IO_Event_Interrupt *interrupt);
|
43
|
+
void IO_Event_Interrupt_clear(struct IO_Event_Interrupt *interrupt);
|
@@ -26,6 +26,7 @@
|
|
26
26
|
#include <errno.h>
|
27
27
|
|
28
28
|
#include "pidfd.c"
|
29
|
+
#include "../interrupt.h"
|
29
30
|
|
30
31
|
static VALUE IO_Event_Selector_EPoll = Qnil;
|
31
32
|
|
@@ -34,6 +35,8 @@ enum {EPOLL_MAX_EVENTS = 64};
|
|
34
35
|
struct IO_Event_Selector_EPoll {
|
35
36
|
struct IO_Event_Selector backend;
|
36
37
|
int descriptor;
|
38
|
+
int blocked;
|
39
|
+
IO_Event_Interrupt interrupt;
|
37
40
|
};
|
38
41
|
|
39
42
|
void IO_Event_Selector_EPoll_Type_mark(void *_data)
|
@@ -47,6 +50,8 @@ void close_internal(struct IO_Event_Selector_EPoll *data) {
|
|
47
50
|
if (data->descriptor >= 0) {
|
48
51
|
close(data->descriptor);
|
49
52
|
data->descriptor = -1;
|
53
|
+
|
54
|
+
IO_Event_Interrupt_close(&data->interrupt);
|
50
55
|
}
|
51
56
|
}
|
52
57
|
|
@@ -85,6 +90,21 @@ VALUE IO_Event_Selector_EPoll_allocate(VALUE self) {
|
|
85
90
|
return instance;
|
86
91
|
}
|
87
92
|
|
93
|
+
void IO_Event_Interrupt_add(IO_Event_Interrupt *interrupt, struct IO_Event_Selector_EPoll *data) {
|
94
|
+
int descriptor = IO_Event_Interrupt_descriptor(interrupt);
|
95
|
+
|
96
|
+
struct epoll_event event = {
|
97
|
+
.events = EPOLLIN|EPOLLRDHUP,
|
98
|
+
.data = {.ptr = NULL, .fd},
|
99
|
+
};
|
100
|
+
|
101
|
+
int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
|
102
|
+
|
103
|
+
if (result == -1) {
|
104
|
+
rb_sys_fail("IO_Event_Interrupt_addL:epoll_ctl");
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
88
108
|
VALUE IO_Event_Selector_EPoll_initialize(VALUE self, VALUE loop) {
|
89
109
|
struct IO_Event_Selector_EPoll *data = NULL;
|
90
110
|
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
|
@@ -100,9 +120,19 @@ VALUE IO_Event_Selector_EPoll_initialize(VALUE self, VALUE loop) {
|
|
100
120
|
rb_update_max_fd(data->descriptor);
|
101
121
|
}
|
102
122
|
|
123
|
+
IO_Event_Interrupt_open(&data->interrupt);
|
124
|
+
IO_Event_Interrupt_add(&data->interrupt, data);
|
125
|
+
|
103
126
|
return self;
|
104
127
|
}
|
105
128
|
|
129
|
+
VALUE IO_Event_Selector_EPoll_loop(VALUE self) {
|
130
|
+
struct IO_Event_Selector_EPoll *data = NULL;
|
131
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
|
132
|
+
|
133
|
+
return data->backend.loop;
|
134
|
+
}
|
135
|
+
|
106
136
|
VALUE IO_Event_Selector_EPoll_close(VALUE self) {
|
107
137
|
struct IO_Event_Selector_EPoll *data = NULL;
|
108
138
|
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
|
@@ -498,7 +528,9 @@ void * select_internal(void *_arguments) {
|
|
498
528
|
|
499
529
|
static
|
500
530
|
void select_internal_without_gvl(struct select_arguments *arguments) {
|
531
|
+
arguments->data->blocked = 1;
|
501
532
|
rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
|
533
|
+
arguments->data->blocked = 0;
|
502
534
|
|
503
535
|
if (arguments->count == -1) {
|
504
536
|
rb_sys_fail("select_internal_without_gvl:epoll_wait");
|
@@ -540,6 +572,10 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
|
540
572
|
VALUE fiber = (VALUE)arguments.events[i].data.ptr;
|
541
573
|
VALUE result = INT2NUM(arguments.events[i].events);
|
542
574
|
|
575
|
+
if (arguments.events[i].data.fd == IO_Event_Interrupt_descriptor(&data->interrupt)) {
|
576
|
+
IO_Event_Interrupt_clear(&data->interrupt);
|
577
|
+
}
|
578
|
+
|
543
579
|
// fprintf(stderr, "-> fiber=%p descriptor=%d\n", (void*)fiber, events[i].data.fd);
|
544
580
|
|
545
581
|
IO_Event_Selector_fiber_transfer(fiber, 1, &result);
|
@@ -548,6 +584,20 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
|
548
584
|
return INT2NUM(arguments.count);
|
549
585
|
}
|
550
586
|
|
587
|
+
VALUE IO_Event_Selector_URing_wakeup(VALUE self) {
|
588
|
+
struct IO_Event_Selector_EPoll *data = NULL;
|
589
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, data);
|
590
|
+
|
591
|
+
// If we are blocking, we can schedule a nop event to wake up the selector:
|
592
|
+
if (data->blocked) {
|
593
|
+
IO_Event_Interrupt_signal(data->interrupt);
|
594
|
+
|
595
|
+
return Qtrue;
|
596
|
+
}
|
597
|
+
|
598
|
+
return Qfalse;
|
599
|
+
}
|
600
|
+
|
551
601
|
void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
|
552
602
|
IO_Event_Selector_EPoll = rb_define_class_under(IO_Event_Selector, "EPoll", rb_cObject);
|
553
603
|
rb_gc_register_mark_object(IO_Event_Selector_EPoll);
|
@@ -555,6 +605,8 @@ void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
|
|
555
605
|
rb_define_alloc_func(IO_Event_Selector_EPoll, IO_Event_Selector_EPoll_allocate);
|
556
606
|
rb_define_method(IO_Event_Selector_EPoll, "initialize", IO_Event_Selector_EPoll_initialize, 1);
|
557
607
|
|
608
|
+
rb_define_method(IO_Event_Selector_EPoll, "loop", IO_Event_Selector_EPoll_loop, 0);
|
609
|
+
|
558
610
|
rb_define_method(IO_Event_Selector_EPoll, "transfer", IO_Event_Selector_EPoll_transfer, 0);
|
559
611
|
rb_define_method(IO_Event_Selector_EPoll, "resume", IO_Event_Selector_EPoll_resume, -1);
|
560
612
|
rb_define_method(IO_Event_Selector_EPoll, "yield", IO_Event_Selector_EPoll_yield, 0);
|
@@ -564,6 +616,7 @@ void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
|
|
564
616
|
rb_define_method(IO_Event_Selector_EPoll, "ready?", IO_Event_Selector_EPoll_ready_p, 0);
|
565
617
|
|
566
618
|
rb_define_method(IO_Event_Selector_EPoll, "select", IO_Event_Selector_EPoll_select, 1);
|
619
|
+
rb_define_method(IO_Event_Selector_EPoll, "wakeup", IO_Event_Selector_EPoll_wakeup, 0);
|
567
620
|
rb_define_method(IO_Event_Selector_EPoll, "close", IO_Event_Selector_EPoll_close, 0);
|
568
621
|
|
569
622
|
rb_define_method(IO_Event_Selector_EPoll, "io_wait", IO_Event_Selector_EPoll_io_wait, 3);
|
@@ -33,6 +33,8 @@ enum {KQUEUE_MAX_EVENTS = 64};
|
|
33
33
|
struct IO_Event_Selector_KQueue {
|
34
34
|
struct IO_Event_Selector backend;
|
35
35
|
int descriptor;
|
36
|
+
|
37
|
+
int blocked;
|
36
38
|
};
|
37
39
|
|
38
40
|
void IO_Event_Selector_KQueue_Type_mark(void *_data)
|
@@ -80,6 +82,7 @@ VALUE IO_Event_Selector_KQueue_allocate(VALUE self) {
|
|
80
82
|
|
81
83
|
IO_Event_Selector_initialize(&data->backend, Qnil);
|
82
84
|
data->descriptor = -1;
|
85
|
+
data->blocked = 0;
|
83
86
|
|
84
87
|
return instance;
|
85
88
|
}
|
@@ -103,6 +106,13 @@ VALUE IO_Event_Selector_KQueue_initialize(VALUE self, VALUE loop) {
|
|
103
106
|
return self;
|
104
107
|
}
|
105
108
|
|
109
|
+
VALUE IO_Event_Selector_KQueue_loop(VALUE self) {
|
110
|
+
struct IO_Event_Selector_KQueue *data = NULL;
|
111
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, data);
|
112
|
+
|
113
|
+
return data->backend.loop;
|
114
|
+
}
|
115
|
+
|
106
116
|
VALUE IO_Event_Selector_KQueue_close(VALUE self) {
|
107
117
|
struct IO_Event_Selector_KQueue *data = NULL;
|
108
118
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, data);
|
@@ -561,7 +571,9 @@ void * select_internal(void *_arguments) {
|
|
561
571
|
|
562
572
|
static
|
563
573
|
void select_internal_without_gvl(struct select_arguments *arguments) {
|
574
|
+
arguments->data->blocked = 1;
|
564
575
|
rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
|
576
|
+
arguments->data->blocked = 0;
|
565
577
|
|
566
578
|
if (arguments->count == -1) {
|
567
579
|
rb_sys_fail("select_internal_without_gvl:kevent");
|
@@ -614,15 +626,40 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
614
626
|
}
|
615
627
|
|
616
628
|
for (int i = 0; i < arguments.count; i += 1) {
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
629
|
+
if (arguments.events[i].udata) {
|
630
|
+
VALUE fiber = (VALUE)arguments.events[i].udata;
|
631
|
+
VALUE result = INT2NUM(arguments.events[i].filter);
|
632
|
+
|
633
|
+
IO_Event_Selector_fiber_transfer(fiber, 1, &result);
|
634
|
+
}
|
621
635
|
}
|
622
636
|
|
623
637
|
return INT2NUM(arguments.count);
|
624
638
|
}
|
625
639
|
|
640
|
+
VALUE IO_Event_Selector_KQueue_wakeup(VALUE self) {
|
641
|
+
struct IO_Event_Selector_KQueue *data = NULL;
|
642
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, data);
|
643
|
+
|
644
|
+
if (data->blocked) {
|
645
|
+
struct kevent trigger = {0};
|
646
|
+
|
647
|
+
trigger.filter = EVFILT_USER;
|
648
|
+
trigger.flags = EV_ADD|EV_CLEAR;
|
649
|
+
trigger.fflags = NOTE_TRIGGER;
|
650
|
+
|
651
|
+
int result = kevent(data->descriptor, &trigger, 1, NULL, 0, NULL);
|
652
|
+
|
653
|
+
if (result == -1) {
|
654
|
+
rb_sys_fail("IO_Event_Selector_KQueue_wakeup:kevent");
|
655
|
+
}
|
656
|
+
|
657
|
+
return Qtrue;
|
658
|
+
}
|
659
|
+
|
660
|
+
return Qfalse;
|
661
|
+
}
|
662
|
+
|
626
663
|
void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
|
627
664
|
IO_Event_Selector_KQueue = rb_define_class_under(IO_Event_Selector, "KQueue", rb_cObject);
|
628
665
|
rb_gc_register_mark_object(IO_Event_Selector_KQueue);
|
@@ -630,6 +667,8 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
|
|
630
667
|
rb_define_alloc_func(IO_Event_Selector_KQueue, IO_Event_Selector_KQueue_allocate);
|
631
668
|
rb_define_method(IO_Event_Selector_KQueue, "initialize", IO_Event_Selector_KQueue_initialize, 1);
|
632
669
|
|
670
|
+
rb_define_method(IO_Event_Selector_KQueue, "loop", IO_Event_Selector_KQueue_loop, 0);
|
671
|
+
|
633
672
|
rb_define_method(IO_Event_Selector_KQueue, "transfer", IO_Event_Selector_KQueue_transfer, 0);
|
634
673
|
rb_define_method(IO_Event_Selector_KQueue, "resume", IO_Event_Selector_KQueue_resume, -1);
|
635
674
|
rb_define_method(IO_Event_Selector_KQueue, "yield", IO_Event_Selector_KQueue_yield, 0);
|
@@ -639,6 +678,7 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
|
|
639
678
|
rb_define_method(IO_Event_Selector_KQueue, "ready?", IO_Event_Selector_KQueue_ready_p, 0);
|
640
679
|
|
641
680
|
rb_define_method(IO_Event_Selector_KQueue, "select", IO_Event_Selector_KQueue_select, 1);
|
681
|
+
rb_define_method(IO_Event_Selector_KQueue, "wakeup", IO_Event_Selector_KQueue_wakeup, 0);
|
642
682
|
rb_define_method(IO_Event_Selector_KQueue, "close", IO_Event_Selector_KQueue_close, 0);
|
643
683
|
|
644
684
|
rb_define_method(IO_Event_Selector_KQueue, "io_wait", IO_Event_Selector_KQueue_io_wait, 3);
|
@@ -26,6 +26,7 @@
|
|
26
26
|
#include <time.h>
|
27
27
|
|
28
28
|
#include "pidfd.c"
|
29
|
+
#include "../interrupt.h"
|
29
30
|
|
30
31
|
static const int DEBUG = 0;
|
31
32
|
|
@@ -37,6 +38,7 @@ struct IO_Event_Selector_URing {
|
|
37
38
|
struct IO_Event_Selector backend;
|
38
39
|
struct io_uring ring;
|
39
40
|
size_t pending;
|
41
|
+
int blocked;
|
40
42
|
};
|
41
43
|
|
42
44
|
void IO_Event_Selector_URing_Type_mark(void *_data)
|
@@ -86,7 +88,8 @@ VALUE IO_Event_Selector_URing_allocate(VALUE self) {
|
|
86
88
|
data->ring.ring_fd = -1;
|
87
89
|
|
88
90
|
data->pending = 0;
|
89
|
-
|
91
|
+
data->blocked = 0;
|
92
|
+
|
90
93
|
return instance;
|
91
94
|
}
|
92
95
|
|
@@ -106,6 +109,13 @@ VALUE IO_Event_Selector_URing_initialize(VALUE self, VALUE loop) {
|
|
106
109
|
return self;
|
107
110
|
}
|
108
111
|
|
112
|
+
VALUE IO_Event_Selector_URing_loop(VALUE self) {
|
113
|
+
struct IO_Event_Selector_URing *data = NULL;
|
114
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
|
115
|
+
|
116
|
+
return data->backend.loop;
|
117
|
+
}
|
118
|
+
|
109
119
|
VALUE IO_Event_Selector_URing_close(VALUE self) {
|
110
120
|
struct IO_Event_Selector_URing *data = NULL;
|
111
121
|
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
|
@@ -156,7 +166,8 @@ VALUE IO_Event_Selector_URing_raise(int argc, VALUE *argv, VALUE self)
|
|
156
166
|
|
157
167
|
return IO_Event_Selector_raise(&data->backend, argc, argv);
|
158
168
|
}
|
159
|
-
|
169
|
+
|
170
|
+
int blocked;
|
160
171
|
VALUE IO_Event_Selector_URing_ready_p(VALUE self) {
|
161
172
|
struct IO_Event_Selector_URing *data = NULL;
|
162
173
|
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, data);
|
@@ -171,14 +182,14 @@ int io_uring_submit_flush(struct IO_Event_Selector_URing *data) {
|
|
171
182
|
|
172
183
|
// Try to submit:
|
173
184
|
int result = io_uring_submit(&data->ring);
|
174
|
-
|
185
|
+
|
175
186
|
if (result >= 0) {
|
176
187
|
// If it was submitted, reset pending count:
|
177
188
|
data->pending = 0;
|
178
189
|
} else if (result != -EBUSY && result != -EAGAIN) {
|
179
190
|
rb_syserr_fail(-result, "io_uring_submit_flush");
|
180
191
|
}
|
181
|
-
|
192
|
+
|
182
193
|
return result;
|
183
194
|
}
|
184
195
|
|
@@ -194,7 +205,7 @@ int io_uring_submit_now(struct IO_Event_Selector_URing *data) {
|
|
194
205
|
data->pending = 0;
|
195
206
|
return result;
|
196
207
|
}
|
197
|
-
|
208
|
+
|
198
209
|
if (result == -EBUSY || result == -EAGAIN) {
|
199
210
|
IO_Event_Selector_yield(&data->backend);
|
200
211
|
} else {
|
@@ -214,7 +225,7 @@ struct io_uring_sqe * io_get_sqe(struct IO_Event_Selector_URing *data) {
|
|
214
225
|
while (sqe == NULL) {
|
215
226
|
// The submit queue is full, we need to drain it:
|
216
227
|
io_uring_submit_now(data);
|
217
|
-
|
228
|
+
|
218
229
|
sqe = io_uring_get_sqe(&data->ring);
|
219
230
|
}
|
220
231
|
|
@@ -523,10 +534,8 @@ struct select_arguments {
|
|
523
534
|
static
|
524
535
|
void * select_internal(void *_arguments) {
|
525
536
|
struct select_arguments * arguments = (struct select_arguments *)_arguments;
|
526
|
-
|
527
|
-
io_uring_submit_flush(arguments->data);
|
528
|
-
|
529
537
|
struct io_uring_cqe *cqe = NULL;
|
538
|
+
|
530
539
|
arguments->result = io_uring_wait_cqe_timeout(&arguments->data->ring, &cqe, arguments->timeout);
|
531
540
|
|
532
541
|
return NULL;
|
@@ -534,7 +543,11 @@ void * select_internal(void *_arguments) {
|
|
534
543
|
|
535
544
|
static
|
536
545
|
int select_internal_without_gvl(struct select_arguments *arguments) {
|
546
|
+
io_uring_submit_flush(arguments->data);
|
547
|
+
|
548
|
+
arguments->data->blocked = 1;
|
537
549
|
rb_thread_call_without_gvl(select_internal, (void *)arguments, RUBY_UBF_IO, 0);
|
550
|
+
arguments->data->blocked = 0;
|
538
551
|
|
539
552
|
if (arguments->result == -ETIME) {
|
540
553
|
arguments->result = 0;
|
@@ -548,6 +561,8 @@ int select_internal_without_gvl(struct select_arguments *arguments) {
|
|
548
561
|
return arguments->result;
|
549
562
|
}
|
550
563
|
|
564
|
+
#define IO_EVENT_SELECTOR_URING_UDATA_INTERRUPT ((__u64) -2)
|
565
|
+
|
551
566
|
static inline
|
552
567
|
unsigned select_process_completions(struct io_uring *ring) {
|
553
568
|
unsigned completed = 0;
|
@@ -563,6 +578,11 @@ unsigned select_process_completions(struct io_uring *ring) {
|
|
563
578
|
continue;
|
564
579
|
}
|
565
580
|
|
581
|
+
if (cqe->user_data == IO_EVENT_SELECTOR_URING_UDATA_INTERRUPT) {
|
582
|
+
io_uring_cq_advance(ring, 1);
|
583
|
+
IO_Event_Interrupt_clear();
|
584
|
+
}
|
585
|
+
|
566
586
|
VALUE fiber = (VALUE)cqe->user_data;
|
567
587
|
VALUE result = RB_INT2NUM(cqe->res);
|
568
588
|
|
@@ -587,7 +607,7 @@ VALUE IO_Event_Selector_URing_select(VALUE self, VALUE duration) {
|
|
587
607
|
int ready = IO_Event_Selector_queue_flush(&data->backend);
|
588
608
|
|
589
609
|
int result = select_process_completions(&data->ring);
|
590
|
-
|
610
|
+
|
591
611
|
// If the ready list was empty and we didn't process any completions:
|
592
612
|
if (!ready && result == 0) {
|
593
613
|
// We might need to wait for events:
|
@@ -605,7 +625,7 @@ VALUE IO_Event_Selector_URing_select(VALUE self, VALUE duration) {
|
|
605
625
|
// The timeout specified required "nonblocking" behaviour so we just flush the SQ if required:
|
606
626
|
io_uring_submit_flush(data);
|
607
627
|
}
|
608
|
-
|
628
|
+
|
609
629
|
// After waiting/flushing the SQ, check if there are any completions:
|
610
630
|
result = select_process_completions(&data->ring);
|
611
631
|
}
|
@@ -613,6 +633,33 @@ VALUE IO_Event_Selector_URing_select(VALUE self, VALUE duration) {
|
|
613
633
|
return RB_INT2NUM(result);
|
614
634
|
}
|
615
635
|
|
636
|
+
VALUE IO_Event_Selector_URing_wakeup(VALUE self) {
|
637
|
+
struct IO_Event_Selector_KQueue *data = NULL;
|
638
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, data);
|
639
|
+
|
640
|
+
// If we are blocking, we can schedule a nop event to wake up the selector:
|
641
|
+
if (data->blocked) {
|
642
|
+
struct io_uring_sqe *sqe = NULL;
|
643
|
+
|
644
|
+
while (true) {
|
645
|
+
sqe = io_uring_get_sqe(&data->ring);
|
646
|
+
if (sqe) break;
|
647
|
+
|
648
|
+
rb_thread_schedule();
|
649
|
+
|
650
|
+
// It's possible we became unblocked already, so we can assume the selector has already cycled at least once:
|
651
|
+
if (!data->blocked) return Qfalse;
|
652
|
+
}
|
653
|
+
|
654
|
+
io_uring_prep_nop(sqe);
|
655
|
+
io_uring_submit(&backend->ring);
|
656
|
+
|
657
|
+
return Qtrue;
|
658
|
+
}
|
659
|
+
|
660
|
+
return Qfalse;
|
661
|
+
}
|
662
|
+
|
616
663
|
void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
|
617
664
|
IO_Event_Selector_URing = rb_define_class_under(IO_Event_Selector, "URing", rb_cObject);
|
618
665
|
rb_gc_register_mark_object(IO_Event_Selector_URing);
|
@@ -620,6 +667,8 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
|
|
620
667
|
rb_define_alloc_func(IO_Event_Selector_URing, IO_Event_Selector_URing_allocate);
|
621
668
|
rb_define_method(IO_Event_Selector_URing, "initialize", IO_Event_Selector_URing_initialize, 1);
|
622
669
|
|
670
|
+
rb_define_method(IO_Event_Selector_URing, "loop", IO_Event_Selector_URing_loop, 1);
|
671
|
+
|
623
672
|
rb_define_method(IO_Event_Selector_URing, "transfer", IO_Event_Selector_URing_transfer, 0);
|
624
673
|
rb_define_method(IO_Event_Selector_URing, "resume", IO_Event_Selector_URing_resume, -1);
|
625
674
|
rb_define_method(IO_Event_Selector_URing, "yield", IO_Event_Selector_URing_yield, 0);
|
@@ -629,6 +678,7 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
|
|
629
678
|
rb_define_method(IO_Event_Selector_URing, "ready?", IO_Event_Selector_URing_ready_p, 0);
|
630
679
|
|
631
680
|
rb_define_method(IO_Event_Selector_URing, "select", IO_Event_Selector_URing_select, 1);
|
681
|
+
rb_define_method(IO_Event_Selector_URing, "wakeup", IO_Event_Selector_URing_wakeup, 0);
|
632
682
|
rb_define_method(IO_Event_Selector_URing, "close", IO_Event_Selector_URing_close, 0);
|
633
683
|
|
634
684
|
rb_define_method(IO_Event_Selector_URing, "io_wait", IO_Event_Selector_URing_io_wait, 3);
|
data/ext/kqueue.o
CHANGED
Binary file
|
data/ext/mkmf.log
CHANGED
@@ -113,6 +113,22 @@ checked program was:
|
|
113
113
|
|
114
114
|
--------------------
|
115
115
|
|
116
|
+
have_header: checking for sys/eventfd.h... -------------------- no
|
117
|
+
|
118
|
+
"clang -E -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0/arm64-darwin21 -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0/ruby/backward -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0 -I. -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe -Wall conftest.c -o conftest.i"
|
119
|
+
conftest.c:3:10: fatal error: 'sys/eventfd.h' file not found
|
120
|
+
#include <sys/eventfd.h>
|
121
|
+
^~~~~~~~~~~~~~~
|
122
|
+
1 error generated.
|
123
|
+
checked program was:
|
124
|
+
/* begin */
|
125
|
+
1: #include "ruby.h"
|
126
|
+
2:
|
127
|
+
3: #include <sys/eventfd.h>
|
128
|
+
/* end */
|
129
|
+
|
130
|
+
--------------------
|
131
|
+
|
116
132
|
have_func: checking for rb_io_descriptor()... -------------------- no
|
117
133
|
|
118
134
|
"clang -fdeclspec -o conftest -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0/arm64-darwin21 -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0/ruby/backward -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0 -I. -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe -Wall conftest.c -L. -L/Users/samuel/.rubies/ruby-3.0.3/lib -L/opt/local/lib -L. -fstack-protector-strong -L/opt/local/lib -m64 -lruby.3.0-static -framework Security -framework Foundation -lpthread -lgmp -ldl -lobjc "
|
@@ -141,7 +157,7 @@ checked program was:
|
|
141
157
|
"clang -fdeclspec -o conftest -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0/arm64-darwin21 -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0/ruby/backward -I/Users/samuel/.rubies/ruby-3.0.3/include/ruby-3.0.0 -I. -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wmisleading-indentation -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe -Wall conftest.c -L. -L/Users/samuel/.rubies/ruby-3.0.3/lib -L/opt/local/lib -L. -fstack-protector-strong -L/opt/local/lib -m64 -lruby.3.0-static -framework Security -framework Foundation -lpthread -lgmp -ldl -lobjc "
|
142
158
|
Undefined symbols for architecture arm64:
|
143
159
|
"_rb_io_descriptor", referenced from:
|
144
|
-
_t in conftest-
|
160
|
+
_t in conftest-3b24c5.o
|
145
161
|
ld: symbol(s) not found for architecture arm64
|
146
162
|
clang: error: linker command failed with exit code 1 (use -v to see invocation)
|
147
163
|
checked program was:
|
@@ -28,6 +28,14 @@ module IO::Event
|
|
28
28
|
@readable = {}
|
29
29
|
@writable = {}
|
30
30
|
@priority = {}
|
31
|
+
|
32
|
+
unless Fiber.current == selector.loop
|
33
|
+
raise "Selector must be initialized on event loop fiber!"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def wakeup
|
38
|
+
@selector.wakeup
|
31
39
|
end
|
32
40
|
|
33
41
|
def close
|
@@ -86,6 +94,10 @@ module IO::Event
|
|
86
94
|
end
|
87
95
|
|
88
96
|
def select(duration = nil)
|
97
|
+
unless Fiber.current == @selector.loop
|
98
|
+
raise "Selector must be run on event loop fiber!"
|
99
|
+
end
|
100
|
+
|
89
101
|
@selector.select(duration)
|
90
102
|
end
|
91
103
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
+
#
|
3
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
# of this software and associated documentation files (the "Software"), to deal
|
5
|
+
# in the Software without restriction, including without limitation the rights
|
6
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
# copies of the Software, and to permit persons to whom the Software is
|
8
|
+
# furnished to do so, subject to the following conditions:
|
9
|
+
#
|
10
|
+
# The above copyright notice and this permission notice shall be included in
|
11
|
+
# all copies or substantial portions of the Software.
|
12
|
+
#
|
13
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
# THE SOFTWARE.
|
20
|
+
|
21
|
+
require_relative 'selector'
|
22
|
+
|
23
|
+
module IO::Event
|
24
|
+
# A thread safe synchronisation primative.
|
25
|
+
class Interrupt
|
26
|
+
def self.attach(selector)
|
27
|
+
self.new(selector)
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(selector)
|
31
|
+
@selector = selector
|
32
|
+
@input, @output = ::IO.pipe
|
33
|
+
|
34
|
+
@fiber = Fiber.new do
|
35
|
+
while true
|
36
|
+
if @selector.io_wait(@fiber, @input, READABLE)
|
37
|
+
@input.read_nonblock(1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@fiber.transfer
|
43
|
+
end
|
44
|
+
|
45
|
+
# Send a sigle byte interrupt.
|
46
|
+
def signal
|
47
|
+
@output.write('.')
|
48
|
+
@output.flush
|
49
|
+
end
|
50
|
+
|
51
|
+
def close
|
52
|
+
@input.close
|
53
|
+
@output.close
|
54
|
+
# @fiber.raise(::Interrupt)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private_constant :Interrupt
|
59
|
+
end
|
@@ -18,19 +18,34 @@
|
|
18
18
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
19
|
# THE SOFTWARE.
|
20
20
|
|
21
|
+
require_relative '../interrupt'
|
22
|
+
|
21
23
|
module IO::Event
|
22
24
|
module Selector
|
23
25
|
class Select
|
24
26
|
def initialize(loop)
|
25
27
|
@loop = loop
|
26
28
|
|
27
|
-
@readable =
|
28
|
-
@writable =
|
29
|
+
@readable = Hash.new.compare_by_identity
|
30
|
+
@writable = Hash.new.compare_by_identity
|
31
|
+
|
32
|
+
@blocked = false
|
29
33
|
|
30
34
|
@ready = Queue.new
|
35
|
+
@interrupt = Interrupt.attach(self)
|
36
|
+
end
|
37
|
+
|
38
|
+
attr :loop
|
39
|
+
|
40
|
+
def wakeup
|
41
|
+
if @blocked
|
42
|
+
@interrupt.signal
|
43
|
+
end
|
31
44
|
end
|
32
45
|
|
33
46
|
def close
|
47
|
+
@interrupt.close
|
48
|
+
|
34
49
|
@loop = nil
|
35
50
|
@readable = nil
|
36
51
|
@writable = nil
|
@@ -193,10 +208,14 @@ module IO::Event
|
|
193
208
|
|
194
209
|
def select(duration = nil)
|
195
210
|
if pop_ready
|
211
|
+
# If we have popped items from the ready list, they may influence the duration calculation, so we don't delay the event loop:
|
196
212
|
duration = 0
|
197
213
|
end
|
198
214
|
|
215
|
+
# The GVL ensures this is sufficiently synchronised for `#wakeup` to work correctly.
|
216
|
+
@blocked = true
|
199
217
|
readable, writable, _ = ::IO.select(@readable.keys, @writable.keys, nil, duration)
|
218
|
+
@blocked = false
|
200
219
|
|
201
220
|
ready = Hash.new(0)
|
202
221
|
|
@@ -213,6 +232,8 @@ module IO::Event
|
|
213
232
|
ready.each do |fiber, events|
|
214
233
|
fiber.transfer(events) if fiber.alive?
|
215
234
|
end
|
235
|
+
|
236
|
+
return ready.size
|
216
237
|
end
|
217
238
|
end
|
218
239
|
end
|
data/lib/io/event/selector.rb
CHANGED
@@ -22,9 +22,9 @@ require_relative 'selector/select'
|
|
22
22
|
|
23
23
|
module IO::Event
|
24
24
|
# These constants are the same as those defined in IO.
|
25
|
-
READABLE =
|
26
|
-
PRIORITY =
|
27
|
-
WRITABLE =
|
25
|
+
READABLE = IO::READABLE
|
26
|
+
PRIORITY = IO::PRIORITY
|
27
|
+
WRITABLE = IO::WRITABLE
|
28
28
|
|
29
29
|
module Selector
|
30
30
|
def self.default(env = ENV)
|
data/lib/io/event/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io-event
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bake
|
@@ -66,20 +66,6 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '3.0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: timers
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
69
|
description:
|
84
70
|
email:
|
85
71
|
executables: []
|
@@ -92,8 +78,11 @@ files:
|
|
92
78
|
- ext/event.o
|
93
79
|
- ext/extconf.h
|
94
80
|
- ext/extconf.rb
|
81
|
+
- ext/interrupt.o
|
95
82
|
- ext/io/event/event.c
|
96
83
|
- ext/io/event/event.h
|
84
|
+
- ext/io/event/interrupt.c
|
85
|
+
- ext/io/event/interrupt.h
|
97
86
|
- ext/io/event/selector/epoll.c
|
98
87
|
- ext/io/event/selector/epoll.h
|
99
88
|
- ext/io/event/selector/kqueue.c
|
@@ -108,6 +97,7 @@ files:
|
|
108
97
|
- ext/selector.o
|
109
98
|
- lib/io/event.rb
|
110
99
|
- lib/io/event/debug/selector.rb
|
100
|
+
- lib/io/event/interrupt.rb
|
111
101
|
- lib/io/event/selector.rb
|
112
102
|
- lib/io/event/selector/select.rb
|
113
103
|
- lib/io/event/version.rb
|