io-event 1.7.0 → 1.7.2

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: 542a0e0f15dd7d59246ac8b03a3579ff9fe8e85618009277572b04a1d1fdbfc9
4
- data.tar.gz: e440cf4f7f2a33a7e7c0b995f4b7829d4d66a44acb3f3d3ca00683b838062fcb
3
+ metadata.gz: 00ee9c58a1f3c352028955bd7fa687b868a38d658f076ed128999e434a50e67f
4
+ data.tar.gz: 8bb4a29b1f992e2fdf5b155e8efb1361e70cf1a635bbcac75723d6e255b27d92
5
5
  SHA512:
6
- metadata.gz: cd577bac5f3b70b70af3ca48f012179ec8d1b1774fc89cd46982fed601fe3a163a9ae9742b58ded385764c5233abc90cbf63f3b2563a114d232233085ba1c5ef
7
- data.tar.gz: ff23dd077067823bd748d89482d39bb1b49cee26e87b6733561d2c3c09ffa3711015d0e8da514ac4851eccd81b84b0e7b66c2d5d7815ade30c551052e0dda536
6
+ metadata.gz: 6882b4c368d9b5e1fd32d3545409d311db6d5624ae9353f1112c0f3960a85e62685aaa05ff9a20612c2e17bb8d286e1ce88be5024ed0d343713c8ddf378f9d05
7
+ data.tar.gz: be96ca6107b200375af43eefad3b549eff15a7e4ad90798fb695c20dcd711f557b405a9c8f36d40324531ab92f03e1dbbaadb07419d7091ae7f6247567573877
checksums.yaml.gz.sig CHANGED
Binary file
data/ext/extconf.rb CHANGED
@@ -30,6 +30,9 @@ have_func("rb_ext_ractor_safe")
30
30
  have_func("&rb_fiber_transfer")
31
31
 
32
32
  if have_library("uring") and have_header("liburing.h")
33
+ # We might want to consider using this in the future:
34
+ # have_func("io_uring_submit_and_wait_timeout", "liburing.h")
35
+
33
36
  $srcs << "io/event/selector/uring.c"
34
37
  end
35
38
 
@@ -8,6 +8,11 @@
8
8
  #include <errno.h>
9
9
  #include <assert.h>
10
10
 
