io-event 1.20.1 → 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/ext/io/event/list.h +1 -1
- data/ext/io/event/selector/uring.c +50 -6
- data/lib/io/event/version.rb +1 -1
- data/readme.md +5 -4
- data/releases.md +5 -0
- data.tar.gz.sig +0 -0
- metadata +1 -1
- 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: 634a83d174720978fa28231fa599a3f9ac4b27bc727b4fd934a3999ccd3b0df0
|
|
4
|
+
data.tar.gz: 0f34bf53b9103e3dc55f545c479c8850ca0b22425caba6029d3c7dbb93b3b322
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bcce50b95a8f978df63deb0e41bda0e9ea4911ea2ba7a1074628fbce6d6b59d314008ec0ca2cc165a067f020f079bb6940df822732a31f92fab96187cc3bffdd
|
|
7
|
+
data.tar.gz: f77dd827a584493fe156cc0f61b07bfa1b3081a514cf591bb156228c6b23b7d54bb1f15c2bb73e9b3a65bd4be6eb13d508a933fdf1a78e2ff314e59b8a79e370
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/ext/io/event/list.h
CHANGED
|
@@ -90,7 +90,7 @@ inline static size_t IO_Event_List_memory_size(const struct IO_Event_List *list)
|
|
|
90
90
|
// Return true if the list is empty.
|
|
91
91
|
inline static int IO_Event_List_empty(const struct IO_Event_List *list)
|
|
92
92
|
{
|
|
93
|
-
return list->head == list
|
|
93
|
+
return list->head == list;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
// Enumerate all items in the list, assuming the list will not be modified during iteration.
|
|
@@ -81,6 +81,7 @@ struct IO_Event_Selector_URing_Completion
|
|
|
81
81
|
struct IO_Event_List list;
|
|
82
82
|
|
|
83
83
|
struct IO_Event_Selector_URing_Waiting *waiting;
|
|
84
|
+
bool operation_pending;
|
|
84
85
|
bool cancellation_pending;
|
|
85
86
|
};
|
|
86
87
|
|
|
@@ -207,10 +208,12 @@ struct IO_Event_Selector_URing_Completion * IO_Event_Selector_URing_Completion_a
|
|
|
207
208
|
if (DEBUG_COMPLETION) fprintf(stderr, "IO_Event_Selector_URing_Completion_acquire(%p, limit=%ld)\n", (void*)completion, selector->completions.limit);
|
|
208
209
|
|
|
209
210
|
assert(completion->waiting == NULL);
|
|
211
|
+
assert(!completion->operation_pending);
|
|
210
212
|
assert(!completion->cancellation_pending);
|
|
211
213
|
|
|
212
214
|
waiting->completion = completion;
|
|
213
215
|
completion->waiting = waiting;
|
|
216
|
+
completion->operation_pending = true;
|
|
214
217
|
|
|
215
218
|
return completion;
|
|
216
219
|
}
|
|
@@ -230,6 +233,7 @@ inline static
|
|
|
230
233
|
void IO_Event_Selector_URing_Completion_recycle(struct IO_Event_Selector_URing *selector, struct IO_Event_Selector_URing_Completion *completion)
|
|
231
234
|
{
|
|
232
235
|
assert(completion->waiting == NULL);
|
|
236
|
+
assert(!completion->operation_pending);
|
|
233
237
|
assert(!completion->cancellation_pending);
|
|
234
238
|
|
|
235
239
|
IO_Event_List_prepend(&selector->free_list, &completion->list);
|
|
@@ -240,6 +244,9 @@ void IO_Event_Selector_URing_Completion_complete(struct IO_Event_Selector_URing
|
|
|
240
244
|
{
|
|
241
245
|
if (DEBUG_COMPLETION) fprintf(stderr, "IO_Event_Selector_URing_Completion_complete(%p)\n", (void*)completion);
|
|
242
246
|
|
|
247
|
+
assert(completion->operation_pending);
|
|
248
|
+
completion->operation_pending = false;
|
|
249
|
+
|
|
243
250
|
IO_Event_Selector_URing_Completion_cancel(completion);
|
|
244
251
|
|
|
245
252
|
// A cancellation SQE still refers to this completion record. Keep it out of
|
|
@@ -257,7 +264,7 @@ void IO_Event_Selector_URing_Completion_cancellation_complete(struct IO_Event_Se
|
|
|
257
264
|
assert(completion->cancellation_pending);
|
|
258
265
|
completion->cancellation_pending = false;
|
|
259
266
|
|
|
260
|
-
if (completion->
|
|
267
|
+
if (!completion->operation_pending) {
|
|
261
268
|
IO_Event_Selector_URing_Completion_recycle(selector, completion);
|
|
262
269
|
}
|
|
263
270
|
}
|
|
@@ -283,6 +290,7 @@ void IO_Event_Selector_URing_Completion_initialize(void *element)
|
|
|
283
290
|
IO_Event_List_initialize(&completion->list);
|
|
284
291
|
completion->list.type = &IO_Event_Selector_URing_Completion_Type;
|
|
285
292
|
completion->waiting = NULL;
|
|
293
|
+
completion->operation_pending = false;
|
|
286
294
|
completion->cancellation_pending = false;
|
|
287
295
|
}
|
|
288
296
|
|
|
@@ -563,9 +571,20 @@ void IO_Event_Selector_URing_Completion_cancel_async(struct IO_Event_Selector_UR
|
|
|
563
571
|
io_uring_submit_pending(selector);
|
|
564
572
|
}
|
|
565
573
|
|
|
574
|
+
static
|
|
575
|
+
VALUE IO_Event_Selector_URing_Waiting_wait_yield(VALUE _selector)
|
|
576
|
+
{
|
|
577
|
+
struct IO_Event_Selector_URing *selector = (struct IO_Event_Selector_URing *)_selector;
|
|
578
|
+
|
|
579
|
+
return IO_Event_Selector_loop_yield(&selector->backend);
|
|
580
|
+
}
|
|
581
|
+
|
|
566
582
|
static
|
|
567
583
|
void IO_Event_Selector_URing_Waiting_cancel_and_wait(struct IO_Event_Selector_URing *selector, struct IO_Event_Selector_URing_Waiting *waiting)
|
|
568
584
|
{
|
|
585
|
+
int state = 0;
|
|
586
|
+
VALUE error = Qnil;
|
|
587
|
+
|
|
569
588
|
if (waiting->completion) {
|
|
570
589
|
IO_Event_Selector_URing_Completion_cancel_async(selector, waiting->completion);
|
|
571
590
|
|
|
@@ -573,11 +592,24 @@ void IO_Event_Selector_URing_Waiting_cancel_and_wait(struct IO_Event_Selector_UR
|
|
|
573
592
|
// Keep the C frame, buffer lock and completion record alive until the
|
|
574
593
|
// original operation CQE confirms that it can no longer access memory.
|
|
575
594
|
while (waiting->completion) {
|
|
576
|
-
|
|
595
|
+
int current_state = 0;
|
|
596
|
+
rb_protect(IO_Event_Selector_URing_Waiting_wait_yield, (VALUE)selector, ¤t_state);
|
|
597
|
+
|
|
598
|
+
if (current_state && !state) {
|
|
599
|
+
state = current_state;
|
|
600
|
+
error = rb_errinfo();
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
rb_set_errinfo(Qnil);
|
|
577
604
|
}
|
|
578
605
|
}
|
|
579
606
|
|
|
580
607
|
IO_Event_Selector_URing_Waiting_cancel(waiting);
|
|
608
|
+
|
|
609
|
+
if (state) {
|
|
610
|
+
rb_set_errinfo(error);
|
|
611
|
+
rb_jump_tag(state);
|
|
612
|
+
}
|
|
581
613
|
}
|
|
582
614
|
|
|
583
615
|
#pragma mark - Process.wait
|
|
@@ -648,10 +680,18 @@ static
|
|
|
648
680
|
VALUE process_wait_transfer(VALUE _arguments) {
|
|
649
681
|
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
|
650
682
|
|
|
683
|
+
#ifdef IO_EVENT_SELECTOR_URING_USE_WAITID
|
|
651
684
|
IO_Event_Selector_loop_yield(&arguments->selector->backend);
|
|
652
685
|
|
|
653
|
-
|
|
686
|
+
if (arguments->waiting->completion) {
|
|
687
|
+
// The kernel may still write to siginfo or reap the child. Keep the C frame alive until the original operation completes, then distinguish cancellation from process completion:
|
|
688
|
+
IO_Event_Selector_URing_Waiting_cancel_and_wait(arguments->selector, arguments->waiting);
|
|
689
|
+
}
|
|
690
|
+
|
|
654
691
|
int32_t result = arguments->waiting->result;
|
|
692
|
+
if (result == -ECANCELED) {
|
|
693
|
+
return Qfalse;
|
|
694
|
+
}
|
|
655
695
|
|
|
656
696
|
if (DEBUG) fprintf(stderr, "waitid result=%d pid=%d code=%d status=%d\n", result, arguments->siginfo.si_pid, arguments->siginfo.si_code, arguments->siginfo.si_status);
|
|
657
697
|
|
|
@@ -672,6 +712,8 @@ VALUE process_wait_transfer(VALUE _arguments) {
|
|
|
672
712
|
return IO_Event_Selector_process_status_reap(arguments->siginfo.si_pid, arguments->flags);
|
|
673
713
|
#endif
|
|
674
714
|
#else
|
|
715
|
+
IO_Event_Selector_loop_yield(&arguments->selector->backend);
|
|
716
|
+
|
|
675
717
|
if (arguments->waiting->result) {
|
|
676
718
|
return IO_Event_Selector_process_status_reap(arguments->pid, arguments->flags);
|
|
677
719
|
} else {
|
|
@@ -684,15 +726,17 @@ static
|
|
|
684
726
|
VALUE process_wait_ensure(VALUE _arguments) {
|
|
685
727
|
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;
|
|
686
728
|
|
|
729
|
+
#ifdef IO_EVENT_SELECTOR_URING_USE_WAITID
|
|
730
|
+
// `waitid` may write to stack-backed siginfo while cancellation is pending:
|
|
731
|
+
IO_Event_Selector_URing_Waiting_cancel_and_wait(arguments->selector, arguments->waiting);
|
|
732
|
+
#else
|
|
687
733
|
if (arguments->waiting->completion) {
|
|
688
734
|
IO_Event_Selector_URing_Completion_cancel_async(arguments->selector, arguments->waiting->completion);
|
|
689
735
|
}
|
|
690
736
|
|
|
691
|
-
#ifndef IO_EVENT_SELECTOR_URING_USE_WAITID
|
|
692
737
|
close(arguments->descriptor);
|
|
693
|
-
#endif
|
|
694
|
-
|
|
695
738
|
IO_Event_Selector_URing_Waiting_cancel(arguments->waiting);
|
|
739
|
+
#endif
|
|
696
740
|
|
|
697
741
|
return Qnil;
|
|
698
742
|
}
|
data/lib/io/event/version.rb
CHANGED
data/readme.md
CHANGED
|
@@ -18,6 +18,11 @@ 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.21.1
|
|
22
|
+
|
|
23
|
+
- Fix the `URing` completion free-list empty check so its sole entry can be reused instead of unnecessarily allocating a new completion.
|
|
24
|
+
- Keep cancelled `URing` completion records allocated until both the operation and cancellation completions have been processed.
|
|
25
|
+
|
|
21
26
|
### v1.20.0
|
|
22
27
|
|
|
23
28
|
- Add compatibility with Ruby 4.1's fiber scheduler interface version 4. Buffered IO operations now use `(offset, length)`, perform a single transfer of at most `length` bytes, return short transfers directly, and report `-EAGAIN` without waiting. Earlier Ruby versions retain the existing minimum-progress behavior.
|
|
@@ -55,10 +60,6 @@ Please see the [project releases](https://socketry.github.io/io-event/releases/i
|
|
|
55
60
|
|
|
56
61
|
- Report inherited selector objects as closed after fork, and avoid closing descriptors they no longer own.
|
|
57
62
|
|
|
58
|
-
### v1.16.4
|
|
59
|
-
|
|
60
|
-
- Correctly implement `Interrupt#signal` so that it is robust enough to be called by `Scheduler#unblock`.
|
|
61
|
-
|
|
62
63
|
## Contributing
|
|
63
64
|
|
|
64
65
|
We welcome contributions to this project.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v1.21.1
|
|
4
|
+
|
|
5
|
+
- Fix the `URing` completion free-list empty check so its sole entry can be reused instead of unnecessarily allocating a new completion.
|
|
6
|
+
- Keep cancelled `URing` completion records allocated until both the operation and cancellation completions have been processed.
|
|
7
|
+
|
|
3
8
|
## v1.20.0
|
|
4
9
|
|
|
5
10
|
- Add compatibility with Ruby 4.1's fiber scheduler interface version 4. Buffered IO operations now use `(offset, length)`, perform a single transfer of at most `length` bytes, return short transfers directly, and report `-EAGAIN` without waiting. Earlier Ruby versions retain the existing minimum-progress behavior.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
metadata.gz.sig
CHANGED
|
Binary file
|