uringmachine 0.25.0 → 0.27.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 +4 -4
- data/CHANGELOG.md +9 -0
- data/TODO.md +17 -19
- data/docs/wroclove.rb.md +52 -0
- data/ext/um/um.c +469 -364
- data/ext/um/um.h +46 -22
- data/ext/um/um_async_op.c +9 -8
- data/ext/um/um_async_op_class.c +3 -3
- data/ext/um/um_class.c +215 -75
- data/ext/um/um_op.c +18 -2
- data/ext/um/um_ssl.c +1 -1
- data/ext/um/um_sync.c +18 -11
- data/ext/um/um_utils.c +14 -4
- data/grant-2025/tasks.md +2 -2
- data/lib/uringmachine/version.rb +1 -1
- data/test/test_async_op.rb +3 -2
- data/test/test_fiber_scheduler.rb +4 -1
- data/test/test_um.rb +410 -27
- metadata +2 -1
data/ext/um/um.c
CHANGED
|
@@ -60,8 +60,8 @@ inline void um_teardown(struct um *machine) {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
inline struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op) {
|
|
63
|
-
DEBUG_PRINTF("
|
|
64
|
-
|
|
63
|
+
DEBUG_PRINTF("* um_get_sqe: op %p kind=%s ref_count=%d flags=%x unsubmitted=%d pending=%d total=%lu\n",
|
|
64
|
+
op, um_op_kind_name(op ? op->kind : OP_UNDEFINED), op ? op->ref_count : 0, op ? op->flags : 0,
|
|
65
65
|
machine->metrics.ops_unsubmitted, machine->metrics.ops_pending, machine->metrics.total_ops
|
|
66
66
|
);
|
|
67
67
|
|
|
@@ -112,12 +112,11 @@ void *um_submit_without_gvl(void *ptr) {
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
inline uint um_submit(struct um *machine) {
|
|
115
|
-
DEBUG_PRINTF("
|
|
116
|
-
|
|
117
|
-
machine->metrics.total_ops
|
|
115
|
+
DEBUG_PRINTF("> um_submit: unsubmitted=%d pending=%d total=%lu\n",
|
|
116
|
+
machine->metrics.ops_unsubmitted, machine->metrics.ops_pending, machine->metrics.total_ops
|
|
118
117
|
);
|
|
119
118
|
if (!machine->metrics.ops_unsubmitted) {
|
|
120
|
-
DEBUG_PRINTF("
|
|
119
|
+
DEBUG_PRINTF("< %p um_submit: no unsubmitted SQEs, early return\n", &machine->ring);
|
|
121
120
|
return 0;
|
|
122
121
|
}
|
|
123
122
|
|
|
@@ -127,7 +126,7 @@ inline uint um_submit(struct um *machine) {
|
|
|
127
126
|
else
|
|
128
127
|
ctx.result = io_uring_submit(&machine->ring);
|
|
129
128
|
|
|
130
|
-
DEBUG_PRINTF("
|
|
129
|
+
DEBUG_PRINTF("< um_submit: result=%d\n", ctx.result);
|
|
131
130
|
|
|
132
131
|
if (ctx.result < 0)
|
|
133
132
|
rb_syserr_fail(-ctx.result, strerror(-ctx.result));
|
|
@@ -136,53 +135,76 @@ inline uint um_submit(struct um *machine) {
|
|
|
136
135
|
return ctx.result;
|
|
137
136
|
}
|
|
138
137
|
|
|
138
|
+
static inline void um_schedule_op(struct um *machine, struct um_op *op) {
|
|
139
|
+
op->flags |= OP_F_SCHEDULED;
|
|
140
|
+
um_runqueue_push(machine, op);
|
|
141
|
+
op->ref_count++;
|
|
142
|
+
}
|
|
143
|
+
|
|
139
144
|
static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe) {
|
|
140
145
|
struct um_op *op = (struct um_op *)cqe->user_data;
|
|
141
146
|
if (DEBUG) {
|
|
142
147
|
if (op) {
|
|
143
|
-
DEBUG_PRINTF("
|
|
144
|
-
|
|
148
|
+
DEBUG_PRINTF("* um_process_cqe: op=%p kind=%s ref_count=%d flags=%x cqe_res=%d cqe_flags=%x pending=%d\n",
|
|
149
|
+
op, um_op_kind_name(op->kind), op->ref_count, op->flags,
|
|
150
|
+
cqe->res, cqe->flags, machine->metrics.ops_pending
|
|
145
151
|
);
|
|
146
152
|
}
|
|
147
153
|
else {
|
|
148
|
-
DEBUG_PRINTF("
|
|
149
|
-
|
|
154
|
+
DEBUG_PRINTF("* um_process_cqe: op=NULL cqe_res=%d cqe_flags=%x pending=%d\n",
|
|
155
|
+
cqe->res, cqe->flags, machine->metrics.ops_pending
|
|
150
156
|
);
|
|
151
157
|
}
|
|
152
158
|
}
|
|
153
159
|
if (unlikely(!op)) return;
|
|
154
160
|
|
|
155
|
-
if
|
|
156
|
-
|
|
161
|
+
// A multishot operation is still in progress if CQE has the F_MORE flag set
|
|
162
|
+
int done = OP_MULTISHOT_P(op) ? !(cqe->flags & IORING_CQE_F_MORE) : true;
|
|
157
163
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
// F_TRANSIENT means the operation was put on the transient list. Transient
|
|
165
|
+
// ops are usually async ops where the app doesn't care when they are done or
|
|
166
|
+
// how. We hold on to those ops on the transient list, where we can mark the
|
|
167
|
+
// corresponding buffer during a GC.
|
|
168
|
+
if (OP_TRANSIENT_P(op)) {
|
|
169
|
+
machine->metrics.ops_pending--;
|
|
170
|
+
um_op_transient_remove(machine, op);
|
|
171
|
+
if (op->ref_count > 1) {
|
|
172
|
+
op->result.res = cqe->res;
|
|
173
|
+
op->result.flags = cqe->flags;
|
|
174
|
+
op->flags |= OP_F_CQE_SEEN | OP_F_CQE_DONE;
|
|
175
|
+
}
|
|
176
|
+
um_op_release(machine, op);
|
|
163
177
|
return;
|
|
164
178
|
}
|
|
165
179
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
180
|
+
if (done) {
|
|
181
|
+
machine->metrics.ops_pending--;
|
|
182
|
+
um_op_release(machine, op);
|
|
183
|
+
}
|
|
169
184
|
|
|
170
|
-
if (op
|
|
171
|
-
|
|
185
|
+
if (unlikely(OP_CANCELED_P(op))) {
|
|
186
|
+
// multishot ops may generate multiple CQEs, we release only on the last
|
|
187
|
+
// one for the op.
|
|
188
|
+
if (done) {
|
|
189
|
+
op->flags |= OP_F_CQE_SEEN | OP_F_CQE_DONE;
|
|
190
|
+
um_op_release(machine, op);
|
|
191
|
+
}
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
172
194
|
|
|
173
|
-
if (op
|
|
195
|
+
if (OP_MULTISHOT_P(op)) {
|
|
174
196
|
um_op_multishot_results_push(machine, op, cqe->res, cqe->flags);
|
|
175
|
-
|
|
176
|
-
|
|
197
|
+
|
|
198
|
+
op->flags |= done ? (OP_F_CQE_SEEN | OP_F_CQE_DONE) : OP_F_CQE_SEEN;
|
|
199
|
+
if (!OP_SCHEDULED_P(op)) um_schedule_op(machine, op);
|
|
177
200
|
}
|
|
178
201
|
else {
|
|
202
|
+
// single shot
|
|
179
203
|
op->result.res = cqe->res;
|
|
180
204
|
op->result.flags = cqe->flags;
|
|
205
|
+
op->flags |= OP_F_CQE_SEEN | OP_F_CQE_DONE;
|
|
206
|
+
if (!OP_ASYNC_P(op)) um_schedule_op(machine, op);
|
|
181
207
|
}
|
|
182
|
-
|
|
183
|
-
if (op->flags & OP_F_ASYNC) return;
|
|
184
|
-
|
|
185
|
-
um_runqueue_push(machine, op);
|
|
186
208
|
}
|
|
187
209
|
|
|
188
210
|
// copied from liburing/queue.c
|
|
@@ -191,8 +213,8 @@ static inline int cq_ring_needs_flush(struct io_uring *ring) {
|
|
|
191
213
|
}
|
|
192
214
|
|
|
193
215
|
static inline int um_process_ready_cqes(struct um *machine) {
|
|
194
|
-
DEBUG_PRINTF("
|
|
195
|
-
|
|
216
|
+
DEBUG_PRINTF("> um_process_ready_cqes: unsubmitted=%d pending=%d total=%lu\n",
|
|
217
|
+
machine->metrics.ops_unsubmitted, machine->metrics.ops_pending, machine->metrics.total_ops
|
|
196
218
|
);
|
|
197
219
|
|
|
198
220
|
unsigned total_count = 0;
|
|
@@ -211,9 +233,9 @@ iterate:
|
|
|
211
233
|
if (overflow_checked) goto done;
|
|
212
234
|
|
|
213
235
|
if (cq_ring_needs_flush(&machine->ring)) {
|
|
214
|
-
DEBUG_PRINTF("
|
|
236
|
+
DEBUG_PRINTF("> io_uring_enter\n");
|
|
215
237
|
int ret = io_uring_enter(machine->ring.ring_fd, 0, 0, IORING_ENTER_GETEVENTS, NULL);
|
|
216
|
-
DEBUG_PRINTF("
|
|
238
|
+
DEBUG_PRINTF("< io_uring_enter: result=%d\n", ret);
|
|
217
239
|
if (ret < 0)
|
|
218
240
|
rb_syserr_fail(-ret, strerror(-ret));
|
|
219
241
|
|
|
@@ -222,7 +244,7 @@ iterate:
|
|
|
222
244
|
}
|
|
223
245
|
|
|
224
246
|
done:
|
|
225
|
-
DEBUG_PRINTF("
|
|
247
|
+
DEBUG_PRINTF("< um_process_ready_cqes: total_processed=%u\n", total_count);
|
|
226
248
|
|
|
227
249
|
return total_count;
|
|
228
250
|
}
|
|
@@ -237,8 +259,8 @@ struct wait_for_cqe_ctx {
|
|
|
237
259
|
void *um_wait_for_cqe_without_gvl(void *ptr) {
|
|
238
260
|
struct wait_for_cqe_ctx *ctx = ptr;
|
|
239
261
|
if (ctx->machine->metrics.ops_unsubmitted) {
|
|
240
|
-
DEBUG_PRINTF("
|
|
241
|
-
|
|
262
|
+
DEBUG_PRINTF("> io_uring_submit_and_wait_timeout: unsubmitted=%d pending=%d total=%lu\n",
|
|
263
|
+
ctx->machine->metrics.ops_unsubmitted, ctx->machine->metrics.ops_pending,
|
|
242
264
|
ctx->machine->metrics.total_ops
|
|
243
265
|
);
|
|
244
266
|
|
|
@@ -249,16 +271,16 @@ void *um_wait_for_cqe_without_gvl(void *ptr) {
|
|
|
249
271
|
// https://github.com/axboe/liburing/issues/1280
|
|
250
272
|
int ret = io_uring_submit_and_wait_timeout(&ctx->machine->ring, &ctx->cqe, ctx->wait_nr, NULL, NULL);
|
|
251
273
|
ctx->machine->metrics.ops_unsubmitted = 0;
|
|
252
|
-
DEBUG_PRINTF("
|
|
274
|
+
DEBUG_PRINTF("< io_uring_submit_and_wait_timeout: result=%d\n", ret);
|
|
253
275
|
ctx->result = (ret > 0 && !ctx->cqe) ? -EINTR : ret;
|
|
254
276
|
}
|
|
255
277
|
else {
|
|
256
|
-
DEBUG_PRINTF("
|
|
257
|
-
|
|
278
|
+
DEBUG_PRINTF("> io_uring_wait_cqes: unsubmitted=%d pending=%d total=%lu\n",
|
|
279
|
+
ctx->machine->metrics.ops_unsubmitted, ctx->machine->metrics.ops_pending,
|
|
258
280
|
ctx->machine->metrics.total_ops
|
|
259
281
|
);
|
|
260
282
|
ctx->result = io_uring_wait_cqes(&ctx->machine->ring, &ctx->cqe, ctx->wait_nr, NULL, NULL);
|
|
261
|
-
DEBUG_PRINTF("
|
|
283
|
+
DEBUG_PRINTF("< io_uring_wait_cqes: result=%d\n", ctx->result);
|
|
262
284
|
}
|
|
263
285
|
return NULL;
|
|
264
286
|
}
|
|
@@ -290,6 +312,7 @@ inline void *um_wait_for_sidecar_signal(void *ptr) {
|
|
|
290
312
|
// either 1 - where we wait for at least one CQE to be ready, or 0, where we
|
|
291
313
|
// don't wait, and just process any CQEs that already ready.
|
|
292
314
|
static inline void um_wait_for_and_process_ready_cqes(struct um *machine, int wait_nr) {
|
|
315
|
+
DEBUG_PRINTF("* um_wait_for_and_process_ready_cqes wait_nr=%d\n", wait_nr);
|
|
293
316
|
struct wait_for_cqe_ctx ctx = { .machine = machine, .cqe = NULL, .wait_nr = wait_nr };
|
|
294
317
|
machine->metrics.total_waits++;
|
|
295
318
|
|
|
@@ -347,14 +370,16 @@ inline void um_profile_switch(struct um *machine, VALUE next_fiber) {
|
|
|
347
370
|
}
|
|
348
371
|
|
|
349
372
|
inline VALUE process_runqueue_op(struct um *machine, struct um_op *op) {
|
|
350
|
-
DEBUG_PRINTF("
|
|
373
|
+
DEBUG_PRINTF("* process_runqueue_op: op=%p kind=%s ref_count=%d flags=%x\n",
|
|
374
|
+
op, um_op_kind_name(op->kind), op->ref_count, op->flags
|
|
375
|
+
);
|
|
351
376
|
|
|
352
377
|
machine->metrics.total_switches++;
|
|
353
378
|
VALUE fiber = op->fiber;
|
|
354
379
|
VALUE value = op->value;
|
|
355
380
|
|
|
356
|
-
|
|
357
|
-
|
|
381
|
+
op->flags &= ~OP_F_SCHEDULED;
|
|
382
|
+
um_op_release(machine, op);
|
|
358
383
|
|
|
359
384
|
if (machine->profile_mode) um_profile_switch(machine, fiber);
|
|
360
385
|
VALUE ret = rb_fiber_transfer(fiber, 1, &value);
|
|
@@ -364,15 +389,19 @@ inline VALUE process_runqueue_op(struct um *machine, struct um_op *op) {
|
|
|
364
389
|
}
|
|
365
390
|
|
|
366
391
|
inline VALUE um_switch(struct um *machine) {
|
|
367
|
-
DEBUG_PRINTF("
|
|
368
|
-
|
|
392
|
+
DEBUG_PRINTF("* um_switch: unsubmitted=%d pending=%d total=%lu\n",
|
|
393
|
+
machine->metrics.ops_unsubmitted, machine->metrics.ops_pending,
|
|
369
394
|
machine->metrics.total_ops
|
|
370
395
|
);
|
|
371
396
|
|
|
372
397
|
while (true) {
|
|
373
398
|
struct um_op *op = um_runqueue_shift(machine);
|
|
374
399
|
if (op) {
|
|
375
|
-
if (unlikely(op
|
|
400
|
+
if (unlikely(OP_SKIP_P(op))) {
|
|
401
|
+
op->flags &= ~OP_F_SCHEDULED;
|
|
402
|
+
um_op_release(machine, op);
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
376
405
|
|
|
377
406
|
// in test mode we want to process I/O on each snooze
|
|
378
407
|
if (unlikely(machine->test_mode && (op->kind == OP_SCHEDULE))) {
|
|
@@ -393,29 +422,62 @@ inline VALUE um_yield(struct um *machine) {
|
|
|
393
422
|
return ret;
|
|
394
423
|
}
|
|
395
424
|
|
|
396
|
-
void um_cancel_op(struct um *machine, struct um_op *op) {
|
|
425
|
+
inline void um_cancel_op(struct um *machine, struct um_op *op) {
|
|
397
426
|
struct io_uring_sqe *sqe = um_get_sqe(machine, NULL);
|
|
398
|
-
|
|
427
|
+
io_uring_prep_cancel(sqe, op, IORING_ASYNC_CANCEL_USERDATA);
|
|
428
|
+
sqe->flags = IOSQE_CQE_SKIP_SUCCESS;
|
|
399
429
|
}
|
|
400
430
|
|
|
401
|
-
inline void
|
|
431
|
+
inline void um_cancel_op_and_discard_cqe(struct um *machine, struct um_op *op) {
|
|
432
|
+
DEBUG_PRINTF("* um_cancel_op_and_discard_cqe op=%p kind=%s ref_count=%d flags=%x\n",
|
|
433
|
+
op, um_op_kind_name(op->kind), op->ref_count, op->flags
|
|
434
|
+
);
|
|
435
|
+
um_cancel_op(machine, op);
|
|
436
|
+
op->flags |= OP_F_CANCELED;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
inline void um_cancel_op_and_await_cqe(struct um *machine, struct um_op *op) {
|
|
440
|
+
DEBUG_PRINTF("* um_cancel_op_and_await_cqe op=%p kind=%s ref_count=%d flags=%x\n",
|
|
441
|
+
op, um_op_kind_name(op->kind), op->ref_count, op->flags
|
|
442
|
+
);
|
|
402
443
|
um_cancel_op(machine, op);
|
|
403
444
|
|
|
404
445
|
VALUE fiber = rb_fiber_current();
|
|
405
446
|
rb_set_add(machine->pending_fibers, fiber);
|
|
406
|
-
|
|
447
|
+
int multishot_wait_count = 0;
|
|
448
|
+
while (!OP_CQE_DONE_P(op)) {
|
|
449
|
+
if (OP_MULTISHOT_P(op)) {
|
|
450
|
+
// I noticed that with multishot timeout ops, there seems to be once in a
|
|
451
|
+
// while a race condition where the cancel would not register, causing
|
|
452
|
+
// this function to block forever, waiting for the operation to be done.
|
|
453
|
+
// The following mechanism reissues a cancel every 4 iterations, which
|
|
454
|
+
// seems to fix the problem. Not clear if this is a bug in io_uring.
|
|
455
|
+
multishot_wait_count++;
|
|
456
|
+
if (!(multishot_wait_count % 4)) um_cancel_op(machine, op);
|
|
457
|
+
um_op_multishot_results_clear(machine, op);
|
|
458
|
+
op->flags &= ~OP_F_CQE_SEEN;
|
|
459
|
+
}
|
|
407
460
|
um_switch(machine);
|
|
408
461
|
}
|
|
409
462
|
rb_set_delete(machine->pending_fibers, fiber);
|
|
410
463
|
}
|
|
411
464
|
|
|
412
|
-
|
|
413
|
-
if (!
|
|
414
|
-
|
|
465
|
+
int um_verify_op_completion(struct um *machine, struct um_op *op, int await_cancelled) {
|
|
466
|
+
if (unlikely(!OP_CQE_DONE_P(op))) {
|
|
467
|
+
if (await_cancelled)
|
|
468
|
+
um_cancel_op_and_await_cqe(machine, op);
|
|
469
|
+
else
|
|
470
|
+
um_cancel_op_and_discard_cqe(machine, op);
|
|
415
471
|
return 0;
|
|
416
472
|
}
|
|
417
473
|
|
|
418
|
-
|
|
474
|
+
int res = op->result.res;
|
|
475
|
+
|
|
476
|
+
// on error we release the op and immediately raise an exception
|
|
477
|
+
if (unlikely(res < 0 && res != -ETIME)) {
|
|
478
|
+
um_op_release(machine, op);
|
|
479
|
+
um_raise_on_error_result(res);
|
|
480
|
+
}
|
|
419
481
|
return 1;
|
|
420
482
|
}
|
|
421
483
|
|
|
@@ -426,25 +488,31 @@ VALUE um_wakeup(struct um *machine) {
|
|
|
426
488
|
return Qnil;
|
|
427
489
|
}
|
|
428
490
|
|
|
429
|
-
inline void um_prep_op(struct um *machine, struct um_op *op, enum um_op_kind kind, unsigned flags) {
|
|
491
|
+
inline void um_prep_op(struct um *machine, struct um_op *op, enum um_op_kind kind, uint ref_count, unsigned flags) {
|
|
430
492
|
memset(op, 0, sizeof(struct um_op));
|
|
431
493
|
op->kind = kind;
|
|
494
|
+
op->ref_count = ref_count;
|
|
432
495
|
op->flags = flags;
|
|
433
496
|
|
|
434
|
-
VALUE fiber = (
|
|
497
|
+
VALUE fiber = OP_ASYNC_P(op) ? Qnil : rb_fiber_current();
|
|
498
|
+
if (OP_TRANSIENT_P(op)) um_op_transient_add(machine, op);
|
|
499
|
+
|
|
435
500
|
RB_OBJ_WRITE(machine->self, &op->fiber, fiber);
|
|
436
501
|
RB_OBJ_WRITE(machine->self, &op->value, Qnil);
|
|
437
502
|
RB_OBJ_WRITE(machine->self, &op->async_op, Qnil);
|
|
438
503
|
}
|
|
439
504
|
|
|
440
505
|
inline void um_schedule(struct um *machine, VALUE fiber, VALUE value) {
|
|
441
|
-
struct um_op *op =
|
|
506
|
+
struct um_op *op = um_op_acquire(machine);
|
|
442
507
|
memset(op, 0, sizeof(struct um_op));
|
|
443
508
|
op->kind = OP_SCHEDULE;
|
|
444
|
-
op->
|
|
509
|
+
op->ref_count = 1;
|
|
510
|
+
op->flags = OP_F_SCHEDULED;
|
|
511
|
+
|
|
445
512
|
RB_OBJ_WRITE(machine->self, &op->fiber, fiber);
|
|
446
513
|
RB_OBJ_WRITE(machine->self, &op->value, value);
|
|
447
514
|
RB_OBJ_WRITE(machine->self, &op->async_op, Qnil);
|
|
515
|
+
|
|
448
516
|
um_runqueue_push(machine, op);
|
|
449
517
|
}
|
|
450
518
|
|
|
@@ -457,18 +525,14 @@ struct op_ctx {
|
|
|
457
525
|
struct um_queue *queue;
|
|
458
526
|
void *read_buf;
|
|
459
527
|
int read_maxlen;
|
|
460
|
-
struct __kernel_timespec ts;
|
|
461
528
|
int flags;
|
|
462
529
|
};
|
|
463
530
|
|
|
464
531
|
VALUE um_timeout_complete(VALUE arg) {
|
|
465
532
|
struct op_ctx *ctx = (struct op_ctx *)arg;
|
|
466
533
|
|
|
467
|
-
if (!
|
|
468
|
-
|
|
469
|
-
ctx->op->flags |= OP_F_TRANSIENT | OP_F_IGNORE_CANCELED;
|
|
470
|
-
um_op_transient_add(ctx->machine, ctx->op);
|
|
471
|
-
}
|
|
534
|
+
if (!OP_CQE_DONE_P(ctx->op)) um_cancel_op_and_discard_cqe(ctx->machine, ctx->op);
|
|
535
|
+
um_op_release(ctx->machine, ctx->op);
|
|
472
536
|
|
|
473
537
|
return Qnil;
|
|
474
538
|
}
|
|
@@ -477,8 +541,8 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
|
477
541
|
static ID ID_new = 0;
|
|
478
542
|
if (!ID_new) ID_new = rb_intern("new");
|
|
479
543
|
|
|
480
|
-
struct um_op *op =
|
|
481
|
-
um_prep_op(machine, op, OP_TIMEOUT, 0);
|
|
544
|
+
struct um_op *op = um_op_acquire(machine);
|
|
545
|
+
um_prep_op(machine, op, OP_TIMEOUT, 2, 0);
|
|
482
546
|
op->ts = um_double_to_timespec(NUM2DBL(interval));
|
|
483
547
|
RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
|
|
484
548
|
RB_OBJ_WRITE(machine->self, &op->value, rb_funcall(class, ID_new, 0));
|
|
@@ -500,20 +564,20 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
|
500
564
|
VALUE um_sleep(struct um *machine, double duration) {
|
|
501
565
|
if (duration <= 0) duration = SLEEP_FOREVER_DURATION;
|
|
502
566
|
|
|
503
|
-
struct um_op op;
|
|
504
|
-
um_prep_op(machine,
|
|
505
|
-
op
|
|
506
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
507
|
-
io_uring_prep_timeout(sqe, &op
|
|
567
|
+
struct um_op *op = um_op_acquire(machine);
|
|
568
|
+
um_prep_op(machine, op, OP_SLEEP, 2, 0);
|
|
569
|
+
op->ts = um_double_to_timespec(duration);
|
|
570
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
571
|
+
io_uring_prep_timeout(sqe, &op->ts, 0, 0);
|
|
508
572
|
|
|
509
573
|
VALUE ret = um_yield(machine);
|
|
510
574
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
575
|
+
DEBUG_PRINTF("sleep resume op %p ref_count %d flags: %x\n",
|
|
576
|
+
op, op->ref_count, op->flags
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = DBL2NUM(duration);
|
|
580
|
+
um_op_release(machine, op);
|
|
517
581
|
|
|
518
582
|
RAISE_IF_EXCEPTION(ret);
|
|
519
583
|
RB_GC_GUARD(ret);
|
|
@@ -521,19 +585,20 @@ VALUE um_sleep(struct um *machine, double duration) {
|
|
|
521
585
|
}
|
|
522
586
|
|
|
523
587
|
VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t buffer_offset, __u64 file_offset) {
|
|
524
|
-
struct um_op op;
|
|
525
|
-
um_prep_op(machine, &op, OP_READ, 0);
|
|
526
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
527
588
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, buffer_offset);
|
|
589
|
+
|
|
590
|
+
struct um_op *op = um_op_acquire(machine);
|
|
591
|
+
um_prep_op(machine, op, OP_READ, 2, 0);
|
|
592
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
528
593
|
io_uring_prep_read(sqe, fd, ptr, maxlen, file_offset);
|
|
529
594
|
|
|
530
595
|
VALUE ret = um_yield(machine);
|
|
531
596
|
|
|
532
|
-
if (
|
|
533
|
-
um_update_read_buffer(buffer, buffer_offset, op
|
|
534
|
-
ret = INT2NUM(op
|
|
535
|
-
|
|
597
|
+
if (likely(um_verify_op_completion(machine, op, true))) {
|
|
598
|
+
um_update_read_buffer(buffer, buffer_offset, op->result.res);
|
|
599
|
+
ret = INT2NUM(op->result.res);
|
|
536
600
|
}
|
|
601
|
+
um_op_release(machine, op);
|
|
537
602
|
|
|
538
603
|
RAISE_IF_EXCEPTION(ret);
|
|
539
604
|
RB_GC_GUARD(ret);
|
|
@@ -541,39 +606,38 @@ VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t b
|
|
|
541
606
|
}
|
|
542
607
|
|
|
543
608
|
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen) {
|
|
544
|
-
struct um_op op;
|
|
545
|
-
um_prep_op(machine,
|
|
546
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
609
|
+
struct um_op *op = um_op_acquire(machine);
|
|
610
|
+
um_prep_op(machine, op, OP_READ, 2, 0);
|
|
611
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
547
612
|
io_uring_prep_read(sqe, fd, buffer, maxlen, -1);
|
|
548
613
|
|
|
614
|
+
int res = 0;
|
|
549
615
|
VALUE ret = um_yield(machine);
|
|
550
616
|
|
|
551
|
-
if (
|
|
552
|
-
|
|
553
|
-
}
|
|
617
|
+
if (likely(um_verify_op_completion(machine, op, true))) res = op->result.res;
|
|
618
|
+
um_op_release(machine, op);
|
|
554
619
|
|
|
555
620
|
RAISE_IF_EXCEPTION(ret);
|
|
556
621
|
RB_GC_GUARD(ret);
|
|
557
|
-
return
|
|
622
|
+
return res;
|
|
558
623
|
}
|
|
559
624
|
|
|
560
625
|
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset) {
|
|
561
626
|
const void *base;
|
|
562
627
|
size_t size;
|
|
563
|
-
um_get_buffer_bytes_for_writing(buffer, &base, &size);
|
|
628
|
+
um_get_buffer_bytes_for_writing(buffer, &base, &size, true);
|
|
564
629
|
if ((len == (size_t)-1) || (len > size)) len = size;
|
|
565
630
|
if (unlikely(!len)) return INT2NUM(0);
|
|
566
631
|
|
|
567
|
-
struct um_op op;
|
|
568
|
-
um_prep_op(machine,
|
|
569
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
570
|
-
|
|
632
|
+
struct um_op *op = um_op_acquire(machine);
|
|
633
|
+
um_prep_op(machine, op, OP_WRITE, 2, 0);
|
|
634
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
571
635
|
io_uring_prep_write(sqe, fd, base, len, file_offset);
|
|
572
636
|
|
|
573
637
|
VALUE ret = um_yield(machine);
|
|
574
638
|
|
|
575
|
-
if (
|
|
576
|
-
|
|
639
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
640
|
+
um_op_release(machine, op);
|
|
577
641
|
|
|
578
642
|
RAISE_IF_EXCEPTION(ret);
|
|
579
643
|
RB_GC_GUARD(ret);
|
|
@@ -581,19 +645,20 @@ VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_
|
|
|
581
645
|
}
|
|
582
646
|
|
|
583
647
|
size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t maxlen) {
|
|
584
|
-
struct um_op op;
|
|
585
|
-
um_prep_op(machine,
|
|
586
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
648
|
+
struct um_op *op = um_op_acquire(machine);
|
|
649
|
+
um_prep_op(machine, op, OP_WRITE, 2, 0);
|
|
650
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
587
651
|
io_uring_prep_write(sqe, fd, buffer, maxlen, 0);
|
|
588
652
|
|
|
653
|
+
int res = 0;
|
|
589
654
|
VALUE ret = um_yield(machine);
|
|
590
655
|
|
|
591
|
-
if (
|
|
592
|
-
|
|
656
|
+
if (likely(um_verify_op_completion(machine, op, true))) res = op->result.res;
|
|
657
|
+
um_op_release(machine, op);
|
|
593
658
|
|
|
594
659
|
RAISE_IF_EXCEPTION(ret);
|
|
595
660
|
RB_GC_GUARD(ret);
|
|
596
|
-
return
|
|
661
|
+
return res;
|
|
597
662
|
}
|
|
598
663
|
|
|
599
664
|
VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv) {
|
|
@@ -607,7 +672,6 @@ VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv) {
|
|
|
607
672
|
struct iovec *iovecs = um_alloc_iovecs_for_writing(argc, argv, &total_len);
|
|
608
673
|
struct iovec *iovecs_ptr = iovecs;
|
|
609
674
|
int iovecs_len = argc;
|
|
610
|
-
struct um_op op;
|
|
611
675
|
VALUE ret = Qnil;
|
|
612
676
|
int writev_res = 0;
|
|
613
677
|
|
|
@@ -615,31 +679,34 @@ VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv) {
|
|
|
615
679
|
free(iovecs);
|
|
616
680
|
return INT2NUM(0);
|
|
617
681
|
}
|
|
682
|
+
|
|
683
|
+
struct um_op *op = um_op_acquire(machine);
|
|
618
684
|
len = total_len;
|
|
619
|
-
while (
|
|
620
|
-
|
|
621
|
-
|
|
685
|
+
while (true) {
|
|
686
|
+
op->iovecs = iovecs;
|
|
687
|
+
um_prep_op(machine, op, OP_WRITEV, 2, OP_F_FREE_IOVECS);
|
|
688
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
622
689
|
io_uring_prep_writev(sqe, fd, iovecs_ptr, iovecs_len, file_offset);
|
|
623
690
|
|
|
624
691
|
ret = um_yield(machine);
|
|
625
692
|
|
|
626
|
-
|
|
627
|
-
if (unlikely(!completed)) goto cancelled;
|
|
693
|
+
if (unlikely(!OP_CQE_DONE_P(op))) goto cancelled;
|
|
628
694
|
|
|
629
|
-
writev_res = op
|
|
695
|
+
writev_res = op->result.res;
|
|
630
696
|
if (unlikely(writev_res < 0)) goto done;
|
|
631
697
|
|
|
632
698
|
len -= writev_res;
|
|
633
|
-
if (len)
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
699
|
+
if (!len) goto done;
|
|
700
|
+
|
|
701
|
+
um_advance_iovecs_for_writing(&iovecs_ptr, &iovecs_len, (size_t)writev_res);
|
|
702
|
+
if (file_offset != (__u64)-1) file_offset += writev_res;
|
|
637
703
|
}
|
|
638
704
|
|
|
639
705
|
cancelled:
|
|
640
|
-
|
|
706
|
+
um_cancel_op_and_await_cqe(machine, op);
|
|
641
707
|
done:
|
|
642
|
-
|
|
708
|
+
um_op_release(machine, op);
|
|
709
|
+
|
|
643
710
|
RAISE_IF_EXCEPTION(ret);
|
|
644
711
|
RB_GC_GUARD(ret);
|
|
645
712
|
um_raise_on_error_result(writev_res);
|
|
@@ -649,31 +716,29 @@ done:
|
|
|
649
716
|
VALUE um_write_async(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset) {
|
|
650
717
|
const void *base;
|
|
651
718
|
size_t size;
|
|
652
|
-
um_get_buffer_bytes_for_writing(buffer, &base, &size);
|
|
719
|
+
um_get_buffer_bytes_for_writing(buffer, &base, &size, true);
|
|
653
720
|
if ((len == (size_t)-1) || (len > size)) len = size;
|
|
654
721
|
if (unlikely(!len)) return INT2NUM(0);
|
|
655
722
|
|
|
656
|
-
struct um_op *op =
|
|
657
|
-
um_prep_op(machine, op, OP_WRITE_ASYNC,
|
|
723
|
+
struct um_op *op = um_op_acquire(machine);
|
|
724
|
+
um_prep_op(machine, op, OP_WRITE_ASYNC, 1, OP_F_ASYNC | OP_F_TRANSIENT);
|
|
658
725
|
RB_OBJ_WRITE(machine->self, &op->value, buffer);
|
|
659
|
-
|
|
660
726
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
661
727
|
io_uring_prep_write(sqe, fd, base, len, file_offset);
|
|
662
|
-
um_op_transient_add(machine, op);
|
|
663
728
|
|
|
664
729
|
return buffer;
|
|
665
730
|
}
|
|
666
731
|
|
|
667
732
|
VALUE um_close(struct um *machine, int fd) {
|
|
668
|
-
struct um_op op;
|
|
669
|
-
um_prep_op(machine,
|
|
670
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
733
|
+
struct um_op *op = um_op_acquire(machine);
|
|
734
|
+
um_prep_op(machine, op, OP_CLOSE, 2, 0);
|
|
735
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
671
736
|
io_uring_prep_close(sqe, fd);
|
|
672
737
|
|
|
673
738
|
VALUE ret = um_yield(machine);
|
|
674
739
|
|
|
675
|
-
if (
|
|
676
|
-
|
|
740
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(fd);
|
|
741
|
+
um_op_release(machine, op);
|
|
677
742
|
|
|
678
743
|
RAISE_IF_EXCEPTION(ret);
|
|
679
744
|
RB_GC_GUARD(ret);
|
|
@@ -681,9 +746,8 @@ VALUE um_close(struct um *machine, int fd) {
|
|
|
681
746
|
}
|
|
682
747
|
|
|
683
748
|
VALUE um_close_async(struct um *machine, int fd) {
|
|
684
|
-
struct um_op *op =
|
|
685
|
-
um_prep_op(machine, op, OP_CLOSE_ASYNC,
|
|
686
|
-
|
|
749
|
+
struct um_op *op = um_op_acquire(machine);
|
|
750
|
+
um_prep_op(machine, op, OP_CLOSE_ASYNC, 1, OP_F_ASYNC);
|
|
687
751
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
688
752
|
io_uring_prep_close(sqe, fd);
|
|
689
753
|
|
|
@@ -691,15 +755,15 @@ VALUE um_close_async(struct um *machine, int fd) {
|
|
|
691
755
|
}
|
|
692
756
|
|
|
693
757
|
VALUE um_accept(struct um *machine, int fd) {
|
|
694
|
-
struct um_op op;
|
|
695
|
-
um_prep_op(machine,
|
|
696
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
758
|
+
struct um_op *op = um_op_acquire(machine);
|
|
759
|
+
um_prep_op(machine, op, OP_ACCEPT, 2, 0);
|
|
760
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
697
761
|
io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
|
|
698
762
|
|
|
699
763
|
VALUE ret = um_yield(machine);
|
|
700
764
|
|
|
701
|
-
if (
|
|
702
|
-
|
|
765
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
|
|
766
|
+
um_op_release(machine, op);
|
|
703
767
|
|
|
704
768
|
RAISE_IF_EXCEPTION(ret);
|
|
705
769
|
RB_GC_GUARD(ret);
|
|
@@ -707,15 +771,15 @@ VALUE um_accept(struct um *machine, int fd) {
|
|
|
707
771
|
}
|
|
708
772
|
|
|
709
773
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags) {
|
|
710
|
-
struct um_op op;
|
|
711
|
-
um_prep_op(machine,
|
|
712
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
774
|
+
struct um_op *op = um_op_acquire(machine);
|
|
775
|
+
um_prep_op(machine, op, OP_SOCKET, 2, 0);
|
|
776
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
713
777
|
io_uring_prep_socket(sqe, domain, type, protocol, flags);
|
|
714
778
|
|
|
715
779
|
VALUE ret = um_yield(machine);
|
|
716
780
|
|
|
717
|
-
if (
|
|
718
|
-
|
|
781
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
|
|
782
|
+
um_op_release(machine, op);
|
|
719
783
|
|
|
720
784
|
RAISE_IF_EXCEPTION(ret);
|
|
721
785
|
RB_GC_GUARD(ret);
|
|
@@ -723,15 +787,15 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
|
|
|
723
787
|
}
|
|
724
788
|
|
|
725
789
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
|
726
|
-
struct um_op op;
|
|
727
|
-
um_prep_op(machine,
|
|
728
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
790
|
+
struct um_op *op = um_op_acquire(machine);
|
|
791
|
+
um_prep_op(machine, op, OP_CONNECT, 2, 0);
|
|
792
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
729
793
|
io_uring_prep_connect(sqe, fd, addr, addrlen);
|
|
730
794
|
|
|
731
795
|
VALUE ret = um_yield(machine);
|
|
732
796
|
|
|
733
|
-
if (
|
|
734
|
-
|
|
797
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
798
|
+
um_op_release(machine, op);
|
|
735
799
|
|
|
736
800
|
RAISE_IF_EXCEPTION(ret);
|
|
737
801
|
RB_GC_GUARD(ret);
|
|
@@ -739,27 +803,24 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
|
|
|
739
803
|
}
|
|
740
804
|
|
|
741
805
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags) {
|
|
742
|
-
struct um_op op;
|
|
743
|
-
um_prep_op(machine, &op, OP_SEND, 0);
|
|
744
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
745
|
-
|
|
746
806
|
const void *base;
|
|
747
807
|
size_t size;
|
|
748
|
-
um_get_buffer_bytes_for_writing(buffer, &base, &size);
|
|
808
|
+
um_get_buffer_bytes_for_writing(buffer, &base, &size, true);
|
|
749
809
|
if ((len == (size_t)-1) || (len > size)) len = size;
|
|
750
810
|
|
|
811
|
+
struct um_op *op = um_op_acquire(machine);
|
|
812
|
+
um_prep_op(machine, op, OP_SEND, 2, 0);
|
|
813
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
751
814
|
io_uring_prep_send(sqe, fd, base, len, flags);
|
|
752
815
|
|
|
753
816
|
VALUE ret = um_yield(machine);
|
|
754
817
|
|
|
755
|
-
if (
|
|
756
|
-
|
|
818
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
819
|
+
um_op_release(machine, op);
|
|
757
820
|
|
|
758
821
|
RAISE_IF_EXCEPTION(ret);
|
|
759
822
|
RB_GC_GUARD(ret);
|
|
760
823
|
return ret;
|
|
761
|
-
// int ret = write(fd, base, len);
|
|
762
|
-
// return UINT2NUM(ret);
|
|
763
824
|
}
|
|
764
825
|
|
|
765
826
|
// for some reason we don't get this define from liburing/io_uring.h
|
|
@@ -767,22 +828,17 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags) {
|
|
|
767
828
|
|
|
768
829
|
VALUE um_sendv(struct um *machine, int fd, int argc, VALUE *argv) {
|
|
769
830
|
struct iovec *iovecs = um_alloc_iovecs_for_writing(argc, argv, NULL);
|
|
770
|
-
struct um_op op;
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
831
|
+
struct um_op *op = um_op_acquire(machine);
|
|
832
|
+
op->iovecs = iovecs;
|
|
833
|
+
um_prep_op(machine, op, OP_SEND, 2, OP_F_FREE_IOVECS);
|
|
834
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
774
835
|
io_uring_prep_send(sqe, fd, iovecs, argc, MSG_NOSIGNAL | MSG_WAITALL);
|
|
775
836
|
sqe->ioprio |= IORING_SEND_VECTORIZED;
|
|
776
837
|
|
|
777
838
|
VALUE ret = um_yield(machine);
|
|
778
839
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
free(iovecs);
|
|
782
|
-
if (likely(completed)) {
|
|
783
|
-
um_raise_on_error_result(op.result.res);
|
|
784
|
-
ret = INT2NUM(op.result.res);
|
|
785
|
-
}
|
|
840
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
841
|
+
um_op_release(machine, op);
|
|
786
842
|
|
|
787
843
|
RAISE_IF_EXCEPTION(ret);
|
|
788
844
|
RB_GC_GUARD(ret);
|
|
@@ -791,19 +847,17 @@ VALUE um_sendv(struct um *machine, int fd, int argc, VALUE *argv) {
|
|
|
791
847
|
|
|
792
848
|
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings) {
|
|
793
849
|
um_add_strings_to_buffer_ring(machine, bgid, strings);
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
798
|
-
|
|
850
|
+
struct um_op *op = um_op_acquire(machine);
|
|
851
|
+
um_prep_op(machine, op, OP_SEND_BUNDLE, 2, 0);
|
|
852
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
799
853
|
io_uring_prep_send_bundle(sqe, fd, 0, MSG_NOSIGNAL | MSG_WAITALL);
|
|
800
854
|
sqe->flags |= IOSQE_BUFFER_SELECT;
|
|
801
855
|
sqe->buf_group = bgid;
|
|
802
856
|
|
|
803
857
|
VALUE ret = um_yield(machine);
|
|
804
858
|
|
|
805
|
-
if (
|
|
806
|
-
|
|
859
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
860
|
+
um_op_release(machine, op);
|
|
807
861
|
|
|
808
862
|
RAISE_IF_EXCEPTION(ret);
|
|
809
863
|
RB_GC_GUARD(ret);
|
|
@@ -811,19 +865,19 @@ VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings) {
|
|
|
811
865
|
}
|
|
812
866
|
|
|
813
867
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags) {
|
|
814
|
-
struct um_op op;
|
|
815
|
-
um_prep_op(machine, &op, OP_RECV, 0);
|
|
816
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
817
868
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
|
|
818
|
-
|
|
869
|
+
struct um_op *op = um_op_acquire(machine);
|
|
870
|
+
um_prep_op(machine, op, OP_RECV, 2, 0);
|
|
871
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
819
872
|
io_uring_prep_recv(sqe, fd, ptr, maxlen, flags);
|
|
820
873
|
|
|
821
874
|
VALUE ret = um_yield(machine);
|
|
822
875
|
|
|
823
|
-
if (
|
|
824
|
-
um_update_read_buffer(buffer, 0, op
|
|
825
|
-
ret = INT2NUM(op
|
|
876
|
+
if (likely(um_verify_op_completion(machine, op, true))) {
|
|
877
|
+
um_update_read_buffer(buffer, 0, op->result.res);
|
|
878
|
+
ret = INT2NUM(op->result.res);
|
|
826
879
|
}
|
|
880
|
+
um_op_release(machine, op);
|
|
827
881
|
|
|
828
882
|
RAISE_IF_EXCEPTION(ret);
|
|
829
883
|
RB_GC_GUARD(ret);
|
|
@@ -831,15 +885,15 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags
|
|
|
831
885
|
}
|
|
832
886
|
|
|
833
887
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen) {
|
|
834
|
-
struct um_op op;
|
|
835
|
-
um_prep_op(machine,
|
|
836
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
888
|
+
struct um_op *op = um_op_acquire(machine);
|
|
889
|
+
um_prep_op(machine, op, OP_BIND, 2, 0);
|
|
890
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
837
891
|
io_uring_prep_bind(sqe, fd, addr, addrlen);
|
|
838
892
|
|
|
839
893
|
VALUE ret = um_yield(machine);
|
|
840
894
|
|
|
841
|
-
if (
|
|
842
|
-
|
|
895
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
896
|
+
um_op_release(machine, op);
|
|
843
897
|
|
|
844
898
|
RAISE_IF_EXCEPTION(ret);
|
|
845
899
|
RB_GC_GUARD(ret);
|
|
@@ -847,15 +901,15 @@ VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrl
|
|
|
847
901
|
}
|
|
848
902
|
|
|
849
903
|
VALUE um_listen(struct um *machine, int fd, int backlog) {
|
|
850
|
-
struct um_op op;
|
|
851
|
-
um_prep_op(machine,
|
|
852
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
904
|
+
struct um_op *op = um_op_acquire(machine);
|
|
905
|
+
um_prep_op(machine, op, OP_BIND, 2, 0);
|
|
906
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
853
907
|
io_uring_prep_listen(sqe, fd, backlog);
|
|
854
908
|
|
|
855
909
|
VALUE ret = um_yield(machine);
|
|
856
910
|
|
|
857
|
-
if (
|
|
858
|
-
|
|
911
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
|
|
912
|
+
um_op_release(machine, op);
|
|
859
913
|
|
|
860
914
|
RAISE_IF_EXCEPTION(ret);
|
|
861
915
|
RB_GC_GUARD(ret);
|
|
@@ -864,17 +918,15 @@ VALUE um_listen(struct um *machine, int fd, int backlog) {
|
|
|
864
918
|
|
|
865
919
|
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
866
920
|
VALUE ret = Qnil;
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
struct
|
|
870
|
-
|
|
871
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
872
|
-
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_GETSOCKOPT, fd, level, opt, &value, sizeof(value));
|
|
921
|
+
struct um_op *op = um_op_acquire(machine);
|
|
922
|
+
um_prep_op(machine, op, OP_GETSOCKOPT, 2, 0);
|
|
923
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
924
|
+
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_GETSOCKOPT, fd, level, opt, &op->int_value, sizeof(op->int_value));
|
|
873
925
|
|
|
874
926
|
ret = um_yield(machine);
|
|
875
927
|
|
|
876
|
-
if (
|
|
877
|
-
|
|
928
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->int_value);
|
|
929
|
+
um_op_release(machine, op);
|
|
878
930
|
|
|
879
931
|
RAISE_IF_EXCEPTION(ret);
|
|
880
932
|
RB_GC_GUARD(ret);
|
|
@@ -883,16 +935,16 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
|
883
935
|
|
|
884
936
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
885
937
|
VALUE ret = Qnil;
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_SETSOCKOPT, fd, level, opt, &
|
|
938
|
+
struct um_op *op = um_op_acquire(machine);
|
|
939
|
+
um_prep_op(machine, op, OP_SETSOCKOPT, 2, 0);
|
|
940
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
941
|
+
op->int_value = value;
|
|
942
|
+
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_SETSOCKOPT, fd, level, opt, &op->int_value, sizeof(op->int_value));
|
|
891
943
|
|
|
892
944
|
ret = um_yield(machine);
|
|
893
945
|
|
|
894
|
-
if (
|
|
895
|
-
|
|
946
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
947
|
+
um_op_release(machine, op);
|
|
896
948
|
|
|
897
949
|
RAISE_IF_EXCEPTION(ret);
|
|
898
950
|
RB_GC_GUARD(ret);
|
|
@@ -901,16 +953,15 @@ VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
|
901
953
|
|
|
902
954
|
VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
903
955
|
VALUE ret = Qnil;
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
956
|
+
struct um_op *op = um_op_acquire(machine);
|
|
957
|
+
um_prep_op(machine, op, OP_SHUTDOWN, 2, 0);
|
|
958
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
908
959
|
io_uring_prep_shutdown(sqe, fd, how);
|
|
909
960
|
|
|
910
961
|
ret = um_yield(machine);
|
|
911
962
|
|
|
912
|
-
if (
|
|
913
|
-
|
|
963
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
964
|
+
um_op_release(machine, op);
|
|
914
965
|
|
|
915
966
|
RAISE_IF_EXCEPTION(ret);
|
|
916
967
|
RB_GC_GUARD(ret);
|
|
@@ -918,25 +969,111 @@ VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
|
918
969
|
}
|
|
919
970
|
|
|
920
971
|
VALUE um_shutdown_async(struct um *machine, int fd, int how) {
|
|
921
|
-
struct um_op *op =
|
|
922
|
-
um_prep_op(machine, op, OP_SHUTDOWN_ASYNC,
|
|
923
|
-
|
|
972
|
+
struct um_op *op = um_op_acquire(machine);
|
|
973
|
+
um_prep_op(machine, op, OP_SHUTDOWN_ASYNC, 1, OP_F_ASYNC);
|
|
924
974
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
925
975
|
io_uring_prep_shutdown(sqe, fd, how);
|
|
926
976
|
|
|
927
977
|
return INT2NUM(fd);
|
|
928
978
|
}
|
|
929
979
|
|
|
980
|
+
struct send_recv_fd_data {
|
|
981
|
+
struct msghdr msgh;
|
|
982
|
+
char iobuf[1];
|
|
983
|
+
struct iovec iov;
|
|
984
|
+
union { // Ancillary data buffer, wrapped in a union for alignment
|
|
985
|
+
char buf[CMSG_SPACE(sizeof(int))];
|
|
986
|
+
struct cmsghdr align;
|
|
987
|
+
} u;
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
inline void recv_fd_prepare(struct send_recv_fd_data *data) {
|
|
991
|
+
memset(&data->msgh, 0, sizeof(data->msgh));
|
|
992
|
+
data->iov.iov_base = data->iobuf;
|
|
993
|
+
data->iov.iov_len = sizeof(data->iobuf);
|
|
994
|
+
data->msgh.msg_iov = &data->iov;
|
|
995
|
+
data->msgh.msg_iovlen = 1;
|
|
996
|
+
data->msgh.msg_control = data->u.buf;
|
|
997
|
+
data->msgh.msg_controllen = sizeof(data->u.buf);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
inline void send_fd_prepare(struct send_recv_fd_data *data, int fd) {
|
|
1001
|
+
memset(&data->msgh, 0, sizeof(data->msgh));
|
|
1002
|
+
data->iov.iov_base = data->iobuf;
|
|
1003
|
+
data->iov.iov_len = sizeof(data->iobuf);
|
|
1004
|
+
data->msgh.msg_iov = &data->iov;
|
|
1005
|
+
data->msgh.msg_iovlen = 1;
|
|
1006
|
+
data->msgh.msg_control = data->u.buf;
|
|
1007
|
+
data->msgh.msg_controllen = sizeof(data->u.buf);
|
|
1008
|
+
|
|
1009
|
+
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&data->msgh);
|
|
1010
|
+
cmsgp->cmsg_level = SOL_SOCKET;
|
|
1011
|
+
cmsgp->cmsg_type = SCM_RIGHTS;
|
|
1012
|
+
cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
|
|
1013
|
+
memcpy(CMSG_DATA(cmsgp), &fd, sizeof(fd));
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
VALUE um_send_fd(struct um *machine, int sock_fd, int fd) {
|
|
1017
|
+
struct send_recv_fd_data data;
|
|
1018
|
+
send_fd_prepare(&data, fd);
|
|
1019
|
+
|
|
1020
|
+
VALUE ret = Qnil;
|
|
1021
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1022
|
+
um_prep_op(machine, op, OP_SENDMSG, 2, 0);
|
|
1023
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1024
|
+
io_uring_prep_sendmsg(sqe, sock_fd, &data.msgh, 0);
|
|
1025
|
+
|
|
1026
|
+
ret = um_yield(machine);
|
|
1027
|
+
|
|
1028
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(fd);
|
|
1029
|
+
um_op_release(machine, op);
|
|
1030
|
+
|
|
1031
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1032
|
+
RB_GC_GUARD(ret);
|
|
1033
|
+
return ret;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
inline int recv_fd_get_fd(struct send_recv_fd_data *data) {
|
|
1037
|
+
int fd;
|
|
1038
|
+
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&data->msgh);
|
|
1039
|
+
|
|
1040
|
+
if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
|
1041
|
+
cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS
|
|
1042
|
+
) um_raise_on_error_result(-EINVAL);
|
|
1043
|
+
|
|
1044
|
+
memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int));
|
|
1045
|
+
return fd;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
VALUE um_recv_fd(struct um *machine, int sock_fd) {
|
|
1049
|
+
struct send_recv_fd_data data;
|
|
1050
|
+
recv_fd_prepare(&data);
|
|
1051
|
+
|
|
1052
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1053
|
+
um_prep_op(machine, op, OP_RECVMSG, 2, 0);
|
|
1054
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1055
|
+
io_uring_prep_recvmsg(sqe, sock_fd, &data.msgh, 0);
|
|
1056
|
+
|
|
1057
|
+
VALUE ret = um_yield(machine);
|
|
1058
|
+
|
|
1059
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(recv_fd_get_fd(&data));
|
|
1060
|
+
um_op_release(machine, op);
|
|
1061
|
+
|
|
1062
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1063
|
+
RB_GC_GUARD(ret);
|
|
1064
|
+
return ret;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
930
1067
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
|
931
|
-
struct um_op op;
|
|
932
|
-
um_prep_op(machine,
|
|
933
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
1068
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1069
|
+
um_prep_op(machine, op, OP_OPEN, 2, 0);
|
|
1070
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
934
1071
|
io_uring_prep_open(sqe, StringValueCStr(pathname), flags, mode);
|
|
935
1072
|
|
|
936
1073
|
VALUE ret = um_yield(machine);
|
|
937
1074
|
|
|
938
|
-
if (
|
|
939
|
-
|
|
1075
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
1076
|
+
um_op_release(machine, op);
|
|
940
1077
|
|
|
941
1078
|
RAISE_IF_EXCEPTION(ret);
|
|
942
1079
|
RB_GC_GUARD(ret);
|
|
@@ -944,27 +1081,25 @@ VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
|
|
944
1081
|
}
|
|
945
1082
|
|
|
946
1083
|
VALUE um_poll(struct um *machine, int fd, unsigned mask) {
|
|
947
|
-
struct um_op op;
|
|
948
|
-
um_prep_op(machine,
|
|
949
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
1084
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1085
|
+
um_prep_op(machine, op, OP_POLL, 2, 0);
|
|
1086
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
950
1087
|
io_uring_prep_poll_add(sqe, fd, mask);
|
|
951
1088
|
|
|
952
1089
|
VALUE ret = um_yield(machine);
|
|
953
1090
|
|
|
954
|
-
if (
|
|
955
|
-
|
|
1091
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
|
|
1092
|
+
um_op_release(machine, op);
|
|
956
1093
|
|
|
957
1094
|
RAISE_IF_EXCEPTION(ret);
|
|
958
1095
|
RB_GC_GUARD(ret);
|
|
959
|
-
RB_GC_GUARD(op.fiber);
|
|
960
|
-
RB_GC_GUARD(op.value);
|
|
961
1096
|
return ret;
|
|
962
1097
|
}
|
|
963
1098
|
|
|
964
|
-
static inline void prepare_select_poll_ops(struct um *machine, uint *idx, struct um_op
|
|
1099
|
+
static inline void prepare_select_poll_ops(struct um *machine, uint *idx, struct um_op **ops, VALUE fds, uint len, uint flags, uint event) {
|
|
965
1100
|
for (uint i = 0; i < len; i++) {
|
|
966
|
-
struct um_op *op = ops
|
|
967
|
-
um_prep_op(machine, op, OP_POLL, flags
|
|
1101
|
+
struct um_op *op = ops[(*idx)++] = um_op_acquire(machine);
|
|
1102
|
+
um_prep_op(machine, op, OP_POLL, 2, flags);
|
|
968
1103
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
969
1104
|
VALUE fd = rb_ary_entry(fds, i);
|
|
970
1105
|
RB_OBJ_WRITE(machine->self, &op->value, fd);
|
|
@@ -973,8 +1108,9 @@ static inline void prepare_select_poll_ops(struct um *machine, uint *idx, struct
|
|
|
973
1108
|
}
|
|
974
1109
|
|
|
975
1110
|
VALUE um_select_single(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds, uint rfds_len, uint wfds_len, uint efds_len) {
|
|
976
|
-
struct um_op op;
|
|
1111
|
+
struct um_op *op;
|
|
977
1112
|
uint idx = 0;
|
|
1113
|
+
|
|
978
1114
|
if (rfds_len)
|
|
979
1115
|
prepare_select_poll_ops(machine, &idx, &op, rfds, rfds_len, OP_F_SELECT_POLLIN, POLLIN);
|
|
980
1116
|
else if (wfds_len)
|
|
@@ -985,12 +1121,14 @@ VALUE um_select_single(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds, u
|
|
|
985
1121
|
|
|
986
1122
|
VALUE ret = um_yield(machine);
|
|
987
1123
|
|
|
988
|
-
|
|
1124
|
+
um_verify_op_completion(machine, op, false);
|
|
1125
|
+
uint flags = op->flags;
|
|
1126
|
+
um_op_release(machine, op);
|
|
989
1127
|
RAISE_IF_EXCEPTION(ret);
|
|
990
1128
|
|
|
991
|
-
if (
|
|
1129
|
+
if (flags & OP_F_SELECT_POLLIN)
|
|
992
1130
|
return rb_ary_new3(3, rb_ary_new3(1, ret), rb_ary_new(), rb_ary_new());
|
|
993
|
-
else if (
|
|
1131
|
+
else if (flags & OP_F_SELECT_POLLOUT)
|
|
994
1132
|
return rb_ary_new3(3, rb_ary_new(), rb_ary_new3(1, ret), rb_ary_new());
|
|
995
1133
|
else
|
|
996
1134
|
return rb_ary_new3(3, rb_ary_new(), rb_ary_new(), rb_ary_new3(1, ret));
|
|
@@ -1009,7 +1147,7 @@ VALUE um_select(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds) {
|
|
|
1009
1147
|
if (unlikely(!total_len))
|
|
1010
1148
|
return rb_ary_new3(3, rb_ary_new(), rb_ary_new(), rb_ary_new());
|
|
1011
1149
|
|
|
1012
|
-
struct um_op
|
|
1150
|
+
struct um_op **ops = malloc(sizeof(struct um_op *) * total_len);
|
|
1013
1151
|
uint idx = 0;
|
|
1014
1152
|
prepare_select_poll_ops(machine, &idx, ops, rfds, rfds_len, OP_F_SELECT_POLLIN, POLLIN);
|
|
1015
1153
|
prepare_select_poll_ops(machine, &idx, ops, wfds, wfds_len, OP_F_SELECT_POLLOUT, POLLOUT);
|
|
@@ -1017,50 +1155,35 @@ VALUE um_select(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds) {
|
|
|
1017
1155
|
assert(idx == total_len);
|
|
1018
1156
|
|
|
1019
1157
|
VALUE ret = um_yield(machine);
|
|
1020
|
-
if (unlikely(um_value_is_exception_p(ret))) {
|
|
1021
|
-
free(ops);
|
|
1022
|
-
um_raise_exception(ret);
|
|
1023
|
-
}
|
|
1024
1158
|
|
|
1025
1159
|
VALUE rfds_out = rb_ary_new();
|
|
1026
1160
|
VALUE wfds_out = rb_ary_new();
|
|
1027
1161
|
VALUE efds_out = rb_ary_new();
|
|
1028
1162
|
|
|
1029
1163
|
int error_code = 0;
|
|
1030
|
-
uint pending = total_len;
|
|
1031
1164
|
for (uint i = 0; i < total_len; i++) {
|
|
1032
|
-
if (
|
|
1033
|
-
ops[i]
|
|
1034
|
-
pending--;
|
|
1165
|
+
if (OP_CQE_DONE_P(ops[i])) {
|
|
1166
|
+
if (OP_SCHEDULED_P(ops[i])) ops[i]->flags |= OP_F_SKIP;
|
|
1035
1167
|
|
|
1036
|
-
if (unlikely((ops[i]
|
|
1037
|
-
error_code = ops[i]
|
|
1168
|
+
if (unlikely((ops[i]->result.res < 0) && !error_code)) {
|
|
1169
|
+
error_code = ops[i]->result.res;
|
|
1038
1170
|
}
|
|
1039
1171
|
else {
|
|
1040
|
-
if (ops[i]
|
|
1041
|
-
if (ops[i]
|
|
1042
|
-
if (ops[i]
|
|
1172
|
+
if (ops[i]->flags & OP_F_SELECT_POLLIN) rb_ary_push(rfds_out, ops[i]->value);
|
|
1173
|
+
if (ops[i]->flags & OP_F_SELECT_POLLOUT) rb_ary_push(wfds_out, ops[i]->value);
|
|
1174
|
+
if (ops[i]->flags & OP_F_SELECT_POLLPRI) rb_ary_push(efds_out, ops[i]->value);
|
|
1043
1175
|
}
|
|
1044
1176
|
}
|
|
1045
1177
|
else {
|
|
1046
|
-
ops[i]
|
|
1047
|
-
um_cancel_op(machine, &ops[i]);
|
|
1178
|
+
um_cancel_op_and_discard_cqe(machine, ops[i]);
|
|
1048
1179
|
}
|
|
1049
1180
|
}
|
|
1050
1181
|
|
|
1051
|
-
|
|
1052
|
-
um_wait_for_and_process_ready_cqes(machine, 1);
|
|
1053
|
-
|
|
1054
|
-
for (uint i = 0; i < total_len; i++) {
|
|
1055
|
-
struct um_op *op = ops + i;
|
|
1056
|
-
if (op->flags & OP_F_CANCELED && um_op_completed_p(op)) {
|
|
1057
|
-
pending--;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
}
|
|
1182
|
+
for (uint i = 0; i < total_len; i++) um_op_release(machine, ops[i]);
|
|
1061
1183
|
free(ops);
|
|
1062
1184
|
|
|
1063
|
-
|
|
1185
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1186
|
+
if (unlikely(error_code))
|
|
1064
1187
|
um_raise_on_error_result(error_code);
|
|
1065
1188
|
|
|
1066
1189
|
return rb_ary_new3(3, rfds_out, wfds_out, efds_out);
|
|
@@ -1070,44 +1193,49 @@ VALUE um_select(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds) {
|
|
|
1070
1193
|
RB_GC_GUARD(efds_out);
|
|
1071
1194
|
}
|
|
1072
1195
|
|
|
1073
|
-
VALUE
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1196
|
+
static inline VALUE siginfo_to_array(siginfo_t *info) {
|
|
1197
|
+
return rb_ary_new_from_args(
|
|
1198
|
+
3,
|
|
1199
|
+
INT2NUM(info->si_pid),
|
|
1200
|
+
INT2NUM(info->si_status),
|
|
1201
|
+
INT2NUM(info->si_code)
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1077
1204
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1205
|
+
VALUE um_waitid(struct um *machine, int idtype, int id, int options) {
|
|
1206
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1207
|
+
um_prep_op(machine, op, OP_WAITID, 2, 0);
|
|
1208
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1209
|
+
io_uring_prep_waitid(sqe, idtype, id, &op->siginfo, options, 0);
|
|
1080
1210
|
|
|
1081
1211
|
VALUE ret = um_yield(machine);
|
|
1082
1212
|
|
|
1083
|
-
if (
|
|
1084
|
-
|
|
1213
|
+
if (likely(um_verify_op_completion(machine, op, false))) ret = INT2NUM(op->result.res);
|
|
1214
|
+
um_op_release(machine, op);
|
|
1085
1215
|
|
|
1086
1216
|
RAISE_IF_EXCEPTION(ret);
|
|
1087
1217
|
RB_GC_GUARD(ret);
|
|
1088
1218
|
|
|
1089
|
-
return
|
|
1090
|
-
3, INT2NUM(infop.si_pid), INT2NUM(infop.si_status), INT2NUM(infop.si_code)
|
|
1091
|
-
);
|
|
1219
|
+
return siginfo_to_array(&op->siginfo);
|
|
1092
1220
|
}
|
|
1093
1221
|
|
|
1094
1222
|
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
1095
1223
|
VALUE um_waitid_status(struct um *machine, int idtype, int id, int options) {
|
|
1096
|
-
struct um_op op;
|
|
1097
|
-
um_prep_op(machine,
|
|
1098
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
1099
|
-
|
|
1100
|
-
siginfo_t infop;
|
|
1101
|
-
io_uring_prep_waitid(sqe, idtype, id, &infop, options | WNOWAIT, 0);
|
|
1224
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1225
|
+
um_prep_op(machine, op, OP_WAITID, 2, 0);
|
|
1226
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1227
|
+
io_uring_prep_waitid(sqe, idtype, id, &op->siginfo, options | WNOWAIT, 0);
|
|
1102
1228
|
|
|
1103
1229
|
VALUE ret = um_yield(machine);
|
|
1104
|
-
|
|
1105
|
-
|
|
1230
|
+
|
|
1231
|
+
if (likely(um_verify_op_completion(machine, op))) ret = INT2NUM(op->result.res);
|
|
1232
|
+
siginfo_t siginfo = op->siginfo;
|
|
1233
|
+
um_op_release(machine, op);
|
|
1106
1234
|
|
|
1107
1235
|
RAISE_IF_EXCEPTION(ret);
|
|
1108
1236
|
RB_GC_GUARD(ret);
|
|
1109
1237
|
|
|
1110
|
-
return rb_process_status_new(
|
|
1238
|
+
return rb_process_status_new(siginfo.si_pid, (siginfo.si_status & 0xff) << 8, 0);
|
|
1111
1239
|
}
|
|
1112
1240
|
#endif
|
|
1113
1241
|
|
|
@@ -1137,10 +1265,9 @@ VALUE statx_to_hash(struct statx *stat) {
|
|
|
1137
1265
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask) {
|
|
1138
1266
|
static char empty_path[] = "";
|
|
1139
1267
|
|
|
1140
|
-
struct um_op op;
|
|
1141
|
-
um_prep_op(machine,
|
|
1142
|
-
struct io_uring_sqe *sqe = um_get_sqe(machine,
|
|
1143
|
-
|
|
1268
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1269
|
+
um_prep_op(machine, op, OP_STATX, 2, 0);
|
|
1270
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1144
1271
|
char *path_ptr = NIL_P(path) ? empty_path : StringValueCStr(path);
|
|
1145
1272
|
struct statx stat;
|
|
1146
1273
|
memset(&stat, 0, sizeof(stat));
|
|
@@ -1148,8 +1275,8 @@ VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned in
|
|
|
1148
1275
|
|
|
1149
1276
|
VALUE ret = um_yield(machine);
|
|
1150
1277
|
|
|
1151
|
-
if (
|
|
1152
|
-
|
|
1278
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(op->result.res);
|
|
1279
|
+
um_op_release(machine, op);
|
|
1153
1280
|
|
|
1154
1281
|
RAISE_IF_EXCEPTION(ret);
|
|
1155
1282
|
RB_GC_GUARD(ret);
|
|
@@ -1168,28 +1295,24 @@ VALUE accept_each_start(VALUE arg) {
|
|
|
1168
1295
|
|
|
1169
1296
|
while (true) {
|
|
1170
1297
|
VALUE ret = um_yield(ctx->machine);
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
}
|
|
1298
|
+
|
|
1299
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1300
|
+
if (unlikely(!OP_CQE_SEEN_P(ctx->op))) return ret;
|
|
1175
1301
|
RB_GC_GUARD(ret);
|
|
1176
1302
|
|
|
1177
|
-
int more = false;
|
|
1178
1303
|
struct um_op_result *result = &ctx->op->result;
|
|
1179
1304
|
while (result) {
|
|
1180
|
-
|
|
1181
|
-
if (result->res < 0) {
|
|
1182
|
-
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1305
|
+
if (unlikely(result->res < 0)) {
|
|
1183
1306
|
rb_syserr_fail(-result->res, strerror(-result->res));
|
|
1184
1307
|
}
|
|
1185
1308
|
rb_yield(INT2NUM(result->res));
|
|
1186
1309
|
result = result->next;
|
|
1187
1310
|
}
|
|
1311
|
+
|
|
1312
|
+
if (OP_CQE_DONE_P(ctx->op)) break;
|
|
1313
|
+
|
|
1188
1314
|
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1189
|
-
|
|
1190
|
-
ctx->op->flags &= ~OP_F_COMPLETED;
|
|
1191
|
-
else
|
|
1192
|
-
break;
|
|
1315
|
+
ctx->op->flags &= ~OP_F_CQE_SEEN;
|
|
1193
1316
|
}
|
|
1194
1317
|
|
|
1195
1318
|
return Qnil;
|
|
@@ -1202,28 +1325,24 @@ VALUE accept_into_queue_start(VALUE arg) {
|
|
|
1202
1325
|
|
|
1203
1326
|
while (true) {
|
|
1204
1327
|
VALUE ret = um_yield(ctx->machine);
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
}
|
|
1328
|
+
|
|
1329
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1330
|
+
if (unlikely(!OP_CQE_SEEN_P(ctx->op))) return ret;
|
|
1209
1331
|
RB_GC_GUARD(ret);
|
|
1210
1332
|
|
|
1211
|
-
int more = false;
|
|
1212
1333
|
struct um_op_result *result = &ctx->op->result;
|
|
1213
1334
|
while (result) {
|
|
1214
|
-
|
|
1215
|
-
if (result->res < 0) {
|
|
1216
|
-
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1335
|
+
if (unlikely(result->res < 0)) {
|
|
1217
1336
|
rb_syserr_fail(-result->res, strerror(-result->res));
|
|
1218
1337
|
}
|
|
1219
1338
|
um_queue_push(ctx->machine, ctx->queue, INT2NUM(result->res));
|
|
1220
1339
|
result = result->next;
|
|
1221
1340
|
}
|
|
1341
|
+
|
|
1342
|
+
if (OP_CQE_DONE_P(ctx->op)) break;
|
|
1343
|
+
|
|
1222
1344
|
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1223
|
-
|
|
1224
|
-
ctx->op->flags &= ~OP_F_COMPLETED;
|
|
1225
|
-
else
|
|
1226
|
-
break;
|
|
1345
|
+
ctx->op->flags &= ~OP_F_CQE_SEEN;
|
|
1227
1346
|
}
|
|
1228
1347
|
|
|
1229
1348
|
return Qnil;
|
|
@@ -1231,14 +1350,8 @@ VALUE accept_into_queue_start(VALUE arg) {
|
|
|
1231
1350
|
|
|
1232
1351
|
VALUE multishot_complete(VALUE arg) {
|
|
1233
1352
|
struct op_ctx *ctx = (struct op_ctx *)arg;
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
if (more)
|
|
1237
|
-
ctx->op->flags &= ~OP_F_COMPLETED;
|
|
1238
|
-
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1239
|
-
}
|
|
1240
|
-
if (!um_op_completed_p(ctx->op))
|
|
1241
|
-
um_cancel_and_wait(ctx->machine, ctx->op);
|
|
1353
|
+
um_verify_op_completion(ctx->machine, ctx->op, true);
|
|
1354
|
+
um_op_release(ctx->machine, ctx->op);
|
|
1242
1355
|
|
|
1243
1356
|
if (ctx->read_buf)
|
|
1244
1357
|
free(ctx->read_buf);
|
|
@@ -1247,19 +1360,20 @@ VALUE multishot_complete(VALUE arg) {
|
|
|
1247
1360
|
}
|
|
1248
1361
|
|
|
1249
1362
|
VALUE um_accept_each(struct um *machine, int fd) {
|
|
1250
|
-
struct um_op op;
|
|
1251
|
-
um_prep_op(machine,
|
|
1363
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1364
|
+
um_prep_op(machine, op, OP_ACCEPT_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1252
1365
|
|
|
1253
|
-
struct op_ctx ctx = { .machine = machine, .op =
|
|
1366
|
+
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .read_buf = NULL };
|
|
1254
1367
|
return rb_ensure(accept_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1255
1368
|
}
|
|
1256
1369
|
|
|
1257
1370
|
VALUE um_accept_into_queue(struct um *machine, int fd, VALUE queue) {
|
|
1258
|
-
struct
|
|
1259
|
-
|
|
1371
|
+
struct um_queue *queue_data = Queue_data(queue);
|
|
1372
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1373
|
+
um_prep_op(machine, op, OP_ACCEPT_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1260
1374
|
|
|
1261
1375
|
struct op_ctx ctx = {
|
|
1262
|
-
.machine = machine, .op =
|
|
1376
|
+
.machine = machine, .op = op, .fd = fd, .queue = queue_data, .read_buf = NULL
|
|
1263
1377
|
};
|
|
1264
1378
|
return rb_ensure(accept_into_queue_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1265
1379
|
}
|
|
@@ -1271,15 +1385,13 @@ int um_read_each_singleshot_loop(struct op_ctx *ctx) {
|
|
|
1271
1385
|
int total = 0;
|
|
1272
1386
|
|
|
1273
1387
|
while (1) {
|
|
1274
|
-
um_prep_op(ctx->machine, ctx->op, OP_READ, 0);
|
|
1388
|
+
um_prep_op(ctx->machine, ctx->op, OP_READ, 2, 0);
|
|
1275
1389
|
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
|
|
1276
1390
|
io_uring_prep_read(sqe, ctx->fd, ctx->read_buf, ctx->read_maxlen, -1);
|
|
1277
1391
|
|
|
1278
1392
|
VALUE ret = um_yield(ctx->machine);
|
|
1279
|
-
if (um_op_completed_p(ctx->op)) {
|
|
1280
|
-
um_raise_on_error_result(ctx->op->result.res);
|
|
1281
|
-
if (!ctx->op->result.res) return total;
|
|
1282
1393
|
|
|
1394
|
+
if (likely(um_verify_op_completion(ctx->machine, ctx->op, true))) {
|
|
1283
1395
|
VALUE buf = rb_str_new(ctx->read_buf, ctx->op->result.res);
|
|
1284
1396
|
total += ctx->op->result.res;
|
|
1285
1397
|
rb_yield(buf);
|
|
@@ -1287,10 +1399,11 @@ int um_read_each_singleshot_loop(struct op_ctx *ctx) {
|
|
|
1287
1399
|
}
|
|
1288
1400
|
else {
|
|
1289
1401
|
RAISE_IF_EXCEPTION(ret);
|
|
1290
|
-
return
|
|
1402
|
+
return 0;
|
|
1291
1403
|
}
|
|
1292
1404
|
RB_GC_GUARD(ret);
|
|
1293
1405
|
}
|
|
1406
|
+
return 0;
|
|
1294
1407
|
}
|
|
1295
1408
|
|
|
1296
1409
|
// // returns true if more results are expected
|
|
@@ -1337,91 +1450,83 @@ VALUE read_recv_each_start(VALUE arg) {
|
|
|
1337
1450
|
|
|
1338
1451
|
while (true) {
|
|
1339
1452
|
VALUE ret = um_yield(ctx->machine);
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
}
|
|
1453
|
+
|
|
1454
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1455
|
+
if (unlikely(!OP_CQE_SEEN_P(ctx->op))) return ret;
|
|
1344
1456
|
RB_GC_GUARD(ret);
|
|
1345
1457
|
|
|
1346
|
-
int more = false;
|
|
1347
1458
|
struct um_op_result *result = &ctx->op->result;
|
|
1348
1459
|
while (result) {
|
|
1349
1460
|
um_raise_on_error_result(result->res);
|
|
1350
1461
|
|
|
1351
|
-
more = (result->flags & IORING_CQE_F_MORE);
|
|
1352
1462
|
if (!read_recv_each_multishot_process_result(ctx, result, &total))
|
|
1353
1463
|
return Qnil;
|
|
1354
1464
|
|
|
1355
1465
|
// rb_yield(INT2NUM(result->res));
|
|
1356
1466
|
result = result->next;
|
|
1357
1467
|
}
|
|
1468
|
+
|
|
1469
|
+
if (OP_CQE_DONE_P(ctx->op)) break;
|
|
1470
|
+
|
|
1358
1471
|
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1359
|
-
|
|
1360
|
-
ctx->op->flags &= ~OP_F_COMPLETED;
|
|
1361
|
-
else
|
|
1362
|
-
break;
|
|
1472
|
+
ctx->op->flags &= ~OP_F_CQE_SEEN;
|
|
1363
1473
|
}
|
|
1364
1474
|
|
|
1365
1475
|
return Qnil;
|
|
1366
1476
|
}
|
|
1367
1477
|
|
|
1368
1478
|
VALUE um_read_each(struct um *machine, int fd, int bgid) {
|
|
1369
|
-
struct um_op op;
|
|
1370
|
-
um_prep_op(machine,
|
|
1479
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1480
|
+
um_prep_op(machine, op, OP_READ_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1371
1481
|
|
|
1372
|
-
struct op_ctx ctx = { .machine = machine, .op =
|
|
1482
|
+
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .bgid = bgid, .read_buf = NULL };
|
|
1373
1483
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1374
1484
|
}
|
|
1375
1485
|
|
|
1376
1486
|
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags) {
|
|
1377
|
-
struct um_op op;
|
|
1378
|
-
um_prep_op(machine,
|
|
1487
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1488
|
+
um_prep_op(machine, op, OP_RECV_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1379
1489
|
|
|
1380
|
-
struct op_ctx ctx = { .machine = machine, .op =
|
|
1490
|
+
struct op_ctx ctx = { .machine = machine, .op = op, .fd = fd, .bgid = bgid, .read_buf = NULL, .flags = flags };
|
|
1381
1491
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1382
1492
|
}
|
|
1383
1493
|
|
|
1384
1494
|
VALUE periodically_start(VALUE arg) {
|
|
1385
1495
|
struct op_ctx *ctx = (struct op_ctx *)arg;
|
|
1386
1496
|
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
|
|
1387
|
-
io_uring_prep_timeout(sqe, &ctx->ts, 0, IORING_TIMEOUT_MULTISHOT);
|
|
1497
|
+
io_uring_prep_timeout(sqe, &ctx->op->ts, 0, IORING_TIMEOUT_MULTISHOT);
|
|
1388
1498
|
|
|
1389
1499
|
while (true) {
|
|
1390
1500
|
VALUE ret = um_switch(ctx->machine);
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
}
|
|
1501
|
+
|
|
1502
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1503
|
+
if (unlikely(!OP_CQE_SEEN_P(ctx->op))) return ret;
|
|
1395
1504
|
RB_GC_GUARD(ret);
|
|
1396
1505
|
|
|
1397
|
-
int more = false;
|
|
1398
1506
|
struct um_op_result *result = &ctx->op->result;
|
|
1399
1507
|
while (result) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1403
|
-
return Qnil;
|
|
1404
|
-
}
|
|
1508
|
+
if (unlikely(result->res < 0 && result->res != -ETIME)) um_raise_on_error_result(result->res);
|
|
1509
|
+
|
|
1405
1510
|
rb_yield(Qnil);
|
|
1406
1511
|
result = result->next;
|
|
1407
1512
|
}
|
|
1513
|
+
if (OP_CQE_DONE_P(ctx->op)) break;
|
|
1514
|
+
|
|
1408
1515
|
um_op_multishot_results_clear(ctx->machine, ctx->op);
|
|
1409
|
-
|
|
1410
|
-
ctx->op->flags &= ~OP_F_COMPLETED;
|
|
1411
|
-
else
|
|
1412
|
-
break;
|
|
1516
|
+
ctx->op->flags &= ~OP_F_CQE_SEEN;
|
|
1413
1517
|
}
|
|
1414
1518
|
|
|
1415
1519
|
return Qnil;
|
|
1416
1520
|
}
|
|
1417
1521
|
|
|
1418
1522
|
VALUE um_periodically(struct um *machine, double interval) {
|
|
1419
|
-
struct um_op op;
|
|
1420
|
-
um_prep_op(machine,
|
|
1421
|
-
op
|
|
1523
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1524
|
+
um_prep_op(machine, op, OP_TIMEOUT_MULTISHOT, 2, OP_F_MULTISHOT);
|
|
1525
|
+
op->ts = um_double_to_timespec(interval);
|
|
1422
1526
|
|
|
1423
|
-
struct op_ctx ctx = { .machine = machine, .op =
|
|
1527
|
+
struct op_ctx ctx = { .machine = machine, .op = op, .read_buf = NULL };
|
|
1424
1528
|
return rb_ensure(periodically_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
|
1529
|
+
return Qnil;
|
|
1425
1530
|
}
|
|
1426
1531
|
|
|
1427
1532
|
extern VALUE SYM_size;
|