11
+ enum {
12
+ IO_EVENT_ARRAY_MAXIMUM_COUNT = SIZE_MAX / sizeof(void*),
13
+ IO_EVENT_ARRAY_DEFAULT_COUNT = 128
14
+ };
15
+
11
16
  struct IO_Event_Array {
12
17
  // The array of pointers to elements:
13
18
  void **base;
@@ -25,20 +30,27 @@ struct IO_Event_Array {
25
30
  void (*element_free)(void*);
26
31
  };
27
32
 
28
- inline static void IO_Event_Array_allocate(struct IO_Event_Array *array, size_t count, size_t element_size)
33
+ inline static int IO_Event_Array_allocate(struct IO_Event_Array *array, size_t count, size_t element_size)
29
34
  {
35
+ array->limit = 0;
36
+ array->element_size = element_size;
37
+
30
38
  if (count) {
31
39
  array->base = (void**)calloc(count, sizeof(void*));
32
- assert(array->base);
40
+
41
+ if (array->base == NULL) {
42
+ return -1;
43
+ }
33
44
 
34
45
  array->count = count;
46
+
47
+ return 1;
35
48
  } else {
36
49
  array->base = NULL;
37
50
  array->count = 0;
51
+
52
+ return 0;
38
53
  }
39
-
40
- array->limit = 0;
41
- array->element_size = element_size;
42
54
  }
43
55
 
44
56
  inline static size_t IO_Event_Array_memory_size(const struct IO_Event_Array *array)
@@ -49,32 +61,51 @@ inline static size_t IO_Event_Array_memory_size(const struct IO_Event_Array *arr
49
61
 
50
62
  inline static void IO_Event_Array_free(struct IO_Event_Array *array)
51
63
  {
52
- for (size_t i = 0; i < array->limit; i += 1) {
53
- void *element = array->base[i];
54
- if (element) {
55
- array->element_free(element);
56
-
57
- free(element);
64
+ if (array->base) {
65
+ void **base = array->base;
66
+ size_t limit = array->limit;
67
+
68
+ array->base = NULL;
69
+ array->count = 0;
70
+ array->limit = 0;
71
+
72
+ for (size_t i = 0; i < limit; i += 1) {
73
+ void *element = base[i];
74
+ if (element) {
75
+ array->element_free(element);
76
+
77
+ free(element);
78
+ }
58
79
  }
80
+
81
+ free(base);
59
82
  }
60
-
61
- if (array->base)
62
- free(array->base);
63
-
64
- array->base = NULL;
65
- array->count = 0;
66
- array->limit = 0;
67
83
  }
68
84
 
69
85
  inline static int IO_Event_Array_resize(struct IO_Event_Array *array, size_t count)
70
86
  {
71
87
  if (count <= array->count) {
88
+ // Already big enough:
72
89
  return 0;
73
90
  }
74
91
 
75
- // Compute the next multiple (ideally a power of 2):
92
+ if (count > IO_EVENT_ARRAY_MAXIMUM_COUNT) {
93
+ errno = ENOMEM;
94
+ return -1;
95
+ }
96
+
76
97
  size_t new_count = array->count;
77
- while (new_count < count) {
98
+
99
+ // If the array is empty, we need to set the initial size:
100
+ if (new_count == 0) new_count = IO_EVENT_ARRAY_DEFAULT_COUNT;
101
+ else while (new_count < count) {
102
+ // Ensure we don't overflow:
103
+ if (new_count > (IO_EVENT_ARRAY_MAXIMUM_COUNT / 2)) {
104
+ new_count = IO_EVENT_ARRAY_MAXIMUM_COUNT;
105
+ break;
106
+ }
107
+
108
+ // Compute the next multiple (ideally a power of 2):
78
109
  new_count *= 2;
79
110
  }
80
111
 
@@ -90,6 +121,7 @@ inline static int IO_Event_Array_resize(struct IO_Event_Array *array, size_t cou
90
121
  array->base = (void**)new_base;
91
122
  array->count = new_count;
92
123
 
124
+ // Resizing sucessful:
93
125
  return 1;
94
126
  }
95
127
 
@@ -241,7 +241,7 @@ int IO_Event_Selector_EPoll_Descriptor_update(struct IO_Event_Selector_EPoll *se
241
241
  } else {
242
242
  // The IO has changed, we need to reset the state:
243
243
  epoll_descriptor->registered_events = 0;
244
- epoll_descriptor->io = io;
244
+ RB_OBJ_WRITE(selector->backend.self, &epoll_descriptor->io, io);
245
245
  }
246
246
 
247
247
  if (epoll_descriptor->waiting_events == 0) {
@@ -251,7 +251,7 @@ int IO_Event_Selector_EPoll_Descriptor_update(struct IO_Event_Selector_EPoll *se
251
251
  epoll_descriptor->registered_events = 0;
252
252
  }
253
253
 
254
- epoll_descriptor->io = 0;
254
+ RB_OBJ_WRITE(selector->backend.self, &epoll_descriptor->io, 0);
255
255
 
256
256
  return 0;
257
257
  }
@@ -337,7 +337,10 @@ VALUE IO_Event_Selector_EPoll_allocate(VALUE self) {
337
337
 
338
338
  selector->descriptors.element_initialize = IO_Event_Selector_EPoll_Descriptor_initialize;
339
339
  selector->descriptors.element_free = IO_Event_Selector_EPoll_Descriptor_free;
340
- IO_Event_Array_allocate(&selector->descriptors, 1024, sizeof(struct IO_Event_Selector_EPoll_Descriptor));
340
+ int result = IO_Event_Array_allocate(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_EPoll_Descriptor));
341
+ if (result < 0) {
342
+ rb_sys_fail("IO_Event_Selector_EPoll_allocate:IO_Event_Array_allocate");
343
+ }
341
344
 
342
345
  return instance;
343
346
  }
@@ -507,6 +510,8 @@ VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid,
507
510
  .events = IO_EVENT_READABLE,
508
511
  };
509
512
 
513
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
514
+
510
515
  int result = IO_Event_Selector_EPoll_Waiting_register(selector, 0, descriptor, &waiting);
511
516
 
512
517
  if (result == -1) {
@@ -566,6 +571,8 @@ VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
566
571
  .events = RB_NUM2INT(events),
567
572
  };
568
573
 
574
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
575
+
569
576
  int result = IO_Event_Selector_EPoll_Waiting_register(selector, io, descriptor, &waiting);
570
577
 
571
578
  if (result == -1) {
@@ -664,6 +671,8 @@ VALUE IO_Event_Selector_EPoll_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
664
671
  .offset = offset,
665
672
  };
666
673
 
674
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
675
+
667
676
  return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
668
677
  }
669
678
 
@@ -760,6 +769,8 @@ VALUE IO_Event_Selector_EPoll_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
760
769
  .offset = offset,
761
770
  };
762
771
 
772
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
773
+
763
774
  return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
764
775
  }
765
776
 
@@ -311,7 +311,11 @@ VALUE IO_Event_Selector_KQueue_allocate(VALUE self) {
311
311
 
312
312
  selector->descriptors.element_initialize = IO_Event_Selector_KQueue_Descriptor_initialize;
313
313
  selector->descriptors.element_free = IO_Event_Selector_KQueue_Descriptor_free;
314
- IO_Event_Array_allocate(&selector->descriptors, 1024, sizeof(struct IO_Event_Selector_KQueue_Descriptor));
314
+
315
+ int result = IO_Event_Array_allocate(&selector->descriptors, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_KQueue_Descriptor));
316
+ if (result < 0) {
317
+ rb_sys_fail("IO_Event_Selector_KQueue_allocate:IO_Event_Array_allocate");
318
+ }
315
319
 
316
320
  return instance;
317
321
  }
