io-event 1.16.4 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83f9faed054855a0c3a50ab469f315c1345a8af43641ab6c5630d648763fc55d
4
- data.tar.gz: 78114e047cd897ed0192c262d099a93baea21d0c30ddb70cd57e4efc73a40889
3
+ metadata.gz: be6f12aa408dcf76d86fbac8ae598d4a6313b65275357d611eeae9dc2fd1fe75
4
+ data.tar.gz: facad52118ca469a78fa08187f14265fc98b577b1e703d76e66c83fc733a3b21
5
5
  SHA512:
6
- metadata.gz: 7cea5251f1c5b93b0235e2aa6aa69c65913e13de847a535eee21343060f744b2a810eb901b15b82bbb3c9979d60a620d4d89dfba349473ab6836e9c420985b9d
7
- data.tar.gz: c8752f8a0bc9da0ca37ae420364a564c68ad4cb6020124f767677a854c7d81639e9e6daa46040d8fc575e02a7231ff5409d72833b8eb15ec72684b063b5d92d2
6
+ metadata.gz: a32f4bf15f0377d88912e799f87898787ee817e24c2b3638dca609d54ebc9ef3c97258732545be36fb90ef0a26455c210047872f686736d5fae2d6fbf8495aef
7
+ data.tar.gz: 931c9b8ee443cc311a8d8823dde3128f109e8cdc739fdc421bf959c5ebfb8fea9a17a17fdc2020a65b0b970eafa91d4cba7fa6ff483165b2c4fca862061ca93c
checksums.yaml.gz.sig CHANGED
Binary file
@@ -9,6 +9,7 @@
9
9
  #include <sys/epoll.h>
10
10
  #include <time.h>
11
11
  #include <errno.h>
12
+ #include <unistd.h>
12
13
 
13
14
  #include "pidfd.c"
14
15
  #include "../interrupt.h"
