io-event 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|