@@ -501,6 +505,8 @@ VALUE IO_Event_Selector_KQueue_process_wait(VALUE self, VALUE fiber, VALUE _pid,
501
505
  .events = IO_EVENT_EXIT,
502
506
  };
503
507
 
508
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
509
+
504
510
  struct process_wait_arguments process_wait_arguments = {
505
511
  .selector = selector,
506
512
  .waiting = &waiting,
@@ -564,6 +570,8 @@ VALUE IO_Event_Selector_KQueue_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE
564
570
  .events = RB_NUM2INT(events),
565
571
  };
566
572
 
573
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
574
+
567
575
  int result = IO_Event_Selector_KQueue_Waiting_register(selector, descriptor, &waiting);
568
576
  if (result == -1) {
569
577
  rb_sys_fail("IO_Event_Selector_KQueue_io_wait:IO_Event_Selector_KQueue_Waiting_register");
@@ -667,6 +675,8 @@ VALUE IO_Event_Selector_KQueue_io_read(VALUE self, VALUE fiber, VALUE io, VALUE
667
675
  .offset = offset,
668
676
  };
669
677
 
678
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
679
+
670
680
  return rb_ensure(io_read_loop, (VALUE)&io_read_arguments, io_read_ensure, (VALUE)&io_read_arguments);
671
681
  }
672
682
 
@@ -773,6 +783,8 @@ VALUE IO_Event_Selector_KQueue_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
773
783
  .offset = offset,
774
784
  };
775
785
 
786
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
787
+
776
788
  return rb_ensure(io_write_loop, (VALUE)&io_write_arguments, io_write_ensure, (VALUE)&io_write_arguments);
777
789
  }
778
790
 
@@ -979,7 +991,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
979
991
  // Non-comprehensive testing shows this gives a 1.5x speedup.
980
992
 
981
993
  // First do the syscall with no timeout to get any immediately available events:
982
- if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl timeout=" PRINTF_TIMESPEC "\r\n", PRINTF_TIMESPEC_ARGS(arguments.storage));
994
+ if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl timeout=" IO_EVENT_PRINTF_TIMESPEC "\r\n", IO_EVENT_PRINTF_TIMESPEC_ARGUMENTS(arguments.storage));
983
995
  select_internal_with_gvl(&arguments);
984
996
  if (DEBUG) fprintf(stderr, "\r\nselect_internal_with_gvl done\r\n");
985
997
 