@@ -38,6 +39,7 @@ struct IO_Event_Selector_EPoll
38
39
  {
39
40
  struct IO_Event_Selector backend;
40
41
  int descriptor;
42
+ pid_t owner;
41
43
 
42
44
  // Flag indicating whether the selector is currently blocked in a system call.
43
45
  // Set to 1 when blocked in epoll_wait() without GVL, 0 otherwise.
@@ -131,10 +133,12 @@ static
131
133
  void close_internal(struct IO_Event_Selector_EPoll *selector)
132
134
  {
133
135
  if (selector->descriptor >= 0) {
134
- close(selector->descriptor);
135
- selector->descriptor = -1;
136
+ if (selector->owner == getpid()) {
137
+ close(selector->descriptor);
138
+ IO_Event_Interrupt_close(&selector->interrupt);
139
+ }
136
140
 
137
- IO_Event_Interrupt_close(&selector->interrupt);
141
+ selector->descriptor = -1;
138
142
  }
139
143
  }
140
144
 
@@ -315,6 +319,7 @@ VALUE IO_Event_Selector_EPoll_allocate(VALUE self) {
315
319
 
316
320
  IO_Event_Selector_initialize(&selector->backend, self, Qnil);
317
321
  selector->descriptor = -1;
322
+ selector->owner = 0;
318
323
  selector->blocked = 0;
319
324
 
320
325
  selector->descriptors.element_initialize = IO_Event_Selector_EPoll_Descriptor_initialize;
@@ -350,6 +355,7 @@ VALUE IO_Event_Selector_EPoll_initialize(VALUE self, VALUE loop) {
350
355
  rb_sys_fail("IO_Event_Selector_EPoll_initialize:epoll_create");
351
356
  } else {
352
357
  selector->descriptor = result;
358
+ selector->owner = getpid();
353
359
 
354
360
  rb_update_max_fd(selector->descriptor);
355
361
  }
@@ -385,6 +391,13 @@ VALUE IO_Event_Selector_EPoll_close(VALUE self) {
385
391
  return Qnil;
386
392
  }
387
393
 
394
+ VALUE IO_Event_Selector_EPoll_closed_p(VALUE self) {
395
+ struct IO_Event_Selector_EPoll *selector = NULL;
396
+ TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
397
+
398
+ return selector->descriptor < 0 || selector->owner != getpid() ? Qtrue : Qfalse;
399
+ }
400
+
388
401
  VALUE IO_Event_Selector_EPoll_transfer(VALUE self)
389
402
  {
390
403
  struct IO_Event_Selector_EPoll *selector = NULL;
@@ -590,36 +603,29 @@ struct io_read_arguments {
590
603
 
591
604
  int descriptor;
592
605
 
593
- VALUE buffer;
606
+ // The remaining writable buffer region after applying the requested offset.
607
+ void *base;
608
+ size_t size;
609
+
610
+ // The minimum number of bytes requested by the caller.
594
611
  size_t length;
595
- size_t offset;
596
612
  };
597
613
 
598
614
  static
599
615
  VALUE io_read_loop(VALUE _arguments) {
600
616
  struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
601
617
 
602
- void *base;
603
- size_t size;
604
- rb_io_buffer_get_bytes_for_writing(arguments->buffer, &base, &size);
605
-
606
618
  size_t length = arguments->length;
607
- size_t offset = arguments->offset;
608
619
  size_t total = 0;
609
620
 
610
- // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
611
- if (offset > size) {
612
- return rb_fiber_scheduler_io_result(-1, EINVAL);
613
- }
614
-
615
- size_t maximum_size = size - offset;
621
+ size_t maximum_size = arguments->size;
616
622
  while (maximum_size) {
617
- ssize_t result = read(arguments->descriptor, (char*)base+offset, maximum_size);
623
+ ssize_t result = read(arguments->descriptor, (char*)arguments->base+total, maximum_size);
618
624
 
619
625
  if (result > 0) {
620
626
  total += result;
621
- offset += result;
622
627
  if ((size_t)result >= length) break;
628
+ maximum_size -= result;
623
629
  length -= result;
624
630
  } else if (result == 0) {
625
631
  break;
@@ -628,8 +634,6 @@ VALUE io_read_loop(VALUE _arguments) {
628
634
  } else {
629
635
  return rb_fiber_scheduler_io_result(-1, errno);
630
636
  }
631
-
632
- maximum_size = size - offset;
633
637
  }
634
638
 
635
639
  return rb_fiber_scheduler_io_result(total, 0);
@@ -645,11 +649,24 @@ VALUE io_read_ensure(VALUE _arguments) {
645
649
  }
646
650
 
647
651
  VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
648
- int descriptor = IO_Event_Selector_io_descriptor(io);
649
-
650
652
  size_t offset = NUM2SIZET(_offset);
651
653
  size_t length = NUM2SIZET(_length);
652
654
 
655
+ void *base;
656
+ size_t size;
657
+ rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
658
+
659
+ if (offset > size) {
660
+ return rb_fiber_scheduler_io_result(-1, EINVAL);
661
+ } else if (offset == size) {
662
+ return rb_fiber_scheduler_io_result(0, 0);
663
+ }
664
+
665
+ base = (char*)base + offset;
666
+ size -= offset;
667
+
668
+ int descriptor = IO_Event_Selector_io_descriptor(io);
669
+
653
670
  struct io_read_arguments io_read_arguments = {
654
671
  .self = self,
655
672
  .fiber = fiber,
@@ -657,9 +674,9 @@ VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
657
674
 
658
675
  .flags = IO_Event_Selector_nonblock_set(descriptor),
659
676
  .descriptor = descriptor,
660
- .buffer = buffer,
677
+ .base = base,
678
+ .size = size,
661
679
  .length = length,
662
- .offset = offset,
663
680
  };
664
681
 
665
682
  RB_OBJ_WRITTEN(self, Qundef, fiber);
@@ -689,40 +706,29 @@ struct io_write_arguments {
689
706
 
690
707
  int descriptor;
691
708
 
692
- VALUE buffer;
709
+ // The remaining readable buffer region after applying the requested offset.
710
+ const void *base;
711
+ size_t size;
712
+
713
+ // The minimum number of bytes requested by the caller.
693
714
  size_t length;
694
- size_t offset;
695
715
  };
696
716
 
697
717
  static
698
718
  VALUE io_write_loop(VALUE _arguments) {
699
719
  struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
700
720
 
701
- const void *base;
702
- size_t size;
703
- rb_io_buffer_get_bytes_for_reading(arguments->buffer, &base, &size);
704
-
705
721
  size_t length = arguments->length;
706
- size_t offset = arguments->offset;
707
722
  size_t total = 0;
708
723
 
709
- if (length > size) {
710
- rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
711
- }
712
-
713
- // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
714
- if (offset > size) {
715
- return rb_fiber_scheduler_io_result(-1, EINVAL);
716
- }
717
-
718
- size_t maximum_size = size - offset;
724
+ size_t maximum_size = arguments->size;
719
725
  while (maximum_size) {
720
- ssize_t result = write(arguments->descriptor, (char*)base+offset, maximum_size);
726
+ ssize_t result = write(arguments->descriptor, (char*)arguments->base+total, maximum_size);
721
727
 
722
728
  if (result > 0) {
723
729
  total += result;
724
- offset += result;
725
730
  if ((size_t)result >= length) break;
731
+ maximum_size -= result;
726
732
  length -= result;
727
733
  } else if (result == 0) {
728
734
  break;
@@ -731,8 +737,6 @@ VALUE io_write_loop(VALUE _arguments) {
731
737
  } else {
732
738
  return rb_fiber_scheduler_io_result(-1, errno);
733
739
  }
734
-
735
- maximum_size = size - offset;
736
740
  }
737
741
 
738
742
  return rb_fiber_scheduler_io_result(total, 0);
@@ -748,11 +752,28 @@ VALUE io_write_ensure(VALUE _arguments) {
748
752
  };
749
753
 
750
754
  VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _length, VALUE _offset) {
751
- int descriptor = IO_Event_Selector_io_descriptor(io);
752
-
753
755
  size_t length = NUM2SIZET(_length);
754
756
  size_t offset = NUM2SIZET(_offset);
755
757
 
758
+ const void *base;
759
+ size_t size;
760
+ rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
761
+
762
+ if (length > size) {
763
+ rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
764
+ }
765
+
766
+ if (offset > size) {
767
+ return rb_fiber_scheduler_io_result(-1, EINVAL);
768
+ } else if (offset == size) {
769
+ return rb_fiber_scheduler_io_result(0, 0);
770
+ }
771
+
772
+ base = (const char*)base + offset;
773
+ size -= offset;
774
+
775
+ int descriptor = IO_Event_Selector_io_descriptor(io);
776
+
756
777
  struct io_write_arguments io_write_arguments = {
757
778
  .self = self,
758
779
  .fiber = fiber,
@@ -760,9 +781,9 @@ VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
760
781
 
761
782
  .flags = IO_Event_Selector_nonblock_set(descriptor),
762
783
  .descriptor = descriptor,
763
- .buffer = buffer,
784
+ .base = base,
785
+ .size = size,
764
786
  .length = length,
765
- .offset = offset,
766
787
  };
767
788
 
768
789
  RB_OBJ_WRITTEN(self, Qundef, fiber);
@@ -1079,6 +1100,7 @@ void Init_IO_Event_Selector_EPoll(VALUE IO_Event_Selector) {
1079
1100
  rb_define_method(IO_Event_Selector_EPoll, "select", IO_Event_Selector_EPoll_select, 1);
1080
1101
  rb_define_method(IO_Event_Selector_EPoll, "wakeup", IO_Event_Selector_EPoll_wakeup, 0);
1081
1102
  rb_define_method(IO_Event_Selector_EPoll, "close", IO_Event_Selector_EPoll_close, 0);
1103
+ rb_define_method(IO_Event_Selector_EPoll, "closed?", IO_Event_Selector_EPoll_closed_p, 0);
1082
1104
 
1083
1105
  rb_define_method(IO_Event_Selector_EPoll, "io_wait", IO_Event_Selector_EPoll_io_wait, 3);
1084
1106
 
@@ -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,6 +48,7 @@ struct IO_Event_Selector_KQueue
47
48
  {
48
49
  struct IO_Event_Selector backend;
49
50
  int descriptor;
51
+ pid_t owner;
50
52
 
51
53
  // Flag indicating whether the selector is currently blocked in a system call.
52
54
  // Set to 1 when blocked in kevent() without GVL, 0 otherwise.
@@ -132,7 +134,14 @@ static
132
134
  void close_internal(struct IO_Event_Selector_KQueue *selector)
133
135
  {
134
136
  if (selector->descriptor >= 0) {
135
- close(selector->descriptor);
137
+ if (selector->owner == getpid()) {
138
+ close(selector->descriptor);
139
+
140
+ #ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
141
+ IO_Event_Interrupt_close(&selector->interrupt);
142
+ #endif
143
+ }
144
+
136
145
  selector->descriptor = -1;
137
146
  }
138
147
  }
@@ -289,6 +298,7 @@ VALUE IO_Event_Selector_KQueue_allocate(VALUE self) {
289
298
 
290
299
  IO_Event_Selector_initialize(&selector->backend, self, Qnil);
291
300
  selector->descriptor = -1;
301
+ selector->owner = 0;
292
302
  selector->blocked = 0;
293
303
 
294
304
  selector->descriptors.element_initialize = IO_Event_Selector_KQueue_Descriptor_initialize;
@@ -331,6 +341,7 @@ VALUE IO_Event_Selector_KQueue_initialize(VALUE self, VALUE loop) {
331
341
  ioctl(result, FIOCLEX);
332
342
 
333
343
  selector->descriptor = result;
344
+ selector->owner = getpid();
334
345
 
335
346
  rb_update_max_fd(selector->descriptor);
336
347
  }
@@ -365,13 +376,16 @@ VALUE IO_Event_Selector_KQueue_close(VALUE self) {
365
376
 
366
377
  close_internal(selector);
367
378
 
368
- #ifdef IO_EVENT_SELECTOR_KQUEUE_USE_INTERRUPT
369
- IO_Event_Interrupt_close(&selector->interrupt);
370
- #endif
371
-
372
379
  return Qnil;
373
380
  }
374
381
 
382
+ VALUE IO_Event_Selector_KQueue_closed_p(VALUE self) {
383
+ struct IO_Event_Selector_KQueue *selector = NULL;
384
+ TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
385
+
386
+ return selector->descriptor < 0 || selector->owner != getpid() ? Qtrue : Qfalse;
387
+ }
388
+
375
389
  VALUE IO_Event_Selector_KQueue_transfer(VALUE self)
376
390
  {
377
391
  struct IO_Event_Selector_KQueue *selector = NULL;
@@ -578,40 +592,33 @@ struct io_read_arguments {
578
592
 
579
593
  int descriptor;
580
594
 
581
- VALUE buffer;
595
+ // The remaining writable buffer region after applying the requested offset.
596
+ void *base;
597
+ size_t size;
598
+
599
+ // The minimum number of bytes requested by the caller.
582
600
  size_t length;
583
- size_t offset;
584
601
  };
585
602
 
586
603
  static
587
604
  VALUE io_read_loop(VALUE _arguments) {
588
605
  struct io_read_arguments *arguments = (struct io_read_arguments *)_arguments;
589
606
 
590
- void *base;
591
- size_t size;
592
- rb_io_buffer_get_bytes_for_writing(arguments->buffer, &base, &size);
593
-
594
607
  size_t length = arguments->length;
595
- size_t offset = arguments->offset;
596
608
  size_t total = 0;
597
609
 
598
610
  if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu)\n", arguments->descriptor, length);
599
611
 
600
- // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
601
- if (offset > size) {
602
- return rb_fiber_scheduler_io_result(-1, EINVAL);
603
- }
604
-
605
- size_t maximum_size = size - offset;
612
+ size_t maximum_size = arguments->size;
606
613
  while (maximum_size) {
607
- if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld)\n", arguments->descriptor, offset, maximum_size);
608
- ssize_t result = read(arguments->descriptor, (char*)base+offset, maximum_size);
609
- if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld) -> %zd\n", arguments->descriptor, offset, maximum_size, result);
614
+ if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld)\n", arguments->descriptor, total, maximum_size);
615
+ ssize_t result = read(arguments->descriptor, (char*)arguments->base+total, maximum_size);
616
+ if (DEBUG_IO_READ) fprintf(stderr, "read(%d, +%ld, %ld) -> %zd\n", arguments->descriptor, total, maximum_size, result);
610
617
 
611
618
  if (result > 0) {
612
619
  total += result;
613
- offset += result;
614
620
  if ((size_t)result >= length) break;
621
+ maximum_size -= result;
615
622
  length -= result;
616
623
  } else if (result == 0) {
617
624
  break;
@@ -622,11 +629,9 @@ VALUE io_read_loop(VALUE _arguments) {
622
629
  if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu) -> errno=%d\n", arguments->descriptor, length, errno);
623
630
  return rb_fiber_scheduler_io_result(-1, errno);
624
631
  }
625
-
626
- maximum_size = size - offset;
627
632
  }
628
633
 
629
- if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length, offset);
634
+ if (DEBUG_IO_READ) fprintf(stderr, "io_read_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length, total);
630
635
  return rb_fiber_scheduler_io_result(total, 0);
631
636
  }
632
637
 
@@ -643,11 +648,24 @@ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
643
648
  struct IO_Event_Selector_KQueue *selector = NULL;
644
649
  TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
645
650
 
646
- int descriptor = IO_Event_Selector_io_descriptor(io);
647
-
648
651
  size_t length = NUM2SIZET(_length);
649
652
  size_t offset = NUM2SIZET(_offset);
650
653
 
654
+ void *base;
655
+ size_t size;
656
+ rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
657
+
658
+ if (offset > size) {
659
+ return rb_fiber_scheduler_io_result(-1, EINVAL);
660
+ } else if (offset == size) {
661
+ return rb_fiber_scheduler_io_result(0, 0);
662
+ }
663
+
664
+ base = (char*)base + offset;
665
+ size -= offset;
666
+
667
+ int descriptor = IO_Event_Selector_io_descriptor(io);
668
+
651
669
  struct io_read_arguments io_read_arguments = {
652
670
  .self = self,
653
671
  .fiber = fiber,
@@ -655,9 +673,9 @@ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
655
673
 
656
674
  .flags = IO_Event_Selector_nonblock_set(descriptor),
657
675
  .descriptor = descriptor,
658
- .buffer = buffer,
676
+ .base = base,
677
+ .size = size,
659
678
  .length = length,
660
- .offset = offset,
661
679
  };
662
680
 
663
681
  RB_OBJ_WRITTEN(self, Qundef, fiber);
@@ -687,44 +705,33 @@ struct io_write_arguments {
687
705
 
688
706
  int descriptor;
689
707
 
690
- VALUE buffer;
708
+ // The remaining readable buffer region after applying the requested offset.
709
+ const void *base;
710
+ size_t size;
711
+
712
+ // The minimum number of bytes requested by the caller.
691
713
  size_t length;
692
- size_t offset;
693
714
  };
694
715
 
695
716
  static
696
717
  VALUE io_write_loop(VALUE _arguments) {
697
718
  struct io_write_arguments *arguments = (struct io_write_arguments *)_arguments;
698
719
 
699
- const void *base;
700
- size_t size;
701
- rb_io_buffer_get_bytes_for_reading(arguments->buffer, &base, &size);
702
-
703
720
  size_t length = arguments->length;
704
- size_t offset = arguments->offset;
705
721
  size_t total = 0;
706
722
 
707
- if (length > size) {
708
- rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
709
- }
710
-
711
723
  if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu)\n", arguments->descriptor, length);
712
724
 
713
- // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
714
- if (offset > size) {
715
- return rb_fiber_scheduler_io_result(-1, EINVAL);
716
- }
717
-
718
- size_t maximum_size = size - offset;
725
+ size_t maximum_size = arguments->size;
719
726
  while (maximum_size) {
720
- if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld, length=%zu)\n", arguments->descriptor, offset, maximum_size, length);
721
- ssize_t result = write(arguments->descriptor, (char*)base+offset, maximum_size);
722
- if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld) -> %zd\n", arguments->descriptor, offset, maximum_size, result);
727
+ if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld, length=%zu)\n", arguments->descriptor, total, maximum_size, length);
728
+ ssize_t result = write(arguments->descriptor, (char*)arguments->base+total, maximum_size);
729
+ if (DEBUG_IO_WRITE) fprintf(stderr, "write(%d, +%ld, %ld) -> %zd\n", arguments->descriptor, total, maximum_size, result);
723
730
 
724
731
  if (result > 0) {
725
732
  total += result;
726
- offset += result;
727
733
  if ((size_t)result >= length) break;
734
+ maximum_size -= result;
728
735
  length -= result;
729
736
  } else if (result == 0) {
730
737
  break;
@@ -735,11 +742,9 @@ VALUE io_write_loop(VALUE _arguments) {
735
742
  if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu) -> errno=%d\n", arguments->descriptor, length, errno);
736
743
  return rb_fiber_scheduler_io_result(-1, errno);
737
744
  }
738
-
739
- maximum_size = size - offset;
740
745
  }
741
746
 
742
- if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length, offset);
747
+ if (DEBUG_IO_WRITE) fprintf(stderr, "io_write_loop(fd=%d, length=%zu) -> %zu\n", arguments->descriptor, length, total);
743
748
  return rb_fiber_scheduler_io_result(total, 0);
744
749
  };
745
750
 
@@ -756,11 +761,28 @@ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
756
761
  struct IO_Event_Selector_KQueue *selector = NULL;
757
762
  TypedData_Get_Struct(self, struct IO_Event_Selector_KQueue, &IO_Event_Selector_KQueue_Type, selector);
758
763
 
759
- int descriptor = IO_Event_Selector_io_descriptor(io);
760
-
761
764
  size_t length = NUM2SIZET(_length);
762
765
  size_t offset = NUM2SIZET(_offset);
763
766
 
767
+ const void *base;
768
+ size_t size;
769
+ rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
770
+
771
+ if (length > size) {
772
+ rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
773
+ }
774
+
775
+ if (offset > size) {
776
+ return rb_fiber_scheduler_io_result(-1, EINVAL);
777
+ } else if (offset == size) {
778
+ return rb_fiber_scheduler_io_result(0, 0);
779
+ }
780
+
781
+ base = (const char*)base + offset;
782
+ size -= offset;
783
+
784
+ int descriptor = IO_Event_Selector_io_descriptor(io);
785
+
764
786
  struct io_write_arguments io_write_arguments = {
765
787
  .self = self,
766
788
  .fiber = fiber,
@@ -768,9 +790,9 @@ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
768
790
 
769
791
  .flags = IO_Event_Selector_nonblock_set(descriptor),
770
792
  .descriptor = descriptor,
771
- .buffer = buffer,
793
+ .base = base,
794
+ .size = size,
772
795
  .length = length,
773
- .offset = offset,
774
796
  };
775
797
 
776
798
  RB_OBJ_WRITTEN(self, Qundef, fiber);
@@ -1090,6 +1112,7 @@ void Init_IO_Event_Selector_KQueue(VALUE IO_Event_Selector) {
1090
1112
  rb_define_method(IO_Event_Selector_KQueue, "select", IO_Event_Selector_KQueue_select, 1);
1091
1113
  rb_define_method(IO_Event_Selector_KQueue, "wakeup", IO_Event_Selector_KQueue_wakeup, 0);
1092
1114
  rb_define_method(IO_Event_Selector_KQueue, "close", IO_Event_Selector_KQueue_close, 0);
1115
+ rb_define_method(IO_Event_Selector_KQueue, "closed?", IO_Event_Selector_KQueue_closed_p, 0);
1093
1116
 
1094
1117
  rb_define_method(IO_Event_Selector_KQueue, "io_wait", IO_Event_Selector_KQueue_io_wait, 3);
1095
1118
 
@@ -11,6 +11,7 @@
11
11
  #include <stdbool.h>
12
12
  #include <stdint.h>
13
13
  #include <time.h>
14
+ #include <unistd.h>
14
15
 
15
16
  #include "../interrupt.h"
16
17
 
@@ -32,6 +33,7 @@ struct IO_Event_Selector_URing
32
33
  {
33
34
  struct IO_Event_Selector backend;
34
35
  struct io_uring ring;
36
+ pid_t owner;
35
37
 
36
38
  // Flag indicating whether the selector is currently blocked in a system call.
37
39
  // Set to 1 when blocked in io_uring_wait_cqe_timeout() without GVL, 0 otherwise.
@@ -115,14 +117,20 @@ void IO_Event_Selector_URing_Type_compact(void *_selector)
115
117
  static
116
118
  void close_internal(struct IO_Event_Selector_URing *selector)
117
119
  {
118
- if (selector->interrupt.descriptor >= 0) {
119
- IO_Event_Interrupt_close(&selector->interrupt);
120
+ if (selector->owner == getpid()) {
121
+ if (selector->interrupt.descriptor >= 0) {
122
+ IO_Event_Interrupt_close(&selector->interrupt);
123
+ selector->interrupt.descriptor = -1;
124
+ selector->wakeup_registered = 0;
125
+ }
126
+
127
+ if (selector->ring.ring_fd >= 0) {
128
+ io_uring_queue_exit(&selector->ring);
129
+ selector->ring.ring_fd = -1;
130
+ }
131
+ } else {
120
132
  selector->interrupt.descriptor = -1;
121
133
  selector->wakeup_registered = 0;
122
- }
123
-
124
- if (selector->ring.ring_fd >= 0) {
125
- io_uring_queue_exit(&selector->ring);
126
134
  selector->ring.ring_fd = -1;
127
135
  }
128
136
  }
@@ -237,6 +245,7 @@ VALUE IO_Event_Selector_URing_allocate(VALUE self) {
237
245
 
238
246
  IO_Event_Selector_initialize(&selector->backend, self, Qnil);
239
247
  selector->ring.ring_fd = -1;
248
+ selector->owner = 0;
240
249
 
241
250
  selector->blocked = 0;
242
251
  selector->interrupt.descriptor = -1;
@@ -299,6 +308,8 @@ VALUE IO_Event_Selector_URing_initialize(VALUE self, VALUE loop) {
299
308
  rb_syserr_fail(-result, "IO_Event_Selector_URing_initialize:io_uring_queue_init");
300
309
  }
301
310
 
311
+ selector->owner = getpid();
312
+
302
313
  rb_update_max_fd(selector->ring.ring_fd);
303
314
 
304
315
  // Interrupt for cross-thread wakeup: another thread calls signal(); the owner
@@ -339,6 +350,13 @@ VALUE IO_Event_Selector_URing_close(VALUE self) {
339
350
  return Qnil;
340
351
  }
341
352
 
353
+ VALUE IO_Event_Selector_URing_closed_p(VALUE self) {
354
+ struct IO_Event_Selector_URing *selector = NULL;
355
+ TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
356
+
357
+ return selector->ring.ring_fd < 0 || selector->owner != getpid() ? Qtrue : Qfalse;
358
+ }
359
+
342
360
  VALUE IO_Event_Selector_URing_transfer(VALUE self)
343
361
  {
344
362
  struct IO_Event_Selector_URing *selector = NULL;
@@ -757,8 +775,6 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
757
775
  struct IO_Event_Selector_URing *selector = NULL;
758
776
  TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
759
777
 
760
- int descriptor = IO_Event_Selector_io_descriptor(io);
761
-
762
778
  void *base;
763
779
  size_t size;
764
780
  rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
@@ -766,13 +782,17 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
766
782
  size_t length = NUM2SIZET(_length);
767
783
  size_t offset = NUM2SIZET(_offset);
768
784
  size_t total = 0;
769
- off_t from = io_seekable(descriptor);
770
785
 
771
786
  // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
772
787
  if (offset > size) {
773
788
  return rb_fiber_scheduler_io_result(-1, EINVAL);
789
+ } else if (offset == size) {
790
+ return rb_fiber_scheduler_io_result(0, 0);
774
791
  }
775
792
 
793
+ int descriptor = IO_Event_Selector_io_descriptor(io);
794
+ off_t from = io_seekable(descriptor);
795
+
776
796
  size_t maximum_size = size - offset;
777
797
 
778
798
  // Are we performing a non-blocking read?
@@ -827,8 +847,6 @@ VALUE IO_Event_Selector_URing_io_pread(VALUE self, VALUE fiber, VALUE io, VALUE
827
847
  struct IO_Event_Selector_URing *selector = NULL;
828
848
  TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
829
849
 
830
- int descriptor = IO_Event_Selector_io_descriptor(io);
831
-
832
850
  void *base;
833
851
  size_t size;
834
852
  rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
@@ -841,8 +859,12 @@ VALUE IO_Event_Selector_URing_io_pread(VALUE self, VALUE fiber, VALUE io, VALUE
841
859
  // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
842
860
  if (offset > size) {
843
861
  return rb_fiber_scheduler_io_result(-1, EINVAL);
862
+ } else if (offset == size) {
863
+ return rb_fiber_scheduler_io_result(0, 0);
844
864
  }
845
865
 
866
+ int descriptor = IO_Event_Selector_io_descriptor(io);
867
+
846
868
  size_t maximum_size = size - offset;
847
869
  while (maximum_size) {
848
870
  int result = io_read(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
@@ -945,8 +967,6 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
945
967
  struct IO_Event_Selector_URing *selector = NULL;
946
968
  TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
947
969
 
948
- int descriptor = IO_Event_Selector_io_descriptor(io);
949
-
950
970
  const void *base;
951
971
  size_t size;
952
972
  rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
@@ -954,7 +974,6 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
954
974
  size_t length = NUM2SIZET(_length);
955
975
  size_t offset = NUM2SIZET(_offset);
956
976
  size_t total = 0;
957
- off_t from = io_seekable(descriptor);
958
977
 
959
978
  if (length > size) {
960
979
  rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
@@ -963,8 +982,13 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
963
982
  // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
964
983
  if (offset > size) {
965
984
  return rb_fiber_scheduler_io_result(-1, EINVAL);
985
+ } else if (offset == size) {
986
+ return rb_fiber_scheduler_io_result(0, 0);
966
987
  }
967
-
988
+
989
+ int descriptor = IO_Event_Selector_io_descriptor(io);
990
+ off_t from = io_seekable(descriptor);
991
+
968
992
  size_t maximum_size = size - offset;
969
993
  while (maximum_size) {
970
994
  int result = io_write(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
@@ -1005,8 +1029,6 @@ VALUE IO_Event_Selector_URing_io_pwrite(VALUE self, VALUE fiber, VALUE io, VALUE
1005
1029
  struct IO_Event_Selector_URing *selector = NULL;
1006
1030
  TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
1007
1031
 
1008
- int descriptor = IO_Event_Selector_io_descriptor(io);
1009
-
1010
1032
  const void *base;
1011
1033
  size_t size;
1012
1034
  rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
@@ -1023,8 +1045,12 @@ VALUE IO_Event_Selector_URing_io_pwrite(VALUE self, VALUE fiber, VALUE io, VALUE
1023
1045
  // Ensure offset is within the bounds of the buffer to avoid size_t underflow and out-of-bounds pointer arithmetic on (char *)base + offset.
1024
1046
  if (offset > size) {
1025
1047
  return rb_fiber_scheduler_io_result(-1, EINVAL);
1048
+ } else if (offset == size) {
1049
+ return rb_fiber_scheduler_io_result(0, 0);
1026
1050
  }
1027
-
1051
+
1052
+ int descriptor = IO_Event_Selector_io_descriptor(io);
1053
+
1028
1054
  size_t maximum_size = size - offset;
1029
1055
  while (maximum_size) {
1030
1056
  int result = io_write(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
@@ -1370,6 +1396,7 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
1370
1396
  rb_define_method(IO_Event_Selector_URing, "select", IO_Event_Selector_URing_select, 1);
1371
1397
  rb_define_method(IO_Event_Selector_URing, "wakeup", IO_Event_Selector_URing_wakeup, 0);
1372
1398
  rb_define_method(IO_Event_Selector_URing, "close", IO_Event_Selector_URing_close, 0);
1399
+ rb_define_method(IO_Event_Selector_URing, "closed?", IO_Event_Selector_URing_closed_p, 0);
1373
1400
 
1374
1401
  rb_define_method(IO_Event_Selector_URing, "io_wait", IO_Event_Selector_URing_io_wait, 3);
1375
1402
 
@@ -111,6 +111,11 @@ module IO::Event
111
111
  @log&.flush
112
112
  end
113
113
 
114
+ # @returns [Boolean] Whether the wrapped selector is closed.
115
+ def closed?
116
+ @selector.nil? || @selector.closed?
117
+ end
118
+
114
119
  # Transfer from the calling fiber to the selector.
115
120
  def transfer
116
121
  log("Transfering to event loop")
@@ -13,6 +13,7 @@ module IO::Event
13
13
  # Initialize the selector with the given event loop fiber.
14
14
  def initialize(loop)
15
15
  @loop = loop
16
+ @owner = Process.pid
16
17
 
17
18
  @waiting = Hash.new.compare_by_identity
18
19
 
@@ -52,6 +53,11 @@ module IO::Event
52
53
  @waiting = nil
53
54
  end
54
55
 
56
+ # @returns [Boolean] Whether the selector is closed or belongs to a different process.
57
+ def closed?
58
+ @loop.nil? || @owner != Process.pid
59
+ end
60
+
55
61
  # An optional reference to a fiber which can be cleared before it is resumed.
56
62
  Optional = Struct.new(:fiber) do
57
63
  # Transfer control to the fiber if it is still available.
@@ -199,6 +205,8 @@ module IO::Event
199
205
  # Ensure offset is within the bounds of the buffer to avoid ArgumentError
200
206
  if offset > buffer.size
201
207
  return -Errno::EINVAL::Errno
208
+ elsif offset == buffer.size
209
+ return 0
202
210
  end
203
211
 
204
212
  total = 0
@@ -234,6 +242,8 @@ module IO::Event
234
242
  # Ensure offset is within the bounds of the buffer to avoid ArgumentError
235
243
  if offset > buffer.size
236
244
  return -Errno::EINVAL::Errno
245
+ elsif offset == buffer.size
246
+ return 0
237
247
  end
238
248
 
239
249
  total = 0
@@ -7,6 +7,6 @@
7
7
  class IO
8
8
  # @namespace
9
9
  module Event
10
- VERSION = "1.16.4"
10
+ VERSION = "1.17.0"
11
11
  end
12
12
  end
data/readme.md CHANGED
@@ -18,6 +18,10 @@ Please see the [project documentation](https://socketry.github.io/io-event/) for
18
18
 
19
19
  Please see the [project releases](https://socketry.github.io/io-event/releases/index) for all releases.
20
20
 
21
+ ### v1.17.0
22
+
23
+ - Report inherited selector objects as closed after fork, and avoid closing descriptors they no longer own.
24
+
21
25
  ### v1.16.4
22
26
 
23
27
  - Correctly implement `Interrupt#signal` so that it is robust enough to be called by `Scheduler#unblock`.
@@ -60,10 +64,6 @@ Please see the [project releases](https://socketry.github.io/io-event/releases/i
60
64
 
61
65
  - Fix several implementation bugs that could cause deadlocks on blocking writes.
62
66
 
63
- ### v1.14.0
64
-
65
- - [Enhanced `IO::Event::PriorityHeap` with deletion and bulk insertion methods](https://socketry.github.io/io-event/releases/index#enhanced-io::event::priorityheap-with-deletion-and-bulk-insertion-methods)
66
-
67
67
  ## Contributing
68
68
 
69
69
  We welcome contributions to this project.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v1.17.0
4
+
5
+ - Report inherited selector objects as closed after fork, and avoid closing descriptors they no longer own.
6
+
3
7
  ## v1.16.4
4
8
 
5
9
  - Correctly implement `Interrupt#signal` so that it is robust enough to be called by `Scheduler#unblock`.
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.16.4
4
+ version: 1.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
metadata.gz.sig CHANGED
Binary file