io-event 1.16.2 → 1.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/context/getting-started.md +31 -5
- data/ext/extconf.rb +4 -4
- data/ext/io/event/list.h +1 -1
- data/ext/io/event/selector/epoll.c +196 -97
- data/ext/io/event/selector/kqueue.c +195 -101
- data/ext/io/event/selector/selector.c +77 -1
- data/ext/io/event/selector/selector.h +24 -2
- data/ext/io/event/selector/uring.c +508 -88
- data/ext/io/event/worker_pool.c +45 -34
- data/lib/io/event/debug/selector.rb +13 -6
- data/lib/io/event/interrupt.rb +12 -7
- data/lib/io/event/selector/select.rb +108 -58
- data/lib/io/event/selector.rb +24 -9
- data/lib/io/event/timers.rb +1 -1
- data/lib/io/event/version.rb +1 -1
- data/license.md +1 -0
- data/readme.md +22 -26
- data/releases.md +50 -0
- data.tar.gz.sig +0 -0
- metadata +3 -2
- metadata.gz.sig +0 -0
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
#include <errno.h>
|
|
13
13
|
#include <sys/wait.h>
|
|
14
14
|
#include <signal.h>
|
|
15
|
+
#include <unistd.h>
|
|
15
16
|
|
|
16
17
|
#include "../interrupt.h"
|
|
17
18
|
|
|
@@ -47,11 +48,7 @@ struct IO_Event_Selector_KQueue
|
|
|
47
48
|
{
|
|
48
49
|
struct IO_Event_Selector backend;
|
|
49
50
|
int descriptor;
|
|
50
|
-
|
|
51
|
-
// Flag indicating whether the selector is currently blocked in a system call.
|
|
52
|
-
// Set to 1 when blocked in kevent() without GVL, 0 otherwise.
|
|
53
|
-
// Used by wakeup() to determine if an interrupt signal is needed.
|
|
54
|
-
int blocked;
|
|
51
|
+
pid_t owner;
|
|
55
52
|
|
|
56
53
|
struct timespec idle_duration;
|
|
57
54
|
|
|
@@ -132,7 +129,14 @@ static
|
|
|
132
129
|
void close_internal(struct IO_Event_Selector_KQueue *selector)
|
|
133
130
|
{
|
|
134
131
|
if (selector->descriptor >= 0) {
|
|
135
|
-
|
|
132
|
+
if (selector->owner == getpid()) {
|
|
133
|
+
close(selector->descriptor);
|
|
134
|
+
|
|
135
|
+
#ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
|
|
136
|
+
IO_Event_Interrupt_close(&selector->interrupt);
|
|
137
|
+
#endif
|
|
138
|
+
}
|
|
139
|
+
|
|
136
140
|
selector->descriptor = -1;
|
|
137
141
|
}
|
|
138
142
|
}
|
|
@@ -289,8 +293,7 @@ VALUE IO_Event_Selector_KQueue_allocate(VALUE self) {
|
|
|
289
293
|
|
|
290
294
|
IO_Event_Selector_initialize(&selector->backend, self, Qnil);
|
|
291
295
|
selector->descriptor = -1;
|
|
292
|
-
selector->
|
|
293
|
-
|
|
296
|
+
selector->owner = 0;
|
|
294
297
|
selector->descriptors.element_initialize = IO_Event_Selector_KQueue_Descriptor_initialize;
|
|
295
298
|
selector->descriptors.element_free = IO_Event_Selector_KQueue_Descriptor_free;
|
|
296
299
|
|
|
@@ -331,6 +334,7 @@ VALUE IO_Event_Selector_KQueue_initialize(VALUE self, VALUE loop) {
|
|
|
331
334
|
ioctl(result, FIOCLEX);
|
|
332
335
|
|
|
333
336
|
selector->descriptor = result;
|
|
337
|
+
selector->owner = getpid();
|
|
334
338
|
|
|
335
339
|
rb_update_max_fd(selector->descriptor);
|
|
336
340
|
}
|
|
@@ -365,13 +369,16 @@ VALUE IO_Event_Selector_KQueue_close(VALUE self) {
|
|
|
365
369
|
|
|
366
370
|
close_internal(selector);
|
|
367
371
|
|
|
368
|
-
#ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
|
|
369
|
-
IO_Event_Interrupt_close(&selector->interrupt);
|
|
370
|
-
#endif
|
|
371
|
-
|
|
372
372
|
return Qnil;
|
|
373
373
|
}
|
|
374
374
|
|
|
375
|
+
VALUE IO_Event_Selector_KQueue_closed_p(VALUE self) {
|
|
376
|
+
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
377
|
+
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
378
|
+
|
|
379
|
+
return selector->descriptor < 0 || selector->owner != getpid() ? Qtrue : Qfalse;
|
|
380
|
+
}
|
|
381
|
+
|
|
375
382
|
VALUE IO_Event_Selector_KQueue_transfer(VALUE self)
|
|
376
383
|
{
|
|
377
384
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
@@ -455,7 +462,7 @@ VALUE process_wait_transfer(VALUE _arguments) {
|
|
|
455
462
|
|
|
456
463
|
if (arguments->waiting->ready) {
|
|
457
464
|
process_prewait(arguments->pid);
|
|
458
|
-
return
|
|
465
|
+
return IO_Event_Selector_process_status_reap(arguments->pid, arguments->flags);
|
|
459
466
|
} else {
|
|
460
467
|
return Qfalse;
|
|
461
468
|
}
|
|
@@ -479,6 +486,11 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
|
479
486
|
pid_t pid = NUM2PIDT(_pid);
|
|
480
487
|
int flags = NUM2INT(_flags);
|
|
481
488
|
|
|
489
|
+
// `EVFILT_PROC` can only refer to a specific process, so waiting for any child or a process group (pid <= 0) is delegated to the threaded fallback:
|
|
490
|
+
if (pid <= 0) {
|
|
491
|
+
return IO_Event_Selector_process_wait(pid, flags);
|
|
492
|
+
}
|
|
493
|
+
|
|
482
494
|
struct IO_Event_Selector_KQueue_Waiting waiting = {
|
|
483
495
|
.list = {.type = &IO_Event_Selector_KQueue_process_wait_list_type},
|
|
484
496
|
.fiber = fiber,
|
|
@@ -500,7 +512,7 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
|
|
|
500
512
|
if (errno == ESRCH) {
|
|
501
513
|
process_prewait(pid);
|
|
502
514
|
|
|
503
|
-
return
|
|
515
|
+
return IO_Event_Selector_process_status_reap(pid, flags);
|
|
504
516
|
}
|
|
505
517
|
|
|
506
518
|
rb_sys_fail("IO_Event_Selector_KQueue_process_wait:IO_Event_Selector_KQueue_Waiting_register");
|
|
@@ -570,48 +582,49 @@ VALUE IO_Event_Selector_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
570
582
|
#ifdef HAVE_RUBY_IO_BUFFER_H
|
|
571
583
|
|
|
572
584
|
struct io_read_arguments {
|
|
585
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
573
586
|
VALUE self;
|
|
574
587
|
VALUE fiber;
|
|
575
588
|
VALUE io;
|
|
589
|
+
#endif
|
|
576
590
|
|
|
577
591
|
int flags;
|
|
578
592
|
|
|
579
593
|
int descriptor;
|
|
580
594
|
|
|
581
|
-
|
|
595
|
+
// The remaining writable buffer region after applying the requested offset.
|
|
596
|
+
void *base;
|
|
597
|
+
size_t size;
|
|
598
|
+
|
|
599
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
600
|
+
// The minimum number of bytes requested by the caller.
|
|
582
601
|
size_t length;
|
|
583
|
-
|
|
602
|
+
#endif
|
|
584
603
|
};
|
|
585
604
|
|
|
586
605
|
static
|
|
587
606
|
VALUE io_read_loop(VALUE _arguments) {
|
|
588
607
|
struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
|
|
589
608
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
609
|
+
#if RUBY_FIBER_SCHEDULER_VERSION >= 4
|
|
610
|
+
ssize_t result = read(arguments->descriptor, arguments->base, arguments->size);
|
|
611
|
+
return rb_fiber_scheduler_io_result(result, errno);
|
|
612
|
+
#else
|
|
594
613
|
size_t length = arguments->length;
|
|
595
|
-
size_t offset = arguments->offset;
|
|
596
614
|
size_t total = 0;
|
|
597
615
|
|
|
598
616
|
if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu)\n", arguments->descriptor, length);
|
|
599
617
|
|
|
600
|
-
|
|
601
|
-
if (offset > size) {
|
|
602
|
-
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
size_t maximum_size = size - offset;
|
|
618
|
+
size_t maximum_size = arguments->size;
|
|
606
619
|
while (maximum_size) {
|
|
607
|
-
if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld)\n", arguments->descriptor,
|
|
608
|
-
ssize_t result = read(arguments->descriptor, (char*)base+
|
|
609
|
-
if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld) -> %zd\n", arguments->descriptor,
|
|
620
|
+
if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld)\n", arguments->descriptor, total, maximum_size);
|
|
621
|
+
ssize_t result = read(arguments->descriptor, (char*)arguments->base+total, maximum_size);
|
|
622
|
+
if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld) -> %zd\n", arguments->descriptor, total, maximum_size, result);
|
|
610
623
|
|
|
611
624
|
if (result > 0) {
|
|
612
625
|
total += result;
|
|
613
|
-
offset += result;
|
|
614
626
|
if ((size_t)result >= length) break;
|
|
627
|
+
maximum_size -= result;
|
|
615
628
|
length -= result;
|
|
616
629
|
} else if (result == 0) {
|
|
617
630
|
break;
|
|
@@ -622,12 +635,11 @@ VALUE io_read_loop(VALUE _arguments) {
|
|
|
622
635
|
if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu) -> errno=%d\n", arguments->descriptor, length, errno);
|
|
623
636
|
return rb_fiber_scheduler_io_result(-1, errno);
|
|
624
637
|
}
|
|
625
|
-
|
|
626
|
-
maximum_size = size - offset;
|
|
627
638
|
}
|
|
628
639
|
|
|
629
|
-
if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length,
|
|
640
|
+
if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length, total);
|
|
630
641
|
return rb_fiber_scheduler_io_result(total, 0);
|
|
642
|
+
#endif
|
|
631
643
|
}
|
|
632
644
|
|
|
633
645
|
static
|
|
@@ -639,25 +651,56 @@ VALUE io_read_ensure(VALUE _arguments) {
|
|
|
639
651
|
return Qnil;
|
|
640
652
|
}
|
|
641
653
|
|
|
642
|
-
VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE
|
|
654
|
+
VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _first, VALUE _second) {
|
|
643
655
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
644
656
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
645
657
|
|
|
646
|
-
|
|
658
|
+
void *base;
|
|
659
|
+
size_t size;
|
|
660
|
+
rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
|
|
661
|
+
|
|
662
|
+
#if RUBY_FIBER_SCHEDULER_VERSION >= 4
|
|
663
|
+
size_t offset = NUM2SIZET(_first);
|
|
664
|
+
size_t length = NUM2SIZET(_second);
|
|
665
|
+
|
|
666
|
+
if (!IO_Event_Selector_valid_buffer_range(size, offset, length)) {
|
|
667
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
668
|
+
} else if (length == 0) {
|
|
669
|
+
return rb_fiber_scheduler_io_result(0, 0);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
base = (char*)base + offset;
|
|
673
|
+
size = length;
|
|
674
|
+
#else
|
|
675
|
+
size_t length = NUM2SIZET(_first);
|
|
676
|
+
size_t offset = NUM2SIZET(_second);
|
|
647
677
|
|
|
648
|
-
|
|
649
|
-
|
|
678
|
+
if (offset > size) {
|
|
679
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
680
|
+
} else if (offset == size) {
|
|
681
|
+
return rb_fiber_scheduler_io_result(0, 0);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
base = (char*)base + offset;
|
|
685
|
+
size -= offset;
|
|
686
|
+
#endif
|
|
687
|
+
|
|
688
|
+
int descriptor = IO_Event_Selector_io_descriptor(io);
|
|
650
689
|
|
|
651
690
|
struct io_read_arguments io_read_arguments = {
|
|
691
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
652
692
|
.self = self,
|
|
653
693
|
.fiber = fiber,
|
|
654
694
|
.io = io,
|
|
695
|
+
#endif
|
|
655
696
|
|
|
656
697
|
.flags = IO_Event_Selector_nonblock_set(descriptor),
|
|
657
698
|
.descriptor = descriptor,
|
|
658
|
-
.
|
|
699
|
+
.base = base,
|
|
700
|
+
.size = size,
|
|
701
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
659
702
|
.length = length,
|
|
660
|
-
|
|
703
|
+
#endif
|
|
661
704
|
};
|
|
662
705
|
|
|
663
706
|
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
@@ -665,6 +708,7 @@ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
665
708
|
return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
|
|
666
709
|
}
|
|
667
710
|
|
|
711
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
668
712
|
static VALUE IO_Event_Selector_KQueue_io_read_compatible(int argc, VALUE *argv, VALUE self)
|
|
669
713
|
{
|
|
670
714
|
rb_check_arity(argc, 4, 5);
|
|
@@ -677,54 +721,52 @@ static VALUE IO_Event_Selector_KQueue_io_read_compatible(int argc, VALUE *argv,
|
|
|
677
721
|
|
|
678
722
|
return IO_Event_Selector_KQueue_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
|
|
679
723
|
}
|
|
724
|
+
#endif
|
|
680
725
|
|
|
681
726
|
struct io_write_arguments {
|
|
727
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
682
728
|
VALUE self;
|
|
683
729
|
VALUE fiber;
|
|
684
730
|
VALUE io;
|
|
731
|
+
#endif
|
|
685
732
|
|
|
686
733
|
int flags;
|
|
687
734
|
|
|
688
735
|
int descriptor;
|
|
689
736
|
|
|
690
|
-
|
|
737
|
+
// The remaining readable buffer region after applying the requested offset.
|
|
738
|
+
const void *base;
|
|
739
|
+
size_t size;
|
|
740
|
+
|
|
741
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
742
|
+
// The minimum number of bytes requested by the caller.
|
|
691
743
|
size_t length;
|
|
692
|
-
|
|
744
|
+
#endif
|
|
693
745
|
};
|
|
694
746
|
|
|
695
747
|
static
|
|
696
748
|
VALUE io_write_loop(VALUE _arguments) {
|
|
697
749
|
struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
|
|
698
750
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
751
|
+
#if RUBY_FIBER_SCHEDULER_VERSION >= 4
|
|
752
|
+
ssize_t result = write(arguments->descriptor, arguments->base, arguments->size);
|
|
753
|
+
return rb_fiber_scheduler_io_result(result, errno);
|
|
754
|
+
#else
|
|
703
755
|
size_t length = arguments->length;
|
|
704
|
-
size_t offset = arguments->offset;
|
|
705
756
|
size_t total = 0;
|
|
706
757
|
|
|
707
|
-
if (length > size) {
|
|
708
|
-
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
|
709
|
-
}
|
|
710
|
-
|
|
711
758
|
if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu)\n", arguments->descriptor, length);
|
|
712
759
|
|
|
713
|
-
|
|
714
|
-
if (offset > size) {
|
|
715
|
-
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
size_t maximum_size = size - offset;
|
|
760
|
+
size_t maximum_size = arguments->size;
|
|
719
761
|
while (maximum_size) {
|
|
720
|
-
if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld, length=%zu)\n", arguments->descriptor,
|
|
721
|
-
ssize_t result = write(arguments->descriptor, (char*)base+
|
|
722
|
-
if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld) -> %zd\n", arguments->descriptor,
|
|
762
|
+
if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld, length=%zu)\n", arguments->descriptor, total, maximum_size, length);
|
|
763
|
+
ssize_t result = write(arguments->descriptor, (char*)arguments->base+total, maximum_size);
|
|
764
|
+
if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld) -> %zd\n", arguments->descriptor, total, maximum_size, result);
|
|
723
765
|
|
|
724
766
|
if (result > 0) {
|
|
725
767
|
total += result;
|
|
726
|
-
offset += result;
|
|
727
768
|
if ((size_t)result >= length) break;
|
|
769
|
+
maximum_size -= result;
|
|
728
770
|
length -= result;
|
|
729
771
|
} else if (result == 0) {
|
|
730
772
|
break;
|
|
@@ -735,12 +777,11 @@ VALUE io_write_loop(VALUE _arguments) {
|
|
|
735
777
|
if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu) -> errno=%d\n", arguments->descriptor, length, errno);
|
|
736
778
|
return rb_fiber_scheduler_io_result(-1, errno);
|
|
737
779
|
}
|
|
738
|
-
|
|
739
|
-
maximum_size = size - offset;
|
|
740
780
|
}
|
|
741
781
|
|
|
742
|
-
if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length,
|
|
782
|
+
if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length, total);
|
|
743
783
|
return rb_fiber_scheduler_io_result(total, 0);
|
|
784
|
+
#endif
|
|
744
785
|
};
|
|
745
786
|
|
|
746
787
|
static
|
|
@@ -752,25 +793,60 @@ VALUE io_write_ensure(VALUE _arguments) {
|
|
|
752
793
|
return Qnil;
|
|
753
794
|
};
|
|
754
795
|
|
|
755
|
-
VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE
|
|
796
|
+
VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _first, VALUE _second) {
|
|
756
797
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
757
798
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
758
799
|
|
|
759
|
-
|
|
800
|
+
const void *base;
|
|
801
|
+
size_t size;
|
|
802
|
+
rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
|
|
760
803
|
|
|
761
|
-
|
|
762
|
-
size_t offset = NUM2SIZET(
|
|
804
|
+
#if RUBY_FIBER_SCHEDULER_VERSION >= 4
|
|
805
|
+
size_t offset = NUM2SIZET(_first);
|
|
806
|
+
size_t length = NUM2SIZET(_second);
|
|
807
|
+
|
|
808
|
+
if (!IO_Event_Selector_valid_buffer_range(size, offset, length)) {
|
|
809
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
810
|
+
} else if (length == 0) {
|
|
811
|
+
return rb_fiber_scheduler_io_result(0, 0);
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
base = (const char*)base + offset;
|
|
815
|
+
size = length;
|
|
816
|
+
#else
|
|
817
|
+
size_t length = NUM2SIZET(_first);
|
|
818
|
+
size_t offset = NUM2SIZET(_second);
|
|
819
|
+
|
|
820
|
+
if (length > size) {
|
|
821
|
+
rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (offset > size) {
|
|
825
|
+
return rb_fiber_scheduler_io_result(-1, EINVAL);
|
|
826
|
+
} else if (offset == size) {
|
|
827
|
+
return rb_fiber_scheduler_io_result(0, 0);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
base = (const char*)base + offset;
|
|
831
|
+
size -= offset;
|
|
832
|
+
#endif
|
|
833
|
+
|
|
834
|
+
int descriptor = IO_Event_Selector_io_descriptor(io);
|
|
763
835
|
|
|
764
836
|
struct io_write_arguments io_write_arguments = {
|
|
837
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
765
838
|
.self = self,
|
|
766
839
|
.fiber = fiber,
|
|
767
840
|
.io = io,
|
|
841
|
+
#endif
|
|
768
842
|
|
|
769
843
|
.flags = IO_Event_Selector_nonblock_set(descriptor),
|
|
770
844
|
.descriptor = descriptor,
|
|
771
|
-
.
|
|
845
|
+
.base = base,
|
|
846
|
+
.size = size,
|
|
847
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
772
848
|
.length = length,
|
|
773
|
-
|
|
849
|
+
#endif
|
|
774
850
|
};
|
|
775
851
|
|
|
776
852
|
RB_OBJ_WRITTEN(self, Qundef, fiber);
|
|
@@ -778,6 +854,7 @@ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
|
|
|
778
854
|
return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
|
|
779
855
|
}
|
|
780
856
|
|
|
857
|
+
#if RUBY_FIBER_SCHEDULER_VERSION < 4
|
|
781
858
|
static VALUE IO_Event_Selector_KQueue_io_write_compatible(int argc, VALUE *argv, VALUE self)
|
|
782
859
|
{
|
|
783
860
|
rb_check_arity(argc, 4, 5);
|
|
@@ -790,6 +867,7 @@ static VALUE IO_Event_Selector_KQueue_io_write_compatible(int argc, VALUE *argv,
|
|
|
790
867
|
|
|
791
868
|
return IO_Event_Selector_KQueue_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
|
|
792
869
|
}
|
|
870
|
+
#endif
|
|
793
871
|
|
|
794
872
|
#endif
|
|
795
873
|
|
|
@@ -816,15 +894,22 @@ struct timespec * make_timeout(VALUE duration, struct timespec * storage) {
|
|
|
816
894
|
return storage;
|
|
817
895
|
}
|
|
818
896
|
|
|
897
|
+
// Return true when it is safe and useful to enter the blocking selector wait.
|
|
819
898
|
static
|
|
820
|
-
int
|
|
821
|
-
|
|
899
|
+
int select_blocking_allowed(struct timespec * timespec) {
|
|
900
|
+
// A `0` timeout is already a poll. The selector has already performed the immediate poll previously, so there is no useful blocking wait to enter here.
|
|
901
|
+
if (timespec && timespec->tv_sec == 0 && timespec->tv_nsec == 0) {
|
|
902
|
+
return 0;
|
|
903
|
+
}
|
|
904
|
+
return 1;
|
|
822
905
|
}
|
|
823
906
|
|
|
824
907
|
struct select_arguments {
|
|
825
908
|
struct IO_Event_Selector_KQueue *selector;
|
|
826
909
|
|
|
827
910
|
int count;
|
|
911
|
+
int result;
|
|
912
|
+
int error;
|
|
828
913
|
struct kevent events[KQUEUE_MAX_EVENTS];
|
|
829
914
|
|
|
830
915
|
struct timespec storage;
|
|
@@ -837,38 +922,42 @@ static
|
|
|
837
922
|
void * select_internal(void *_arguments) {
|
|
838
923
|
struct select_arguments * arguments = (struct select_arguments *)_arguments;
|
|
839
924
|
|
|
840
|
-
arguments->
|
|
925
|
+
arguments->result = kevent(arguments->selector->descriptor, NULL, 0, arguments->events, arguments->count, arguments->timeout);
|
|
926
|
+
arguments->error = errno;
|
|
841
927
|
|
|
842
928
|
return NULL;
|
|
843
929
|
}
|
|
844
930
|
|
|
845
931
|
static
|
|
846
|
-
|
|
847
|
-
arguments->
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
rb_sys_fail("select_internal_without_gvl:kevent");
|
|
932
|
+
int select_internal_without_gvl(struct select_arguments *arguments) {
|
|
933
|
+
arguments->result = -1;
|
|
934
|
+
arguments->error = EINTR;
|
|
935
|
+
IO_Event_Selector_blocking_operation(&arguments->selector->backend, select_internal, (void *)arguments, RUBY_UBF_IO, 0);
|
|
936
|
+
|
|
937
|
+
if (arguments->result == -1) {
|
|
938
|
+
if (arguments->error != EINTR) {
|
|
939
|
+
rb_syserr_fail(arguments->error, "select_internal_without_gvl:kevent");
|
|
855
940
|
} else {
|
|
856
|
-
|
|
941
|
+
return 0;
|
|
857
942
|
}
|
|
858
943
|
}
|
|
944
|
+
|
|
945
|
+
return arguments->result;
|
|
859
946
|
}
|
|
860
947
|
|
|
861
948
|
static
|
|
862
|
-
|
|
949
|
+
int select_internal_with_gvl(struct select_arguments *arguments) {
|
|
863
950
|
select_internal((void *)arguments);
|
|
864
951
|
|
|
865
|
-
if (arguments->
|
|
866
|
-
if (
|
|
867
|
-
|
|
952
|
+
if (arguments->result == -1) {
|
|
953
|
+
if (arguments->error != EINTR) {
|
|
954
|
+
rb_syserr_fail(arguments->error, "select_internal_with_gvl:kevent");
|
|
868
955
|
} else {
|
|
869
|
-
|
|
956
|
+
return 0;
|
|
870
957
|
}
|
|
871
958
|
}
|
|
959
|
+
|
|
960
|
+
return arguments->result;
|
|
872
961
|
}
|
|
873
962
|
|
|
874
963
|
static
|
|
@@ -922,14 +1011,14 @@ VALUE select_handle_events(VALUE _arguments)
|
|
|
922
1011
|
struct select_arguments *arguments = (struct select_arguments *)_arguments;
|
|
923
1012
|
struct IO_Event_Selector_KQueue *selector = arguments->selector;
|
|
924
1013
|
|
|
925
|
-
for (int i = 0; i < arguments->
|
|
1014
|
+
for (int i = 0; i < arguments->result; i += 1) {
|
|
926
1015
|
if (arguments->events[i].udata) {
|
|
927
1016
|
struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor = arguments->events[i].udata;
|
|
928
1017
|
kqueue_descriptor->ready_events |= events_from_kevent_filter(arguments->events[i].filter);
|
|
929
1018
|
}
|
|
930
1019
|
}
|
|
931
1020
|
|
|
932
|
-
for (int i = 0; i < arguments->
|
|
1021
|
+
for (int i = 0; i < arguments->result; i += 1) {
|
|
933
1022
|
if (arguments->events[i].udata) {
|
|
934
1023
|
struct IO_Event_Selector_KQueue_Descriptor *kqueue_descriptor = arguments->events[i].udata;
|
|
935
1024
|
IO_Event_Selector_KQueue_handle(selector, arguments->events[i].ident, kqueue_descriptor, &arguments->saved);
|
|
@@ -940,7 +1029,7 @@ VALUE select_handle_events(VALUE _arguments)
|
|
|
940
1029
|
}
|
|
941
1030
|
}
|
|
942
1031
|
|
|
943
|
-
return RB_INT2NUM(arguments->
|
|
1032
|
+
return RB_INT2NUM(arguments->result);
|
|
944
1033
|
}
|
|
945
1034
|
|
|
946
1035
|
static
|
|
@@ -965,6 +1054,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
965
1054
|
struct select_arguments arguments = {
|
|
966
1055
|
.selector = selector,
|
|
967
1056
|
.count = KQUEUE_MAX_EVENTS,
|
|
1057
|
+
.result = 0,
|
|
968
1058
|
.storage = {
|
|
969
1059
|
.tv_sec = 0,
|
|
970
1060
|
.tv_nsec = 0
|
|
@@ -975,14 +1065,14 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
975
1065
|
arguments.timeout = &arguments.storage;
|
|
976
1066
|
|
|
977
1067
|
// We break this implementation into two parts.
|
|
978
|
-
// (1)
|
|
979
|
-
// (2) without gvl: kevent(..., timeout = 0) if
|
|
1068
|
+
// (1) result = kevent(..., timeout = 0)
|
|
1069
|
+
// (2) without gvl: kevent(..., timeout = 0) if result == 0 and timeout != 0
|
|
980
1070
|
// This allows us to avoid releasing and reacquiring the GVL.
|
|
981
1071
|
// Non-comprehensive testing shows this gives a 1.5x speedup.
|
|
982
1072
|
|
|
983
1073
|
// First do the syscall with no timeout to get any immediately available events:
|
|
984
1074
|
if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl timeout=" IO_EVENT_TIME_PRINTF_TIMESPEC "\r\n", IO_EVENT_TIME_PRINTF_TIMESPEC_ARGUMENTS(arguments.storage));
|
|
985
|
-
select_internal_with_gvl(&arguments);
|
|
1075
|
+
int result = select_internal_with_gvl(&arguments);
|
|
986
1076
|
if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl done\r\n");
|
|
987
1077
|
|
|
988
1078
|
// If we:
|
|
@@ -990,17 +1080,15 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
990
1080
|
// 2. Didn't process any events from non-blocking select (above), and
|
|
991
1081
|
// 3. There are no items in the ready list,
|
|
992
1082
|
// then we can perform a blocking select.
|
|
993
|
-
if (!ready && !
|
|
1083
|
+
if (!ready && !result && !selector->backend.ready) {
|
|
994
1084
|
arguments.timeout = make_timeout(duration, &arguments.storage);
|
|
995
1085
|
|
|
996
|
-
if (
|
|
997
|
-
arguments.count = KQUEUE_MAX_EVENTS;
|
|
998
|
-
|
|
1086
|
+
if (select_blocking_allowed(arguments.timeout)) {
|
|
999
1087
|
struct timespec start_time;
|
|
1000
1088
|
IO_Event_Time_current(&start_time);
|
|
1001
1089
|
|
|
1002
1090
|
if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout=" IO_EVENT_TIME_PRINTF_TIMESPEC "\n", IO_EVENT_TIME_PRINTF_TIMESPEC_ARGUMENTS(arguments.storage));
|
|
1003
|
-
select_internal_without_gvl(&arguments);
|
|
1091
|
+
result = select_internal_without_gvl(&arguments);
|
|
1004
1092
|
|
|
1005
1093
|
struct timespec end_time;
|
|
1006
1094
|
IO_Event_Time_current(&end_time);
|
|
@@ -1008,7 +1096,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
|
|
|
1008
1096
|
}
|
|
1009
1097
|
}
|
|
1010
1098
|
|
|
1011
|
-
if (
|
|
1099
|
+
if (result) {
|
|
1012
1100
|
return rb_ensure(select_handle_events, (VALUE)&arguments, select_handle_events_ensure, (VALUE)&arguments);
|
|
1013
1101
|
} else {
|
|
1014
1102
|
return RB_INT2NUM(0);
|
|
@@ -1019,7 +1107,7 @@ VALUE IO_Event_Selector_KQueue_wakeup(VALUE self) {
|
|
|
1019
1107
|
struct IO_Event_Selector_KQueue *selector = NULL;
|
|
1020
1108
|
TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
|
|
1021
1109
|
|
|
1022
|
-
if (selector->blocked) {
|
|
1110
|
+
if (selector->backend.blocked) {
|
|
1023
1111
|
#ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
|
|
1024
1112
|
IO_Event_Interrupt_signal(&selector->interrupt);
|
|
1025
1113
|
#else
|
|
@@ -1090,12 +1178,18 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
|
|
|
1090
1178
|
rb_define_method(IO_Event_Selector_KQueue, "select", IO_Event_Selector_KQueue_select, 1);
|
|
1091
1179
|
rb_define_method(IO_Event_Selector_KQueue, "wakeup", IO_Event_Selector_KQueue_wakeup, 0);
|
|
1092
1180
|
rb_define_method(IO_Event_Selector_KQueue, "close", IO_Event_Selector_KQueue_close, 0);
|
|
1181
|
+
rb_define_method(IO_Event_Selector_KQueue, "closed?", IO_Event_Selector_KQueue_closed_p, 0);
|
|
1093
1182
|
|
|
1094
1183
|
rb_define_method(IO_Event_Selector_KQueue, "io_wait", IO_Event_Selector_KQueue_io_wait, 3);
|
|
1095
1184
|
|
|
1096
1185
|
#ifdef HAVE_RUBY_IO_BUFFER_H
|
|
1186
|
+
#if RUBY_FIBER_SCHEDULER_VERSION >= 4
|
|
1187
|
+
rb_define_method(IO_Event_Selector_KQueue, "io_read", IO_Event_Selector_KQueue_io_read, 5);
|
|
1188
|
+
rb_define_method(IO_Event_Selector_KQueue, "io_write", IO_Event_Selector_KQueue_io_write, 5);
|
|
1189
|
+
#else
|
|
1097
1190
|
rb_define_method(IO_Event_Selector_KQueue, "io_read", IO_Event_Selector_KQueue_io_read_compatible, -1);
|
|
1098
1191
|
rb_define_method(IO_Event_Selector_KQueue, "io_write", IO_Event_Selector_KQueue_io_write_compatible, -1);
|
|
1192
|
+
#endif
|
|
1099
1193
|
#endif
|
|
1100
1194
|
|
|
1101
1195
|
rb_define_method(IO_Event_Selector_KQueue, "process_wait", IO_Event_Selector_KQueue_process_wait, 3);
|