@@ -997,7 +1009,7 @@ VALUE IO_Event_Selector_KQueue_select(VALUE self, VALUE duration) {
997
1009
  struct timespec start_time;
998
1010
  IO_Event_Selector_current_time(&start_time);
999
1011
 
1000
- if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout=" PRINTF_TIMESPEC "\n", PRINTF_TIMESPEC_ARGS(arguments.storage));
1012
+ if (DEBUG) fprintf(stderr, "IO_Event_Selector_KQueue_select timeout=" IO_EVENT_PRINTF_TIMESPEC "\n", IO_EVENT_PRINTF_TIMESPEC_ARGUMENTS(arguments.storage));
1001
1013
  select_internal_without_gvl(&arguments);
1002
1014
 
1003
1015
  struct timespec end_time;
@@ -38,6 +38,7 @@ inline static void IO_Event_List_append(struct IO_Event_List *list, struct IO_Ev
38
38
  head->tail = node;
39
39
  }
40
40
 
41
+ // Prepend an item to the beginning of the list.
41
42
  inline static void IO_Event_List_prepend(struct IO_Event_List *list, struct IO_Event_List *node)
42
43
  {
43
44
  assert(node->head == NULL);
@@ -64,6 +65,7 @@ inline static void IO_Event_List_pop(struct IO_Event_List *node)
64
65
  node->head = node->tail = NULL;
65
66
  }
66
67
 
68
+ // Remove an item from the list, if it is in a list.
67
69
  inline static void IO_Event_List_free(struct IO_Event_List *node)
68
70
  {
69
71
  if (node->head && node->tail) {
@@ -71,11 +73,27 @@ inline static void IO_Event_List_free(struct IO_Event_List *node)
71
73
  }
72
74
  }
73
75
 
74
- inline static int IO_Event_List_empty(struct IO_Event_List *list)
76
+ // Calculate the memory size of the list nodes.
77
+ inline static size_t IO_Event_List_memory_size(const struct IO_Event_List *list)
78
+ {
79
+ size_t memsize = 0;
80
+
81
+ const struct IO_Event_List *node = list->tail;
82
+ while (node != list) {
83
+ memsize += sizeof(struct IO_Event_List);
84
+ node = node->tail;
85
+ }
86
+
87
+ return memsize;
88
+ }
89
+
90
+ // Return true if the list is empty.
91
+ inline static int IO_Event_List_empty(const struct IO_Event_List *list)
75
92
  {
76
93
  return list->head == list->tail;
77
94
  }
78
95
 
96
+ // Enumerate all items in the list, assuming the list will not be modified during iteration.
79
97
  inline static void IO_Event_List_immutable_each(struct IO_Event_List *list, void (*callback)(struct IO_Event_List *node))
80
98
  {
81
99
  struct IO_Event_List *node = list->tail;
@@ -287,8 +287,7 @@ void IO_Event_Selector_queue_push(struct IO_Event_Selector *backend, VALUE fiber
287
287
  waiting->tail = NULL;
288
288
  waiting->flags = IO_EVENT_SELECTOR_QUEUE_INTERNAL;
289
289
 
290
- waiting->fiber = fiber;
291
- RB_OBJ_WRITTEN(backend->self, Qundef, fiber);
290
+ RB_OBJ_WRITE(backend->self, &waiting->fiber, fiber);
292
291
 
293
292
  queue_push(backend, waiting);
294
293
  }
@@ -152,5 +152,5 @@ int IO_Event_Selector_queue_flush(struct IO_Event_Selector *backend);
152
152
  void IO_Event_Selector_elapsed_time(struct timespec* start, struct timespec* stop, struct timespec *duration);
153
153
  void IO_Event_Selector_current_time(struct timespec *time);
154
154
 
155
- #define PRINTF_TIMESPEC "%lld.%.9ld"
156
- #define PRINTF_TIMESPEC_ARGS(ts) (long long)((ts).tv_sec), (ts).tv_nsec
155
+ #define IO_EVENT_PRINTF_TIMESPEC "%lld.%.9ld"
156
+ #define IO_EVENT_PRINTF_TIMESPEC_ARGUMENTS(ts) (long long)((ts).tv_sec), (ts).tv_nsec
@@ -35,6 +35,7 @@
35
35
  enum {
36
36
  DEBUG = 0,
37
37
  DEBUG_COMPLETION = 0,
38
+ DEBUG_IO_READ = 1,
38
39
  };
39
40
 
40
41
  enum {URING_ENTRIES = 64};
@@ -138,6 +139,7 @@ size_t IO_Event_Selector_URing_Type_size(const void *_selector)
138
139
 
139
140
  return sizeof(struct IO_Event_Selector_URing)
140
141
  + IO_Event_Array_memory_size(&selector->completions)
142
+ + IO_Event_List_memory_size(&selector->free_list)
141
143
  ;
142
144
  }
143
145
 
@@ -236,7 +238,10 @@ VALUE IO_Event_Selector_URing_allocate(VALUE self) {
236
238
 
237
239
  selector->completions.element_initialize = IO_Event_Selector_URing_Completion_initialize;
238
240
  selector->completions.element_free = IO_Event_Selector_URing_Completion_free;
239
- IO_Event_Array_allocate(&selector->completions, 1024, sizeof(struct IO_Event_Selector_URing_Completion));
241
+ int result = IO_Event_Array_allocate(&selector->completions, IO_EVENT_ARRAY_DEFAULT_COUNT, sizeof(struct IO_Event_Selector_URing_Completion));
242
+ if (result < 0) {
243
+ rb_sys_fail("IO_Event_Selector_URing_allocate:IO_Event_Array_allocate");
244
+ }
240
245
 
241
246
  return instance;
242
247
  }
@@ -482,6 +487,8 @@ VALUE IO_Event_Selector_URing_process_wait(VALUE self, VALUE fiber, VALUE _pid,
482
487
  .fiber = fiber,
483
488
  };
484
489
 
490
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
491
+
485
492
  struct IO_Event_Selector_URing_Completion *completion = IO_Event_Selector_URing_Completion_acquire(selector, &waiting);
486
493
 
487
494
  struct process_wait_arguments process_wait_arguments = {
@@ -585,6 +592,8 @@ VALUE IO_Event_Selector_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE e
585
592
  .fiber = fiber,
586
593
  };
587
594
 
595
+ RB_OBJ_WRITTEN(self, Qundef, fiber);
596
+
588
597
  struct IO_Event_Selector_URing_Completion *completion = IO_Event_Selector_URing_Completion_acquire(selector, &waiting);
589
598
 
590
599
  struct io_uring_sqe *sqe = io_get_sqe(selector);
@@ -628,6 +637,7 @@ struct io_read_arguments {
628
637
  struct IO_Event_Selector_URing *selector;
629
638
  struct IO_Event_Selector_URing_Waiting *waiting;
630
639
  int descriptor;
640
+ off_t offset;
631
641
  char *buffer;
632
642
  size_t length;
633
643
  };
@@ -641,7 +651,7 @@ io_read_submit(VALUE _arguments)
641
651
  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);
