io-event 1.3.1 → 1.3.3
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/ext/io/event/selector/epoll.c +51 -20
- data/ext/io/event/selector/kqueue.c +54 -26
- data/ext/io/event/selector/list.h +2 -1
- data/ext/io/event/selector/selector.c +2 -7
- data/ext/io/event/selector/selector.h +3 -2
- data/ext/io/event/selector/uring.c +55 -42
- data/lib/io/event/selector/select.rb +65 -1
- data/lib/io/event/support.rb +11 -0
- data/lib/io/event/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +2 -2
- 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: 3362ef0fb1bd825601c2476c06e99d32aa911a4e66b189b1518f40b6246b1ab6
|
4
|
+
data.tar.gz: a41015ab836dd0e28656427001882a87ba26a424395babb81aecd0e6d07d5fdd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e1563b616697985daed4bb585bfdeaec00f6dfbaa9f377e99b278a9070f5ee32b475136e0f8f7626e4238a0d623a0bdb745ef03a612ec0de4b7f2eb9ef2f4510
|
7
|
+
data.tar.gz: d061bea14bd722ae77eddc68e81d0c4138a5de1b1b12e6fce22a45bc62391c7bf3d9dd25cf0f876361309b04d9e480a06c9752128103c999a504d01e6ffb78d3
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -446,6 +446,7 @@ struct process_wait_arguments {
|
|
446
446
|
struct IO_Event_Selector_EPoll *selector;
|
447
447
|
struct IO_Event_Selector_EPoll_Waiting *waiting;
|
448
448
|
int pid;
|
449
|
+
int flags;
|
449
450
|
int descriptor;
|
450
451
|
};
|
451
452
|
|
@@ -456,7 +457,7 @@ VALUE process_wait_transfer(VALUE _arguments) {
|
|
456
457
|
IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
|
457
458
|
|
458
459
|
if (arguments->waiting->ready) {
|
459
|
-
return IO_Event_Selector_process_status_wait(arguments->pid);
|
460
|
+
return IO_Event_Selector_process_status_wait(arguments->pid, arguments->flags);
|
460
461
|
} else {
|
461
462
|
return Qfalse;
|
462
463
|
}
|
@@ -480,7 +481,7 @@ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
480
481
|
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
|
481
482
|
|
482
483
|
pid_t pid = NUM2PIDT(_pid);
|
483
|
-
|
484
|
+
int flags = NUM2INT(_flags);
|
484
485
|
|
485
486
|
int descriptor = pidfd_open(pid, 0);
|
486
487
|
|
@@ -506,6 +507,7 @@ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
506
507
|
struct process_wait_arguments process_wait_arguments = {
|
507
508
|
.selector = selector,
|
508
509
|
.pid = pid,
|
510
|
+
.flags = flags,
|
509
511
|
.descriptor = descriptor,
|
510
512
|
.waiting = &waiting,
|
511
513
|
};
|
@@ -802,9 +804,11 @@ struct select_arguments {
|
|
802
804
|
|
803
805
|
int count;
|
804
806
|
struct epoll_event events[EPOLL_MAX_EVENTS];
|
805
|
-
|
807
|
+
|
806
808
|
struct timespec * timeout;
|
807
809
|
struct timespec storage;
|
810
|
+
|
811
|
+
struct IO_Event_List saved;
|
808
812
|
};
|
809
813
|
|
810
814
|
static int make_timeout_ms(struct timespec * timeout) {
|
@@ -881,7 +885,7 @@ void select_internal_with_gvl(struct select_arguments *arguments) {
|
|
881
885
|
}
|
882
886
|
|
883
887
|
static
|
884
|
-
int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, const struct epoll_event *event)
|
888
|
+
int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, const struct epoll_event *event, struct IO_Event_List *saved)
|
885
889
|
{
|
886
890
|
int descriptor = event->data.fd;
|
887
891
|
|
@@ -891,29 +895,32 @@ int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, con
|
|
891
895
|
struct IO_Event_Selector_EPoll_Descriptor *epoll_descriptor = IO_Event_Selector_EPoll_Descriptor_lookup(selector, descriptor);
|
892
896
|
struct IO_Event_List *list = &epoll_descriptor->list;
|
893
897
|
struct IO_Event_List *node = list->tail;
|
894
|
-
struct IO_Event_List saved = {NULL, NULL};
|
895
898
|
|
896
899
|
// Reset the events back to 0 so that we can re-arm if necessary:
|
897
900
|
epoll_descriptor->waiting_events = 0;
|
898
901
|
|
902
|
+
if (DEBUG) fprintf(stderr, "IO_Event_Selector_EPoll_handle: descriptor=%d, ready_events=%d epoll_descriptor=%p\n", descriptor, ready_events, epoll_descriptor);
|
903
|
+
|
899
904
|
// It's possible (but unlikely) that the address of list will changing during iteration.
|
900
905
|
while (node != list) {
|
906
|
+
if (DEBUG) fprintf(stderr, "IO_Event_Selector_EPoll_handle: node=%p list=%p type=%p\n", node, list, node->type);
|
907
|
+
|
901
908
|
struct IO_Event_Selector_EPoll_Waiting *waiting = (struct IO_Event_Selector_EPoll_Waiting *)node;
|
902
909
|
|
903
910
|
// Compute the intersection of the events we are waiting for and the events that occured:
|
904
911
|
enum IO_Event matching_events = waiting->events & ready_events;
|
905
912
|
|
906
|
-
if (DEBUG) fprintf(stderr, "IO_Event_Selector_EPoll_handle: descriptor=%d, ready_events=%d, matching_events=%d\n", descriptor, ready_events, matching_events);
|
913
|
+
if (DEBUG) fprintf(stderr, "IO_Event_Selector_EPoll_handle: descriptor=%d, ready_events=%d, waiting_events=%d, matching_events=%d\n", descriptor, ready_events, waiting->events, matching_events);
|
907
914
|
|
908
915
|
if (matching_events) {
|
909
|
-
IO_Event_List_append(node,
|
916
|
+
IO_Event_List_append(node, saved);
|
910
917
|
|
911
918
|
// Resume the fiber:
|
912
919
|
waiting->ready = matching_events;
|
913
920
|
IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
|
914
921
|
|
915
|
-
node = saved
|
916
|
-
IO_Event_List_pop(
|
922
|
+
node = saved->tail;
|
923
|
+
IO_Event_List_pop(saved);
|
917
924
|
} else {
|
918
925
|
// We are still waiting for the events:
|
919
926
|
epoll_descriptor->waiting_events |= waiting->events;
|
@@ -924,6 +931,36 @@ int IO_Event_Selector_EPoll_handle(struct IO_Event_Selector_EPoll *selector, con
|
|
924
931
|
return IO_Event_Selector_EPoll_Descriptor_update(selector, epoll_descriptor->io, descriptor, epoll_descriptor);
|
925
932
|
}
|
926
933
|
|
934
|
+
static
|
935
|
+
VALUE select_handle_events(VALUE _arguments)
|
936
|
+
{
|
937
|
+
struct select_arguments *arguments = (struct select_arguments *)_arguments;
|
938
|
+
struct IO_Event_Selector_EPoll *selector = arguments->selector;
|
939
|
+
|
940
|
+
for (int i = 0; i < arguments->count; i += 1) {
|
941
|
+
const struct epoll_event *event = &arguments->events[i];
|
942
|
+
if (DEBUG) fprintf(stderr, "-> fd=%d events=%d\n", event->data.fd, event->events);
|
943
|
+
|
944
|
+
if (event->data.fd >= 0) {
|
945
|
+
IO_Event_Selector_EPoll_handle(selector, event, &arguments->saved);
|
946
|
+
} else {
|
947
|
+
IO_Event_Interrupt_clear(&selector->interrupt);
|
948
|
+
}
|
949
|
+
}
|
950
|
+
|
951
|
+
return INT2NUM(arguments->count);
|
952
|
+
}
|
953
|
+
|
954
|
+
static
|
955
|
+
VALUE select_handle_events_ensure(VALUE _arguments)
|
956
|
+
{
|
957
|
+
struct select_arguments *arguments = (struct select_arguments *)_arguments;
|
958
|
+
|
959
|
+
IO_Event_List_free(&arguments->saved);
|
960
|
+
|
961
|
+
return Qnil;
|
962
|
+
}
|
963
|
+
|
927
964
|
// TODO This function is not re-entrant and we should document and assert as such.
|
928
965
|
VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
929
966
|
struct IO_Event_Selector_EPoll *selector = NULL;
|
@@ -937,6 +974,7 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
|
937
974
|
.tv_sec = 0,
|
938
975
|
.tv_nsec = 0
|
939
976
|
},
|
977
|
+
.saved = {},
|
940
978
|
};
|
941
979
|
|
942
980
|
arguments.timeout = &arguments.storage;
|
@@ -958,18 +996,11 @@ VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
|
|
958
996
|
}
|
959
997
|
}
|
960
998
|
|
961
|
-
|
962
|
-
|
963
|
-
|
964
|
-
|
965
|
-
if (event->data.fd >= 0) {
|
966
|
-
IO_Event_Selector_EPoll_handle(selector, event);
|
967
|
-
} else {
|
968
|
-
IO_Event_Interrupt_clear(&selector->interrupt);
|
969
|
-
}
|
999
|
+
if (arguments.count) {
|
1000
|
+
return rb_ensure(select_handle_events, (VALUE)&arguments, select_handle_events_ensure, (VALUE)&arguments);
|
1001
|
+
} else {
|
1002
|
+
return RB_INT2NUM(0);
|
970
1003
|
}
|
971
|
-
|
972
|
-
return INT2NUM(arguments.count);
|
973
1004
|
}
|
974
1005
|
|
975
1006
|
VALUE IO_Event_Selector_EPoll_wakeup(VALUE self) {
|
@@ -433,6 +433,7 @@ struct process_wait_arguments {
|
|
433
433
|
struct IO_Event_Selector_KQueue *selector;
|
434
434
|
struct IO_Event_Selector_KQueue_Waiting *waiting;
|
435
435
|
pid_t pid;
|
436
|
+
int flags;
|
436
437
|
};
|
437
438
|
|
438
439
|
static
|
@@ -461,7 +462,7 @@ VALUE process_wait_transfer(VALUE _arguments) {
|
|
461
462
|
|
462
463
|
if (arguments->waiting->ready) {
|
463
464
|
process_prewait(arguments->pid);
|
464
|
-
return IO_Event_Selector_process_status_wait(arguments->pid);
|
465
|
+
return IO_Event_Selector_process_status_wait(arguments->pid, arguments->flags);
|
465
466
|
} else {
|
466
467
|
return Qfalse;
|
467
468
|
}
|
@@ -483,6 +484,7 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
483
484
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
484
485
|
|
485
486
|
pid_t pid = NUM2PIDT(_pid);
|
487
|
+
int flags = NUM2INT(_flags);
|
486
488
|
|
487
489
|
struct IO_Event_Selector_KQueue_Waiting waiting = {
|
488
490
|
.list = {.type = &IO_Event_Selector_KQueue_process_wait_list_type},
|
@@ -494,6 +496,7 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
494
496
|
.selector = selector,
|
495
497
|
.waiting = &waiting,
|
496
498
|
.pid = pid,
|
499
|
+
.flags = flags,
|
497
500
|
};
|
498
501
|
|
499
502
|
int result = IO_Event_Selector_KQueue_Waiting_register(selector, pid, &waiting);
|
@@ -502,7 +505,7 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
502
505
|
if (errno == ESRCH) {
|
503
506
|
process_prewait(pid);
|
504
507
|
|
505
|
-
return IO_Event_Selector_process_status_wait(pid);
|
508
|
+
return IO_Event_Selector_process_status_wait(pid, flags);
|
506
509
|
}
|
507
510
|
|
508
511
|
rb_sys_fail("IO_Event_Selector_KQueue_process_wait:IO_Event_Selector_KQueue_Waiting_register");
|
@@ -818,6 +821,8 @@ struct select_arguments {
|
|
818
821
|
|
819
822
|
struct timespec storage;
|
820
823
|
struct timespec *timeout;
|
824
|
+
|
825
|
+
struct IO_Event_List saved;
|
821
826
|
};
|
822
827
|
|
823
828
|
static
|
@@ -859,7 +864,7 @@ void select_internal_with_gvl(struct select_arguments *arguments) {
|
|
859
864
|
}
|
860
865
|
|
861
866
|
static
|
862
|
-
int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, uintptr_t identifier, struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor)
|
867
|
+
int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, uintptr_t identifier, struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor, struct IO_Event_List *saved)
|
863
868
|
{
|
864
869
|
// This is the mask of all events that occured for the given descriptor:
|
865
870
|
enum IO_Event ready_events = kqueue_descriptor->ready_events;
|
@@ -874,7 +879,6 @@ int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, u
|
|
874
879
|
|
875
880
|
struct IO_Event_List *list = &kqueue_descriptor->list;
|
876
881
|
struct IO_Event_List *node = list->tail;
|
877
|
-
struct IO_Event_List saved = {NULL, NULL};
|
878
882
|
|
879
883
|
// Reset the events back to 0 so that we can re-arm if necessary:
|
880
884
|
kqueue_descriptor->waiting_events = 0;
|
@@ -888,13 +892,13 @@ int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, u
|
|
888
892
|
if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_handle: identifier=%lu, ready_events=%d, matching_events=%d\n", identifier, ready_events, matching_events);
|
889
893
|
|
890
894
|
if (matching_events) {
|
891
|
-
IO_Event_List_append(node,
|
895
|
+
IO_Event_List_append(node, saved);
|
892
896
|
|
893
897
|
waiting->ready = matching_events;
|
894
898
|
IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
|
895
899
|
|
896
|
-
node = saved
|
897
|
-
IO_Event_List_pop(
|
900
|
+
node = saved->tail;
|
901
|
+
IO_Event_List_pop(saved);
|
898
902
|
} else {
|
899
903
|
kqueue_descriptor->waiting_events |= waiting->events;
|
900
904
|
node = node->tail;
|
@@ -904,6 +908,43 @@ int IO_Event_Selector_KQueue_handle(struct IO_Event_Selector_KQueue *selector, u
|
|
904
908
|
return IO_Event_Selector_KQueue_Descriptor_update(selector, identifier, kqueue_descriptor);
|
905
909
|
}
|
906
910
|
|
911
|
+
static
|
912
|
+
VALUE select_handle_events(VALUE _arguments)
|
913
|
+
{
|
914
|
+
struct select_arguments *arguments = (struct select_arguments *)_arguments;
|
915
|
+
struct IO_Event_Selector_KQueue *selector = arguments->selector;
|
916
|
+
|
917
|
+
for (int i = 0; i < arguments->count; i += 1) {
|
918
|
+
if (arguments->events[i].udata) {
|
919
|
+
struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor = arguments->events[i].udata;
|
920
|
+
kqueue_descriptor->ready_events |= events_from_kevent_filter(arguments->events[i].filter);
|
921
|
+
}
|
922
|
+
}
|
923
|
+
|
924
|
+
for (int i = 0; i < arguments->count; i += 1) {
|
925
|
+
if (arguments->events[i].udata) {
|
926
|
+
struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor = arguments->events[i].udata;
|
927
|
+
IO_Event_Selector_KQueue_handle(selector, arguments->events[i].ident, kqueue_descriptor, &arguments->saved);
|
928
|
+
} else {
|
929
|
+
#ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
|
930
|
+
IO_Event_Interrupt_clear(&selector->interrupt);
|
931
|
+
#endif
|
932
|
+
}
|
933
|
+
}
|
934
|
+
|
935
|
+
return RB_INT2NUM(arguments->count);
|
936
|
+
}
|
937
|
+
|
938
|
+
static
|
939
|
+
VALUE select_handle_events_ensure(VALUE _arguments)
|
940
|
+
{
|
941
|
+
struct select_arguments *arguments = (struct select_arguments *)_arguments;
|
942
|
+
|
943
|
+
IO_Event_List_free(&arguments->saved);
|
944
|
+
|
945
|
+
return Qnil;
|
946
|
+
}
|
947
|
+
|
907
948
|
VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
908
949
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
909
950
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
@@ -916,7 +957,8 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
916
957
|
.storage = {
|
917
958
|
.tv_sec = 0,
|
918
959
|
.tv_nsec = 0
|
919
|
-
}
|
960
|
+
},
|
961
|
+
.saved = {},
|
920
962
|
};
|
921
963
|
|
922
964
|
arguments.timeout = &arguments.storage;
|
@@ -948,25 +990,11 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
948
990
|
}
|
949
991
|
}
|
950
992
|
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
}
|
956
|
-
}
|
957
|
-
|
958
|
-
for (int i = 0; i < arguments.count; i += 1) {
|
959
|
-
if (arguments.events[i].udata) {
|
960
|
-
struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor = arguments.events[i].udata;
|
961
|
-
IO_Event_Selector_KQueue_handle(selector, arguments.events[i].ident, kqueue_descriptor);
|
962
|
-
} else {
|
963
|
-
#ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
|
964
|
-
IO_Event_Interrupt_clear(&selector->interrupt);
|
965
|
-
#endif
|
966
|
-
}
|
993
|
+
if (arguments.count) {
|
994
|
+
return rb_ensure(select_handle_events, (VALUE)&arguments, select_handle_events_ensure, (VALUE)&arguments);
|
995
|
+
} else {
|
996
|
+
return RB_INT2NUM(0);
|
967
997
|
}
|
968
|
-
|
969
|
-
return RB_INT2NUM(arguments.count);
|
970
998
|
}
|
971
999
|
|
972
1000
|
VALUE IO_Event_Selector_KQueue_wakeup(VALUE self) {
|
@@ -21,6 +21,7 @@ inline static void IO_Event_List_initialize(struct IO_Event_List *list)
|
|
21
21
|
inline static void IO_Event_List_clear(struct IO_Event_List *list)
|
22
22
|
{
|
23
23
|
list->head = list->tail = NULL;
|
24
|
+
list->type = 0;
|
24
25
|
}
|
25
26
|
|
26
27
|
// Append an item to the end of the list.
|
@@ -64,7 +65,7 @@ inline static void IO_Event_List_pop(struct IO_Event_List *node)
|
|
64
65
|
|
65
66
|
inline static void IO_Event_List_free(struct IO_Event_List *node)
|
66
67
|
{
|
67
|
-
if (node->head
|
68
|
+
if (node->head && node->tail) {
|
68
69
|
IO_Event_List_pop(node);
|
69
70
|
}
|
70
71
|
}
|
@@ -25,10 +25,6 @@ static const int DEBUG = 0;
|
|
25
25
|
|
26
26
|
static ID id_transfer, id_alive_p;
|
27
27
|
|
28
|
-
#ifndef HAVE_RB_PROCESS_STATUS_WAIT
|
29
|
-
static VALUE process_wnohang;
|
30
|
-
#endif
|
31
|
-
|
32
28
|
VALUE IO_Event_Selector_fiber_transfer(VALUE fiber, int argc, VALUE *argv) {
|
33
29
|
// TODO Consider introducing something like `rb_fiber_scheduler_transfer(...)`.
|
34
30
|
#ifdef HAVE__RB_FIBER_TRANSFER
|
@@ -76,9 +72,9 @@ int IO_Event_Selector_io_descriptor(VALUE io) {
|
|
76
72
|
static ID id_wait;
|
77
73
|
static VALUE rb_Process_Status = Qnil;
|
78
74
|
|
79
|
-
VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid)
|
75
|
+
VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid, int flags)
|
80
76
|
{
|
81
|
-
return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid),
|
77
|
+
return rb_funcall(rb_Process_Status, id_wait, 2, PIDT2NUM(pid), INT2NUM(flags | WNOHANG));
|
82
78
|
}
|
83
79
|
#endif
|
84
80
|
|
@@ -157,7 +153,6 @@ void Init_IO_Event_Selector(VALUE IO_Event_Selector) {
|
|
157
153
|
|
158
154
|
#ifndef HAVE_RB_PROCESS_STATUS_WAIT
|
159
155
|
id_wait = rb_intern("wait");
|
160
|
-
process_wnohang = rb_const_get(rb_mProcess, rb_intern("WNOHANG"));
|
161
156
|
rb_Process_Status = rb_const_get_at(rb_mProcess, rb_intern("Status"));
|
162
157
|
rb_gc_register_mark_object(rb_Process_Status);
|
163
158
|
#endif
|
@@ -66,10 +66,11 @@ VALUE IO_Event_Selector_fiber_raise(VALUE fiber, int argc, VALUE *argv);
|
|
66
66
|
int IO_Event_Selector_io_descriptor(VALUE io);
|
67
67
|
#endif
|
68
68
|
|
69
|
+
// Reap a process without hanging.
|
69
70
|
#ifdef HAVE_RB_PROCESS_STATUS_WAIT
|
70
|
-
#define IO_Event_Selector_process_status_wait(pid) rb_process_status_wait(pid)
|
71
|
+
#define IO_Event_Selector_process_status_wait(pid, flags) rb_process_status_wait(pid, flags | WNOHANG)
|
71
72
|
#else
|
72
|
-
VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid);
|
73
|
+
VALUE IO_Event_Selector_process_status_wait(rb_pid_t pid, int flags);
|
73
74
|
#endif
|
74
75
|
|
75
76
|
int IO_Event_Selector_nonblock_set(int file_descriptor);
|
@@ -326,6 +326,32 @@ VALUE IO_Event_Selector_URing_ready_p(VALUE self) {
|
|
326
326
|
|
327
327
|
#pragma mark - Submission Queue
|
328
328
|
|
329
|
+
static
|
330
|
+
void IO_Event_Selector_URing_dump_completion_queue(struct IO_Event_Selector_URing *selector)
|
331
|
+
{
|
332
|
+
struct io_uring *ring = &selector->ring;
|
333
|
+
unsigned head;
|
334
|
+
struct io_uring_cqe *cqe;
|
335
|
+
|
336
|
+
if (DEBUG) {
|
337
|
+
int first = 1;
|
338
|
+
io_uring_for_each_cqe(ring, head, cqe) {
|
339
|
+
if (!first) {
|
340
|
+
fprintf(stderr, ", ");
|
341
|
+
}
|
342
|
+
else {
|
343
|
+
fprintf(stderr, "CQ: [");
|
344
|
+
first = 0;
|
345
|
+
}
|
346
|
+
|
347
|
+
fprintf(stderr, "%d:%p", (int)cqe->res, (void*)cqe->user_data);
|
348
|
+
}
|
349
|
+
if (!first) {
|
350
|
+
fprintf(stderr, "]\n");
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
|
329
355
|
// Flush the submission queue if pending operations are present.
|
330
356
|
static
|
331
357
|
int io_uring_submit_flush(struct IO_Event_Selector_URing *selector) {
|
@@ -345,19 +371,24 @@ int io_uring_submit_flush(struct IO_Event_Selector_URing *selector) {
|
|
345
371
|
return result;
|
346
372
|
}
|
347
373
|
|
374
|
+
if (DEBUG) {
|
375
|
+
IO_Event_Selector_URing_dump_completion_queue(selector);
|
376
|
+
}
|
377
|
+
|
348
378
|
return 0;
|
349
379
|
}
|
350
380
|
|
351
381
|
// Immediately flush the submission queue, yielding to the event loop if it was not successful.
|
352
382
|
static
|
353
383
|
int io_uring_submit_now(struct IO_Event_Selector_URing *selector) {
|
354
|
-
if (DEBUG
|
355
|
-
|
384
|
+
if (DEBUG) fprintf(stderr, "io_uring_submit_now(pending=%ld)\n", selector->pending);
|
385
|
+
|
356
386
|
while (true) {
|
357
387
|
int result = io_uring_submit(&selector->ring);
|
358
388
|
|
359
389
|
if (result >= 0) {
|
360
390
|
selector->pending = 0;
|
391
|
+
if (DEBUG) IO_Event_Selector_URing_dump_completion_queue(selector);
|
361
392
|
return result;
|
362
393
|
}
|
363
394
|
|
@@ -369,12 +400,6 @@ int io_uring_submit_now(struct IO_Event_Selector_URing *selector) {
|
|
369
400
|
}
|
370
401
|
}
|
371
402
|
|
372
|
-
static
|
373
|
-
void IO_Event_Selector_URing_submit_sqe(struct io_uring_sqe *sqe)
|
374
|
-
{
|
375
|
-
if (DEBUG) fprintf(stderr, "IO_Event_Selector_URing_submit_sqe(%p): user_data=%p opcode=%d\n", sqe, (void*)sqe->user_data, sqe->opcode);
|
376
|
-
}
|
377
|
-
|
378
403
|
// Submit a pending operation. This does not submit the operation immediately, but instead defers it to the next call to `io_uring_submit_flush` or `io_uring_submit_now`. This is useful for operations that are not urgent, but should be used with care as it can lead to a deadlock if the submission queue is not flushed.
|
379
404
|
static
|
380
405
|
void io_uring_submit_pending(struct IO_Event_Selector_URing *selector) {
|
@@ -403,6 +428,7 @@ struct process_wait_arguments {
|
|
403
428
|
struct IO_Event_Selector_URing_Waiting *waiting;
|
404
429
|
|
405
430
|
pid_t pid;
|
431
|
+
int flags;
|
406
432
|
int descriptor;
|
407
433
|
};
|
408
434
|
|
@@ -413,7 +439,7 @@ VALUE process_wait_transfer(VALUE _arguments) {
|
|
413
439
|
IO_Event_Selector_fiber_transfer(arguments->selector->backend.loop, 0, NULL);
|
414
440
|
|
415
441
|
if (arguments->waiting->result) {
|
416
|
-
return IO_Event_Selector_process_status_wait(arguments->pid);
|
442
|
+
return IO_Event_Selector_process_status_wait(arguments->pid, arguments->flags);
|
417
443
|
} else {
|
418
444
|
return Qfalse;
|
419
445
|
}
|
@@ -435,6 +461,7 @@ VALUE IO_Event_Selector_URing_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
435
461
|
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
|
436
462
|
|
437
463
|
pid_t pid = NUM2PIDT(_pid);
|
464
|
+
int flags = NUM2INT(_flags);
|
438
465
|
|
439
466
|
int descriptor = pidfd_open(pid, 0);
|
440
467
|
if (descriptor < 0) {
|
@@ -452,15 +479,14 @@ VALUE IO_Event_Selector_URing_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
452
479
|
.selector = selector,
|
453
480
|
.waiting = &waiting,
|
454
481
|
.pid = pid,
|
482
|
+
.flags = flags,
|
455
483
|
.descriptor = descriptor,
|
456
484
|
};
|
457
485
|
|
458
|
-
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
459
|
-
|
460
486
|
if (DEBUG) fprintf(stderr, "IO_Event_Selector_URing_process_wait:io_uring_prep_poll_add(%p)\n", (void*)fiber);
|
487
|
+
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
461
488
|
io_uring_prep_poll_add(sqe, descriptor, POLLIN|POLLHUP|POLLERR);
|
462
489
|
io_uring_sqe_set_data(sqe, completion);
|
463
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
464
490
|
io_uring_submit_pending(selector);
|
465
491
|
|
466
492
|
return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
|
@@ -504,14 +530,12 @@ static
|
|
504
530
|
VALUE io_wait_ensure(VALUE _arguments) {
|
505
531
|
struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
|
506
532
|
|
507
|
-
if (DEBUG) fprintf(stderr, "io_wait_ensure:io_uring_prep_cancel(waiting=%p, completion=%p)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion);
|
508
|
-
|
509
533
|
// If the operation is still in progress, cancel it:
|
510
534
|
if (arguments->waiting->completion) {
|
535
|
+
if (DEBUG) fprintf(stderr, "io_wait_ensure:io_uring_prep_cancel(waiting=%p, completion=%p)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion);
|
511
536
|
struct io_uring_sqe *sqe = io_get_sqe(arguments->selector);
|
512
537
|
io_uring_prep_cancel(sqe, (void*)arguments->waiting->completion, 0);
|
513
538
|
io_uring_sqe_set_data(sqe, NULL);
|
514
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
515
539
|
io_uring_submit_now(arguments->selector);
|
516
540
|
}
|
517
541
|
|
@@ -543,23 +567,20 @@ VALUE IO_Event_Selector_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
|
|
543
567
|
TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
|
544
568
|
|
545
569
|
int descriptor = IO_Event_Selector_io_descriptor(io);
|
546
|
-
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
547
570
|
|
548
571
|
short flags = poll_flags_from_events(NUM2INT(events));
|
549
572
|
|
550
573
|
if (DEBUG) fprintf(stderr, "IO_Event_Selector_URing_io_wait:io_uring_prep_poll_add(descriptor=%d, flags=%d, fiber=%p)\n", descriptor, flags, (void*)fiber);
|
551
574
|
|
552
|
-
io_uring_prep_poll_add(sqe, descriptor, flags);
|
553
|
-
|
554
575
|
struct IO_Event_Selector_URing_Waiting waiting = {
|
555
576
|
.fiber = fiber,
|
556
577
|
};
|
557
578
|
|
558
579
|
struct IO_Event_Selector_URing_Completion *completion = IO_Event_Selector_URing_Completion_acquire(selector, &waiting);
|
559
580
|
|
581
|
+
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
582
|
+
io_uring_prep_poll_add(sqe, descriptor, flags);
|
560
583
|
io_uring_sqe_set_data(sqe, completion);
|
561
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
562
|
-
|
563
584
|
// If we are going to wait, we assume that we are waiting for a while:
|
564
585
|
io_uring_submit_pending(selector);
|
565
586
|
|
@@ -607,13 +628,12 @@ io_read_submit(VALUE _arguments)
|
|
607
628
|
{
|
608
629
|
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
609
630
|
struct IO_Event_Selector_URing *selector = arguments->selector;
|
610
|
-
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
611
631
|
|
612
632
|
if (DEBUG) fprintf(stderr, "io_read_submit:io_uring_prep_read(waiting=%p, completion=%p, descriptor=%d, buffer=%p, length=%ld)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion, arguments->descriptor, arguments->buffer, arguments->length);
|
613
633
|
|
634
|
+
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
614
635
|
io_uring_prep_read(sqe, arguments->descriptor, arguments->buffer, arguments->length, io_seekable(arguments->descriptor));
|
615
636
|
io_uring_sqe_set_data(sqe, arguments->waiting->completion);
|
616
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
617
637
|
io_uring_submit_now(selector);
|
618
638
|
|
619
639
|
IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
|
@@ -627,15 +647,12 @@ io_read_ensure(VALUE _arguments)
|
|
627
647
|
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
628
648
|
struct IO_Event_Selector_URing *selector = arguments->selector;
|
629
649
|
|
630
|
-
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
631
|
-
|
632
|
-
if (DEBUG) fprintf(stderr, "io_read_ensure:io_uring_prep_cancel(waiting=%p, completion=%p)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion);
|
633
|
-
|
634
650
|
// If the operation is still in progress, cancel it:
|
635
651
|
if (arguments->waiting->completion) {
|
652
|
+
if (DEBUG) fprintf(stderr, "io_read_ensure:io_uring_prep_cancel(waiting=%p, completion=%p)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion);
|
653
|
+
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
636
654
|
io_uring_prep_cancel(sqe, (void*)arguments->waiting->completion, 0);
|
637
655
|
io_uring_sqe_set_data(sqe, NULL);
|
638
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
639
656
|
io_uring_submit_now(selector);
|
640
657
|
}
|
641
658
|
|
@@ -732,13 +749,11 @@ io_write_submit(VALUE _argument)
|
|
732
749
|
struct io_write_arguments *arguments = (struct io_write_arguments*)_argument;
|
733
750
|
struct IO_Event_Selector_URing *selector = arguments->selector;
|
734
751
|
|
735
|
-
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
736
|
-
|
737
752
|
if (DEBUG) fprintf(stderr, "io_write_submit:io_uring_prep_write(waiting=%p, completion=%p, descriptor=%d, buffer=%p, length=%ld)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion, arguments->descriptor, arguments->buffer, arguments->length);
|
738
753
|
|
754
|
+
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
739
755
|
io_uring_prep_write(sqe, arguments->descriptor, arguments->buffer, arguments->length, io_seekable(arguments->descriptor));
|
740
756
|
io_uring_sqe_set_data(sqe, arguments->waiting->completion);
|
741
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
742
757
|
io_uring_submit_pending(selector);
|
743
758
|
|
744
759
|
IO_Event_Selector_fiber_transfer(selector->backend.loop, 0, NULL);
|
@@ -752,15 +767,12 @@ io_write_ensure(VALUE _argument)
|
|
752
767
|
struct io_write_arguments *arguments = (struct io_write_arguments*)_argument;
|
753
768
|
struct IO_Event_Selector_URing *selector = arguments->selector;
|
754
769
|
|
755
|
-
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
756
|
-
|
757
|
-
if (DEBUG) fprintf(stderr, "io_write_ensure:io_uring_prep_cancel(waiting=%p, completion=%p)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion);
|
758
|
-
|
759
770
|
// If the operation is still in progress, cancel it:
|
760
771
|
if (arguments->waiting->completion) {
|
772
|
+
if (DEBUG) fprintf(stderr, "io_write_ensure:io_uring_prep_cancel(waiting=%p, completion=%p)\n", (void*)arguments->waiting, (void*)arguments->waiting->completion);
|
773
|
+
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
761
774
|
io_uring_prep_cancel(sqe, (void*)arguments->waiting->completion, 0);
|
762
775
|
io_uring_sqe_set_data(sqe, NULL);
|
763
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
764
776
|
io_uring_submit_now(selector);
|
765
777
|
}
|
766
778
|
|
@@ -859,10 +871,8 @@ VALUE IO_Event_Selector_URing_io_close(VALUE self, VALUE io) {
|
|
859
871
|
|
860
872
|
if (ASYNC_CLOSE) {
|
861
873
|
struct io_uring_sqe *sqe = io_get_sqe(selector);
|
862
|
-
|
863
874
|
io_uring_prep_close(sqe, descriptor);
|
864
875
|
io_uring_sqe_set_data(sqe, NULL);
|
865
|
-
IO_Event_Selector_URing_submit_sqe(sqe);
|
866
876
|
io_uring_submit_now(selector);
|
867
877
|
} else {
|
868
878
|
close(descriptor);
|
@@ -953,7 +963,10 @@ unsigned select_process_completions(struct IO_Event_Selector_URing *selector) {
|
|
953
963
|
unsigned head;
|
954
964
|
struct io_uring_cqe *cqe;
|
955
965
|
|
956
|
-
if (DEBUG)
|
966
|
+
if (DEBUG) {
|
967
|
+
fprintf(stderr, "select_process_completions: selector=%p\n", (void*)selector);
|
968
|
+
IO_Event_Selector_URing_dump_completion_queue(selector);
|
969
|
+
}
|
957
970
|
|
958
971
|
io_uring_for_each_cqe(ring, head, cqe) {
|
959
972
|
if (DEBUG) fprintf(stderr, "select_process_completions: cqe res=%d user_data=%p\n", cqe->res, (void*)cqe->user_data);
|
@@ -976,15 +989,15 @@ unsigned select_process_completions(struct IO_Event_Selector_URing *selector) {
|
|
976
989
|
waiting->flags = cqe->flags;
|
977
990
|
}
|
978
991
|
|
992
|
+
io_uring_cq_advance(ring, 1);
|
993
|
+
// This marks the waiting operation as "complete":
|
994
|
+
IO_Event_Selector_URing_Completion_release(selector, completion);
|
995
|
+
|
979
996
|
if (waiting && waiting->fiber) {
|
980
997
|
assert(waiting->result != -ECANCELED);
|
981
998
|
|
982
999
|
IO_Event_Selector_fiber_transfer(waiting->fiber, 0, NULL);
|
983
1000
|
}
|
984
|
-
|
985
|
-
// This marks the waiting operation as "complete":
|
986
|
-
IO_Event_Selector_URing_Completion_release(selector, completion);
|
987
|
-
io_uring_cq_advance(ring, 1);
|
988
1001
|
}
|
989
1002
|
|
990
1003
|
if (DEBUG && completed > 0) fprintf(stderr, "select_process_completions(completed=%d)\n", completed);
|
@@ -160,7 +160,66 @@ module IO::Event
|
|
160
160
|
errno == EAGAIN or errno == EWOULDBLOCK
|
161
161
|
end
|
162
162
|
|
163
|
-
if Support.
|
163
|
+
if Support.fiber_scheduler_v3?
|
164
|
+
# Ruby 3.3+, full IO::Buffer support.
|
165
|
+
|
166
|
+
# @parameter length [Integer] The minimum number of bytes to read.
|
167
|
+
# @parameter offset [Integer] The offset into the buffer to read to.
|
168
|
+
def io_read(fiber, io, buffer, length, offset = 0)
|
169
|
+
total = 0
|
170
|
+
|
171
|
+
Selector.nonblock(io) do
|
172
|
+
while true
|
173
|
+
result = Fiber.blocking{buffer.read(io, 0, offset)}
|
174
|
+
|
175
|
+
if result < 0
|
176
|
+
if again?(result)
|
177
|
+
self.io_wait(fiber, io, IO::READABLE)
|
178
|
+
else
|
179
|
+
return result
|
180
|
+
end
|
181
|
+
elsif result == 0
|
182
|
+
break
|
183
|
+
else
|
184
|
+
total += result
|
185
|
+
break if total >= length
|
186
|
+
offset += result
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
return total
|
192
|
+
end
|
193
|
+
|
194
|
+
# @parameter length [Integer] The minimum number of bytes to write.
|
195
|
+
# @parameter offset [Integer] The offset into the buffer to write from.
|
196
|
+
def io_write(fiber, io, buffer, length, offset = 0)
|
197
|
+
total = 0
|
198
|
+
|
199
|
+
Selector.nonblock(io) do
|
200
|
+
while true
|
201
|
+
result = Fiber.blocking{buffer.write(io, 0, offset)}
|
202
|
+
|
203
|
+
if result < 0
|
204
|
+
if again?(result)
|
205
|
+
self.io_wait(fiber, io, IO::READABLE)
|
206
|
+
else
|
207
|
+
return result
|
208
|
+
end
|
209
|
+
elsif result == 0
|
210
|
+
break result
|
211
|
+
else
|
212
|
+
total += result
|
213
|
+
break if total >= length
|
214
|
+
offset += result
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
return total
|
220
|
+
end
|
221
|
+
elsif Support.fiber_scheduler_v2?
|
222
|
+
# Ruby 3.2, most IO::Buffer support, but slightly clunky read/write methods.
|
164
223
|
def io_read(fiber, io, buffer, length, offset = 0)
|
165
224
|
total = 0
|
166
225
|
|
@@ -219,8 +278,11 @@ module IO::Event
|
|
219
278
|
return total
|
220
279
|
end
|
221
280
|
elsif Support.fiber_scheduler_v1?
|
281
|
+
# Ruby <= 3.1, limited IO::Buffer support.
|
222
282
|
def io_read(fiber, _io, buffer, length, offset = 0)
|
283
|
+
# We need to avoid any internal buffering, so we use a duplicated IO object:
|
223
284
|
io = IO.for_fd(_io.fileno, autoclose: false)
|
285
|
+
|
224
286
|
total = 0
|
225
287
|
|
226
288
|
maximum_size = buffer.size - offset
|
@@ -261,7 +323,9 @@ module IO::Event
|
|
261
323
|
end
|
262
324
|
|
263
325
|
def io_write(fiber, _io, buffer, length, offset = 0)
|
326
|
+
# We need to avoid any internal buffering, so we use a duplicated IO object:
|
264
327
|
io = IO.for_fd(_io.fileno, autoclose: false)
|
328
|
+
|
265
329
|
total = 0
|
266
330
|
|
267
331
|
maximum_size = buffer.size - offset
|
data/lib/io/event/support.rb
CHANGED
@@ -17,6 +17,17 @@ class IO
|
|
17
17
|
def self.fiber_scheduler_v2?
|
18
18
|
IO.const_defined?(:Buffer) and Fiber.respond_to?(:blocking) and IO::Buffer.instance_method(:read).arity == -1
|
19
19
|
end
|
20
|
+
|
21
|
+
def self.fiber_scheduler_v3?
|
22
|
+
if fiber_scheduler_v2?
|
23
|
+
begin
|
24
|
+
IO::Buffer.new.slice(0, 0).write(STDOUT)
|
25
|
+
return true
|
26
|
+
rescue
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
20
31
|
end
|
21
32
|
end
|
22
33
|
end
|
data/lib/io/event/version.rb
CHANGED
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.3.
|
4
|
+
version: 1.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -42,7 +42,7 @@ cert_chain:
|
|
42
42
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
43
43
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
44
44
|
-----END CERTIFICATE-----
|
45
|
-
date: 2023-
|
45
|
+
date: 2023-10-24 00:00:00.000000000 Z
|
46
46
|
dependencies: []
|
47
47
|
description:
|
48
48
|
email:
|
metadata.gz.sig
CHANGED
Binary file
|