642
652
 
643
653
  struct io_uring_sqe *sqe = io_get_sqe(selector);
644
- io_uring_prep_read(sqe, arguments->descriptor, arguments->buffer, arguments->length, io_seekable(arguments->descriptor));
654
+ io_uring_prep_read(sqe, arguments->descriptor, arguments->buffer, arguments->length, arguments->offset);
645
655
  io_uring_sqe_set_data(sqe, arguments->waiting->completion);
646
656
  io_uring_submit_now(selector);
647
657
 
@@ -671,18 +681,21 @@ io_read_ensure(VALUE _arguments)
671
681
  }
672
682
 
673
683
  static int
674
- io_read(struct IO_Event_Selector_URing *selector, VALUE fiber, int descriptor, char *buffer, size_t length)
684
+ io_read(struct IO_Event_Selector_URing *selector, VALUE fiber, int descriptor, char *buffer, size_t length, off_t offset)
675
685
  {
676
686
  struct IO_Event_Selector_URing_Waiting waiting = {
677
687
  .fiber = fiber,
678
688
  };
679
689
 
690
+ RB_OBJ_WRITTEN(selector->backend.self, Qundef, fiber);
691
+
680
692
  IO_Event_Selector_URing_Completion_acquire(selector, &waiting);
681
693
 
682
694
  struct io_read_arguments io_read_arguments = {
683
695
  .selector = selector,
684
696
  .waiting = &waiting,
685
697
  .descriptor = descriptor,
698
+ .offset = offset,
686
699
  .buffer = buffer,
687
700
  .length = length
688
701
  };
@@ -705,10 +718,11 @@ VALUE IO_Event_Selector_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE b
705
718
  size_t length = NUM2SIZET(_length);
706
719
  size_t offset = NUM2SIZET(_offset);
707
720
  size_t total = 0;
721
+ off_t from = io_seekable(descriptor);
708
722
 
709
723
  size_t maximum_size = size - offset;
710
724
  while (maximum_size) {
711
- int result = io_read(selector, fiber, descriptor, (char*)base+offset, maximum_size);
725
+ int result = io_read(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
712
726
 
713
727
  if (result > 0) {
714
728
  total += result;
@@ -742,12 +756,52 @@ static VALUE IO_Event_Selector_URing_io_read_compatible(int argc, VALUE *argv, V
742
756
  return IO_Event_Selector_URing_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
743
757
  }
744
758
 
759
+ VALUE IO_Event_Selector_URing_io_pread(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _from, VALUE _length, VALUE _offset) {
760
+ struct IO_Event_Selector_URing *selector = NULL;
761
+ TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
762
+
763
+ int descriptor = IO_Event_Selector_io_descriptor(io);
764
+
765
+ void *base;
766
+ size_t size;
767
+ rb_io_buffer_get_bytes_for_writing(buffer, &base, &size);
768
+
769
+ size_t length = NUM2SIZET(_length);
770
+ size_t offset = NUM2SIZET(_offset);
771
+ size_t total = 0;
772
+ off_t from = NUM2OFFT(_from);
773
+
774
+ size_t maximum_size = size - offset;
775
+ while (maximum_size) {
776
+ int result = io_read(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
777
+
778
+ if (result > 0) {
779
+ total += result;
780
+ offset += result;
781
+ from += result;
782
+ if ((size_t)result >= length) break;
783
+ length -= result;
784
+ } else if (result == 0) {
785
+ break;
786
+ } else if (length > 0 && IO_Event_try_again(-result)) {
787
+ IO_Event_Selector_URing_io_wait(self, fiber, io, RB_INT2NUM(IO_EVENT_READABLE));
788
+ } else {
789
+ return rb_fiber_scheduler_io_result(-1, -result);
790
+ }
791
+
792
+ maximum_size = size - offset;
793
+ }
794
+
795
+ return rb_fiber_scheduler_io_result(total, 0);
796
+ }
797
+
745
798
  #pragma mark - IO#write
746
799
 
747
800
  struct io_write_arguments {
748
801
  struct IO_Event_Selector_URing *selector;
749
802
  struct IO_Event_Selector_URing_Waiting *waiting;
750
803
  int descriptor;
804
+ off_t offset;
751
805
  char *buffer;
752
806
  size_t length;
753
807
  };
@@ -761,7 +815,7 @@ io_write_submit(VALUE _argument)
761
815
  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);
762
816
 
763
817
  struct io_uring_sqe *sqe = io_get_sqe(selector);
764
- io_uring_prep_write(sqe, arguments->descriptor, arguments->buffer, arguments->length, io_seekable(arguments->descriptor));
818
+ io_uring_prep_write(sqe, arguments->descriptor, arguments->buffer, arguments->length, arguments->offset);
765
819
  io_uring_sqe_set_data(sqe, arguments->waiting->completion);
766
820
  io_uring_submit_pending(selector);
767
821
 
@@ -791,18 +845,21 @@ io_write_ensure(VALUE _argument)
791
845
  }
792
846
 
793
847
  static int
794
- io_write(struct IO_Event_Selector_URing *selector, VALUE fiber, int descriptor, char *buffer, size_t length)
848
+ io_write(struct IO_Event_Selector_URing *selector, VALUE fiber, int descriptor, char *buffer, size_t length, off_t offset)
795
849
  {
796
850
  struct IO_Event_Selector_URing_Waiting waiting = {
797
851
  .fiber = fiber,
798
852
  };
799
853
 
854
+ RB_OBJ_WRITTEN(selector->backend.self, Qundef, fiber);
855
+
800
856
  IO_Event_Selector_URing_Completion_acquire(selector, &waiting);
801
857
 
802
858
  struct io_write_arguments arguments = {
803
859
  .selector = selector,
804
860
  .waiting = &waiting,
805
861
  .descriptor = descriptor,
862
+ .offset = offset,
806
863
  .buffer = buffer,
807
864
  .length = length,
808
865
  };
@@ -825,6 +882,7 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
825
882
  size_t length = NUM2SIZET(_length);
826
883
  size_t offset = NUM2SIZET(_offset);
827
884
  size_t total = 0;
885
+ off_t from = io_seekable(descriptor);
828
886
 
829
887
  if (length > size) {
830
888
  rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
@@ -832,7 +890,7 @@ VALUE IO_Event_Selector_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE
832
890
 
833
891
  size_t maximum_size = size - offset;
834
892
  while (maximum_size) {
835
- int result = io_write(selector, fiber, descriptor, (char*)base+offset, maximum_size);
893
+ int result = io_write(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
836
894
 
837
895
  if (result > 0) {
838
896
  total += result;
@@ -866,6 +924,49 @@ static VALUE IO_Event_Selector_URing_io_write_compatible(int argc, VALUE *argv,
866
924
  return IO_Event_Selector_URing_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
867
925
  }
868
926
 
927
+ VALUE IO_Event_Selector_URing_io_pwrite(VALUE self, VALUE fiber, VALUE io, VALUE buffer, VALUE _from, VALUE _length, VALUE _offset) {
928
+ struct IO_Event_Selector_URing *selector = NULL;
929
+ TypedData_Get_Struct(self, struct IO_Event_Selector_URing, &IO_Event_Selector_URing_Type, selector);
930
+
931
+ int descriptor = IO_Event_Selector_io_descriptor(io);
932
+
933
+ const void *base;
934
+ size_t size;
935
+ rb_io_buffer_get_bytes_for_reading(buffer, &base, &size);
936
+
937
+ size_t length = NUM2SIZET(_length);
938
+ size_t offset = NUM2SIZET(_offset);
939
+ size_t total = 0;
940
+ off_t from = NUM2OFFT(_from);
941
+
942
+ if (length > size) {
943
+ rb_raise(rb_eRuntimeError, "Length exceeds size of buffer!");
944
+ }
945
+
946
+ size_t maximum_size = size - offset;
947
+ while (maximum_size) {
948
+ int result = io_write(selector, fiber, descriptor, (char*)base+offset, maximum_size, from);
949
+
950
+ if (result > 0) {
951
+ total += result;
952
+ offset += result;
953
+ from += result;
954
+ if ((size_t)result >= length) break;
955
+ length -= result;
956
+ } else if (result == 0) {
957
+ break;
958
+ } else if (length > 0 && IO_Event_try_again(-result)) {
959
+ IO_Event_Selector_URing_io_wait(self, fiber, io, RB_INT2NUM(IO_EVENT_WRITABLE));
960
+ } else {
961
+ return rb_fiber_scheduler_io_result(-1, -result);
962
+ }
963
+
964
+ maximum_size = size - offset;
965
+ }
966
+
967
+ return rb_fiber_scheduler_io_result(total, 0);
968
+ }
969
+
869
970
  #endif
870
971
 
871
972
  #pragma mark - IO#close
@@ -1117,6 +1218,8 @@ void Init_IO_Event_Selector_URing(VALUE IO_Event_Selector) {
1117
1218
  #ifdef HAVE_RUBY_IO_BUFFER_H
1118
1219
  rb_define_method(IO_Event_Selector_URing, "io_read", IO_Event_Selector_URing_io_read_compatible, -1);
1119
1220
  rb_define_method(IO_Event_Selector_URing, "io_write", IO_Event_Selector_URing_io_write_compatible, -1);
1221
+ rb_define_method(IO_Event_Selector_URing, "io_pread", IO_Event_Selector_URing_io_pread, 6);
1222
+ rb_define_method(IO_Event_Selector_URing, "io_pwrite", IO_Event_Selector_URing_io_pwrite, 6);
1120
1223
  #endif
1121
1224
 
1122
1225
  rb_define_method(IO_Event_Selector_URing, "io_close", IO_Event_Selector_URing_io_close, 1);
@@ -5,6 +5,6 @@
5
5
 
6
6
  class IO
7
7
  module Event
8
- VERSION = "1.7.0"
8
+ VERSION = "1.7.2"
9
9
  end
10
10
  end
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.7.0
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -45,7 +45,7 @@ cert_chain:
45
45
  Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
46
46
  voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
47
47
  -----END CERTIFICATE-----
48
- date: 2024-10-04 00:00:00.000000000 Z
48
+ date: 2024-10-16 00:00:00.000000000 Z
49
49
  dependencies: []
50
50
  description:
51
51
  email:
@@ -104,7 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
106
  requirements: []
107
- rubygems_version: 3.4.19
107
+ rubygems_version: 3.5.11
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: An event loop.
metadata.gz.sig CHANGED
Binary file