uringmachine 0.3 → 0.4
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/README.md +85 -0
- data/TODO.md +5 -0
- data/examples/echo_server.rb +18 -40
- data/examples/inout.rb +19 -0
- data/examples/nc.rb +36 -0
- data/ext/um/extconf.rb +6 -15
- data/ext/um/um.c +245 -53
- data/ext/um/um.h +21 -9
- data/ext/um/um_class.c +74 -87
- data/ext/um/um_const.c +184 -0
- data/ext/um/um_op.c +10 -13
- data/ext/um/um_utils.c +48 -3
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +12 -0
- data/test/helper.rb +8 -0
- data/test/test_um.rb +227 -7
- data/vendor/liburing/.github/workflows/build.yml +29 -1
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +15 -0
- data/vendor/liburing/CONTRIBUTING.md +165 -0
- data/vendor/liburing/configure +32 -0
- data/vendor/liburing/examples/Makefile +8 -1
- data/vendor/liburing/examples/kdigest.c +405 -0
- data/vendor/liburing/examples/proxy.c +75 -8
- data/vendor/liburing/liburing.pc.in +1 -1
- data/vendor/liburing/src/Makefile +16 -2
- data/vendor/liburing/src/include/liburing/io_uring.h +31 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +39 -0
- data/vendor/liburing/src/include/liburing.h +31 -4
- data/vendor/liburing/src/liburing-ffi.map +5 -0
- data/vendor/liburing/src/liburing.map +1 -0
- data/vendor/liburing/src/queue.c +3 -0
- data/vendor/liburing/src/register.c +36 -0
- data/vendor/liburing/src/sanitize.c +176 -0
- data/vendor/liburing/src/setup.c +1 -1
- data/vendor/liburing/test/35fa71a030ca.c +7 -0
- data/vendor/liburing/test/500f9fbadef8.c +2 -0
- data/vendor/liburing/test/7ad0e4b2f83c.c +0 -25
- data/vendor/liburing/test/917257daa0fe.c +7 -0
- data/vendor/liburing/test/Makefile +31 -4
- data/vendor/liburing/test/a0908ae19763.c +7 -0
- data/vendor/liburing/test/a4c0b3decb33.c +7 -0
- data/vendor/liburing/test/accept.c +14 -4
- data/vendor/liburing/test/b19062a56726.c +7 -0
- data/vendor/liburing/test/bind-listen.c +2 -2
- data/vendor/liburing/test/buf-ring-nommap.c +10 -3
- data/vendor/liburing/test/buf-ring.c +2 -0
- data/vendor/liburing/test/coredump.c +7 -0
- data/vendor/liburing/test/cq-overflow.c +13 -1
- data/vendor/liburing/test/d4ae271dfaae.c +11 -3
- data/vendor/liburing/test/defer-taskrun.c +2 -2
- data/vendor/liburing/test/defer-tw-timeout.c +4 -1
- data/vendor/liburing/test/defer.c +2 -2
- data/vendor/liburing/test/double-poll-crash.c +1 -1
- data/vendor/liburing/test/eeed8b54e0df.c +2 -0
- data/vendor/liburing/test/eventfd.c +0 -1
- data/vendor/liburing/test/exit-no-cleanup.c +11 -0
- data/vendor/liburing/test/fadvise.c +9 -26
- data/vendor/liburing/test/fdinfo.c +9 -1
- data/vendor/liburing/test/file-register.c +14 -2
- data/vendor/liburing/test/file-update.c +1 -1
- data/vendor/liburing/test/file-verify.c +27 -16
- data/vendor/liburing/test/files-exit-hang-timeout.c +1 -2
- data/vendor/liburing/test/fixed-buf-iter.c +3 -1
- data/vendor/liburing/test/fixed-hugepage.c +12 -1
- data/vendor/liburing/test/fsnotify.c +1 -0
- data/vendor/liburing/test/futex.c +16 -4
- data/vendor/liburing/test/helpers.c +47 -0
- data/vendor/liburing/test/helpers.h +6 -0
- data/vendor/liburing/test/init-mem.c +5 -3
- data/vendor/liburing/test/io-cancel.c +0 -24
- data/vendor/liburing/test/io_uring_passthrough.c +2 -0
- data/vendor/liburing/test/io_uring_register.c +25 -6
- data/vendor/liburing/test/iopoll-leak.c +4 -0
- data/vendor/liburing/test/iopoll-overflow.c +1 -1
- data/vendor/liburing/test/iopoll.c +3 -3
- data/vendor/liburing/test/kallsyms.c +203 -0
- data/vendor/liburing/test/link-timeout.c +159 -0
- data/vendor/liburing/test/linked-defer-close.c +224 -0
- data/vendor/liburing/test/madvise.c +12 -25
- data/vendor/liburing/test/min-timeout-wait.c +0 -25
- data/vendor/liburing/test/min-timeout.c +0 -25
- data/vendor/liburing/test/mkdir.c +6 -0
- data/vendor/liburing/test/msg-ring.c +8 -2
- data/vendor/liburing/test/napi-test.c +15 -2
- data/vendor/liburing/test/no-mmap-inval.c +2 -0
- data/vendor/liburing/test/nop.c +44 -0
- data/vendor/liburing/test/ooo-file-unreg.c +1 -1
- data/vendor/liburing/test/open-close.c +40 -0
- data/vendor/liburing/test/openat2.c +37 -14
- data/vendor/liburing/test/poll-many.c +13 -7
- data/vendor/liburing/test/poll-mshot-update.c +17 -10
- data/vendor/liburing/test/poll-v-poll.c +6 -3
- data/vendor/liburing/test/pollfree.c +148 -0
- data/vendor/liburing/test/read-mshot-empty.c +156 -153
- data/vendor/liburing/test/read-mshot.c +276 -27
- data/vendor/liburing/test/read-write.c +78 -13
- data/vendor/liburing/test/recv-msgall-stream.c +3 -0
- data/vendor/liburing/test/recv-msgall.c +5 -0
- data/vendor/liburing/test/recvsend_bundle-inc.c +680 -0
- data/vendor/liburing/test/recvsend_bundle.c +92 -29
- data/vendor/liburing/test/reg-fd-only.c +14 -4
- data/vendor/liburing/test/regbuf-clone.c +187 -0
- data/vendor/liburing/test/regbuf-merge.c +7 -0
- data/vendor/liburing/test/register-restrictions.c +86 -85
- data/vendor/liburing/test/rename.c +59 -1
- data/vendor/liburing/test/ringbuf-read.c +5 -0
- data/vendor/liburing/test/ringbuf-status.c +5 -1
- data/vendor/liburing/test/runtests.sh +16 -1
- data/vendor/liburing/test/send-zerocopy.c +59 -0
- data/vendor/liburing/test/short-read.c +1 -0
- data/vendor/liburing/test/socket.c +43 -0
- data/vendor/liburing/test/splice.c +3 -1
- data/vendor/liburing/test/sq-poll-dup.c +1 -1
- data/vendor/liburing/test/sq-poll-share.c +2 -0
- data/vendor/liburing/test/sqpoll-disable-exit.c +8 -0
- data/vendor/liburing/test/sqpoll-exit-hang.c +1 -25
- data/vendor/liburing/test/sqpoll-sleep.c +1 -25
- data/vendor/liburing/test/statx.c +89 -0
- data/vendor/liburing/test/stdout.c +2 -0
- data/vendor/liburing/test/submit-and-wait.c +1 -25
- data/vendor/liburing/test/submit-reuse.c +4 -26
- data/vendor/liburing/test/symlink.c +12 -1
- data/vendor/liburing/test/sync-cancel.c +48 -21
- data/vendor/liburing/test/thread-exit.c +5 -0
- data/vendor/liburing/test/timeout-new.c +1 -26
- data/vendor/liburing/test/timeout.c +12 -26
- data/vendor/liburing/test/unlink.c +94 -1
- data/vendor/liburing/test/uring_cmd_ublk.c +1252 -0
- data/vendor/liburing/test/waitid.c +62 -8
- data/vendor/liburing/test/wq-aff.c +35 -0
- data/vendor/liburing/test/xfail_prep_link_timeout_out_of_scope.c +46 -0
- data/vendor/liburing/test/xfail_register_buffers_out_of_scope.c +51 -0
- metadata +17 -4
- data/examples/event_loop.rb +0 -69
- data/examples/fibers.rb +0 -105
data/ext/um/um.c
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#include "um.h"
|
|
2
2
|
#include "ruby/thread.h"
|
|
3
|
-
#include <sys/mman.h>
|
|
4
3
|
|
|
5
4
|
void um_setup(struct um *machine) {
|
|
6
5
|
machine->ring_initialized = 0;
|
|
@@ -13,7 +12,7 @@ void um_setup(struct um *machine) {
|
|
|
13
12
|
machine->result_freelist = NULL;
|
|
14
13
|
|
|
15
14
|
unsigned prepared_limit = 4096;
|
|
16
|
-
|
|
15
|
+
unsigned flags = 0;
|
|
17
16
|
#ifdef HAVE_IORING_SETUP_SUBMIT_ALL
|
|
18
17
|
flags |= IORING_SETUP_SUBMIT_ALL;
|
|
19
18
|
#endif
|
|
@@ -98,6 +97,7 @@ inline void um_handle_submitted_op_cqe_single(struct um *machine, struct um_op *
|
|
|
98
97
|
|
|
99
98
|
inline void um_handle_submitted_op_cqe_multi(struct um *machine, struct um_op *op, struct io_uring_cqe *cqe) {
|
|
100
99
|
if (!op->results_head) {
|
|
100
|
+
// if no results are ready yet, schedule the corresponding fiber
|
|
101
101
|
struct um_op *op2 = um_op_checkout(machine);
|
|
102
102
|
op2->state = OP_schedule;
|
|
103
103
|
op2->fiber = op->fiber;
|
|
@@ -114,16 +114,19 @@ inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe) {
|
|
|
114
114
|
struct um_op *op = (struct um_op *)cqe->user_data;
|
|
115
115
|
if (unlikely(!op)) return;
|
|
116
116
|
|
|
117
|
+
// if (op->is_multishot)
|
|
118
|
+
// printf("process_cqe %p state: %d result: %d flags: %d (%d)\n", op, op->state, cqe->res, cqe->flags, (cqe->flags & IORING_CQE_F_MORE));
|
|
119
|
+
|
|
117
120
|
switch (op->state) {
|
|
118
121
|
case OP_submitted:
|
|
119
122
|
if (unlikely(cqe->res == -ECANCELED)) {
|
|
120
123
|
um_op_checkin(machine, op);
|
|
121
124
|
break;
|
|
122
125
|
}
|
|
123
|
-
if (
|
|
124
|
-
um_handle_submitted_op_cqe_single(machine, op, cqe);
|
|
125
|
-
else
|
|
126
|
+
if (op->is_multishot)
|
|
126
127
|
um_handle_submitted_op_cqe_multi(machine, op, cqe);
|
|
128
|
+
else
|
|
129
|
+
um_handle_submitted_op_cqe_single(machine, op, cqe);
|
|
127
130
|
break;
|
|
128
131
|
case OP_abandonned:
|
|
129
132
|
// op has been abandonned by the I/O method, so we need to cleanup (check
|
|
@@ -196,7 +199,7 @@ loop:
|
|
|
196
199
|
// we need to submit events and check completions without blocking
|
|
197
200
|
if (
|
|
198
201
|
unlikely(
|
|
199
|
-
first_iteration && machine->unsubmitted_count &&
|
|
202
|
+
first_iteration && machine->unsubmitted_count &&
|
|
200
203
|
machine->runqueue_head &&
|
|
201
204
|
machine->runqueue_head->fiber == rb_fiber_current()
|
|
202
205
|
)
|
|
@@ -209,9 +212,9 @@ loop:
|
|
|
209
212
|
op = um_runqueue_shift(machine);
|
|
210
213
|
if (op) {
|
|
211
214
|
VALUE resume_value = op->resume_value;
|
|
212
|
-
if (op->state == OP_schedule)
|
|
215
|
+
if (op->state == OP_schedule)
|
|
213
216
|
um_op_checkin(machine, op);
|
|
214
|
-
|
|
217
|
+
|
|
215
218
|
// the resume value is disregarded, we pass the fiber itself
|
|
216
219
|
VALUE v = rb_fiber_transfer(op->fiber, 1, &resume_value);
|
|
217
220
|
return v;
|
|
@@ -226,7 +229,7 @@ static inline void um_cancel_op(struct um *machine, struct um_op *op) {
|
|
|
226
229
|
io_uring_prep_cancel64(sqe, (long long)op, 0);
|
|
227
230
|
}
|
|
228
231
|
|
|
229
|
-
static inline VALUE um_await_op(struct um *machine, struct um_op *op,
|
|
232
|
+
static inline VALUE um_await_op(struct um *machine, struct um_op *op, __s32 *result, __u32 *flags) {
|
|
230
233
|
op->fiber = rb_fiber_current();
|
|
231
234
|
VALUE v = um_fiber_switch(machine);
|
|
232
235
|
int is_exception = um_value_is_exception_p(v);
|
|
@@ -240,8 +243,6 @@ static inline VALUE um_await_op(struct um *machine, struct um_op *op, int *resul
|
|
|
240
243
|
// checked in.
|
|
241
244
|
if (result) *result = op->cqe_result;
|
|
242
245
|
if (flags) *flags = op->cqe_flags;
|
|
243
|
-
if (!op->is_multishot)
|
|
244
|
-
um_op_checkin(machine, op);
|
|
245
246
|
}
|
|
246
247
|
|
|
247
248
|
if (unlikely(is_exception)) um_raise_exception(v);
|
|
@@ -279,7 +280,11 @@ inline void um_interrupt(struct um *machine, VALUE fiber, VALUE value) {
|
|
|
279
280
|
struct op_ensure_ctx {
|
|
280
281
|
struct um *machine;
|
|
281
282
|
struct um_op *op;
|
|
283
|
+
int fd;
|
|
282
284
|
int bgid;
|
|
285
|
+
|
|
286
|
+
void *read_buf;
|
|
287
|
+
int read_maxlen;
|
|
283
288
|
};
|
|
284
289
|
|
|
285
290
|
VALUE um_timeout_ensure(VALUE arg) {
|
|
@@ -291,10 +296,10 @@ VALUE um_timeout_ensure(VALUE arg) {
|
|
|
291
296
|
um_cancel_op(ctx->machine, ctx->op);
|
|
292
297
|
ctx->op->state == OP_abandonned;
|
|
293
298
|
}
|
|
294
|
-
else
|
|
299
|
+
else
|
|
295
300
|
// completed, so can be checked in
|
|
296
301
|
um_op_checkin(ctx->machine, ctx->op);
|
|
297
|
-
|
|
302
|
+
|
|
298
303
|
return Qnil;
|
|
299
304
|
}
|
|
300
305
|
|
|
@@ -315,23 +320,31 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
|
315
320
|
return rb_ensure(rb_yield, Qnil, um_timeout_ensure, (VALUE)&ctx);
|
|
316
321
|
}
|
|
317
322
|
|
|
323
|
+
inline void discard_op_if_completed(struct um *machine, struct um_op *op) {
|
|
324
|
+
if (op->state == OP_completed) um_op_checkin(machine, op);
|
|
325
|
+
}
|
|
326
|
+
|
|
318
327
|
inline VALUE um_sleep(struct um *machine, double duration) {
|
|
319
328
|
struct um_op *op = um_op_checkout(machine);
|
|
320
329
|
op->ts = um_double_to_timespec(duration);
|
|
321
330
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
322
|
-
|
|
331
|
+
__s32 result = 0;
|
|
323
332
|
|
|
324
333
|
io_uring_prep_timeout(sqe, &op->ts, 0, 0);
|
|
325
334
|
op->state = OP_submitted;
|
|
326
335
|
|
|
327
|
-
|
|
336
|
+
um_await_op(machine, op, &result, NULL);
|
|
337
|
+
|
|
338
|
+
discard_op_if_completed(machine, op);
|
|
339
|
+
if (result != -ETIME) um_raise_on_system_error(result);
|
|
340
|
+
return Qnil;
|
|
328
341
|
}
|
|
329
342
|
|
|
330
343
|
inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset) {
|
|
331
344
|
struct um_op *op = um_op_checkout(machine);
|
|
332
345
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
333
|
-
|
|
334
|
-
|
|
346
|
+
__s32 result = 0;
|
|
347
|
+
__u32 flags = 0;
|
|
335
348
|
|
|
336
349
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, buffer_offset);
|
|
337
350
|
io_uring_prep_read(sqe, fd, ptr, maxlen, -1);
|
|
@@ -339,6 +352,7 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
|
|
|
339
352
|
|
|
340
353
|
um_await_op(machine, op, &result, &flags);
|
|
341
354
|
|
|
355
|
+
discard_op_if_completed(machine, op);
|
|
342
356
|
um_raise_on_system_error(result);
|
|
343
357
|
um_update_read_buffer(machine, buffer, buffer_offset, result, flags);
|
|
344
358
|
return INT2FIX(result);
|
|
@@ -346,6 +360,7 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
|
|
|
346
360
|
|
|
347
361
|
VALUE um_multishot_ensure(VALUE arg) {
|
|
348
362
|
struct op_ensure_ctx *ctx = (struct op_ensure_ctx *)arg;
|
|
363
|
+
|
|
349
364
|
switch (ctx->op->state) {
|
|
350
365
|
case OP_submitted:
|
|
351
366
|
um_cancel_op(ctx->machine, ctx->op);
|
|
@@ -353,59 +368,141 @@ VALUE um_multishot_ensure(VALUE arg) {
|
|
|
353
368
|
case OP_completed:
|
|
354
369
|
um_op_checkin(ctx->machine, ctx->op);
|
|
355
370
|
break;
|
|
356
|
-
default:
|
|
371
|
+
default:
|
|
357
372
|
}
|
|
373
|
+
|
|
374
|
+
if (ctx->read_buf) free(ctx->read_buf);
|
|
358
375
|
return Qnil;
|
|
359
376
|
}
|
|
360
377
|
|
|
378
|
+
static inline void um_read_each_prepare_op(struct op_ensure_ctx *ctx, int singleshot_mode) {
|
|
379
|
+
struct um_op *op = um_op_checkout(ctx->machine);
|
|
380
|
+
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, op);
|
|
381
|
+
|
|
382
|
+
if (singleshot_mode)
|
|
383
|
+
io_uring_prep_read(sqe, ctx->fd, ctx->read_buf, ctx->read_maxlen, -1);
|
|
384
|
+
else {
|
|
385
|
+
io_uring_prep_read_multishot(sqe, ctx->fd, 0, -1, ctx->bgid);
|
|
386
|
+
op->is_multishot = 1;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
op->state = OP_submitted;
|
|
390
|
+
ctx->op = op;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
int um_read_each_safe_loop_singleshot(struct op_ensure_ctx *ctx, int total) {
|
|
394
|
+
struct buf_ring_descriptor *desc = ctx->machine->buffer_rings + ctx->bgid;
|
|
395
|
+
__s32 result = 0;
|
|
396
|
+
ctx->read_maxlen = desc->buf_size;
|
|
397
|
+
ctx->read_buf = malloc(desc->buf_size);
|
|
398
|
+
|
|
399
|
+
while (1) {
|
|
400
|
+
um_read_each_prepare_op(ctx, 1);
|
|
401
|
+
um_await_op(ctx->machine, ctx->op, &result, NULL);
|
|
402
|
+
um_raise_on_system_error(result);
|
|
403
|
+
if (!result) return total;
|
|
404
|
+
|
|
405
|
+
total += result;
|
|
406
|
+
VALUE buf = rb_str_new(ctx->read_buf, result);
|
|
407
|
+
rb_yield(buf);
|
|
408
|
+
um_op_checkin(ctx->machine, ctx->op);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
int um_read_each_multishot_process_results(struct op_ensure_ctx *ctx, int *total) {
|
|
415
|
+
__s32 result = 0;
|
|
416
|
+
__u32 flags = 0;
|
|
417
|
+
__s32 bad_result = 0;
|
|
418
|
+
int eof = 0;
|
|
419
|
+
|
|
420
|
+
while (um_op_result_shift(ctx->machine, ctx->op, &result, &flags)) {
|
|
421
|
+
if (result < 0) {
|
|
422
|
+
bad_result = result;
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
if (result == 0) {
|
|
426
|
+
eof = 1;
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
*total += result;
|
|
431
|
+
VALUE buf = um_get_string_from_buffer_ring(ctx->machine, ctx->bgid, result, flags);
|
|
432
|
+
rb_yield(buf);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (ctx->op->state == OP_completed) {
|
|
436
|
+
um_op_checkin(ctx->machine, ctx->op);
|
|
437
|
+
|
|
438
|
+
// TTY devices might not support multishot reads:
|
|
439
|
+
// https://github.com/axboe/liburing/issues/1185. A workaround is to
|
|
440
|
+
// fallback to singleshot mode, using the first buffer in the buffer
|
|
441
|
+
// group.
|
|
442
|
+
if (!(flags & IORING_CQE_F_BUFFER)) {
|
|
443
|
+
*total = um_read_each_safe_loop_singleshot(ctx, *total);
|
|
444
|
+
return 0;
|
|
445
|
+
}
|
|
446
|
+
else
|
|
447
|
+
um_read_each_prepare_op(ctx, 0);
|
|
448
|
+
}
|
|
449
|
+
if (bad_result)
|
|
450
|
+
um_raise_on_system_error(bad_result);
|
|
451
|
+
|
|
452
|
+
return eof ? 0 : 1;
|
|
453
|
+
}
|
|
454
|
+
|
|
361
455
|
VALUE um_read_each_safe_loop(VALUE arg) {
|
|
362
456
|
struct op_ensure_ctx *ctx = (struct op_ensure_ctx *)arg;
|
|
363
|
-
int result = 0;
|
|
364
|
-
int flags = 0;
|
|
365
457
|
int total = 0;
|
|
366
458
|
|
|
459
|
+
um_read_each_prepare_op(ctx, 0);
|
|
460
|
+
|
|
367
461
|
while (1) {
|
|
368
462
|
um_await_op(ctx->machine, ctx->op, NULL, NULL);
|
|
369
|
-
if (!ctx->op->results_head)
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (likely(result > 0)) {
|
|
375
|
-
total += result;
|
|
376
|
-
VALUE buf = get_string_from_buffer_ring(ctx->machine, ctx->bgid, result, flags);
|
|
377
|
-
rb_yield(buf);
|
|
378
|
-
}
|
|
379
|
-
else
|
|
380
|
-
return INT2FIX(total);
|
|
381
|
-
}
|
|
463
|
+
if (!ctx->op->results_head)
|
|
464
|
+
rb_raise(rb_eRuntimeError, "no result found!\n");
|
|
465
|
+
|
|
466
|
+
if (!um_read_each_multishot_process_results(ctx, &total))
|
|
467
|
+
return INT2NUM(total);
|
|
382
468
|
}
|
|
383
469
|
}
|
|
384
470
|
|
|
385
471
|
VALUE um_read_each(struct um *machine, int fd, int bgid) {
|
|
472
|
+
struct op_ensure_ctx ctx = { .machine = machine, .fd = fd, .bgid = bgid, .read_buf = NULL };
|
|
473
|
+
return rb_ensure(um_read_each_safe_loop, (VALUE)&ctx, um_multishot_ensure, (VALUE)&ctx);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
VALUE um_write(struct um *machine, int fd, VALUE buffer, int len) {
|
|
386
477
|
struct um_op *op = um_op_checkout(machine);
|
|
387
478
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
479
|
+
__s32 result = 0;
|
|
480
|
+
__u32 flags = 0;
|
|
388
481
|
|
|
389
|
-
|
|
390
|
-
io_uring_prep_read_multishot(sqe, fd, 0, -1, bgid);
|
|
482
|
+
io_uring_prep_write(sqe, fd, RSTRING_PTR(buffer), len, -1);
|
|
391
483
|
op->state = OP_submitted;
|
|
392
484
|
|
|
393
|
-
|
|
394
|
-
|
|
485
|
+
um_await_op(machine, op, &result, &flags);
|
|
486
|
+
|
|
487
|
+
discard_op_if_completed(machine, op);
|
|
488
|
+
um_raise_on_system_error(result);
|
|
489
|
+
return INT2FIX(result);
|
|
395
490
|
}
|
|
396
491
|
|
|
397
|
-
VALUE
|
|
492
|
+
VALUE um_close(struct um *machine, int fd) {
|
|
398
493
|
struct um_op *op = um_op_checkout(machine);
|
|
399
494
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
400
|
-
|
|
401
|
-
|
|
495
|
+
__s32 result = 0;
|
|
496
|
+
__u32 flags = 0;
|
|
402
497
|
|
|
403
|
-
|
|
498
|
+
io_uring_prep_close(sqe, fd);
|
|
404
499
|
op->state = OP_submitted;
|
|
405
500
|
|
|
406
501
|
um_await_op(machine, op, &result, &flags);
|
|
502
|
+
|
|
503
|
+
discard_op_if_completed(machine, op);
|
|
407
504
|
um_raise_on_system_error(result);
|
|
408
|
-
return INT2FIX(
|
|
505
|
+
return INT2FIX(fd);
|
|
409
506
|
}
|
|
410
507
|
|
|
411
508
|
VALUE um_accept(struct um *machine, int fd) {
|
|
@@ -413,28 +510,33 @@ VALUE um_accept(struct um *machine, int fd) {
|
|
|
413
510
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
414
511
|
struct sockaddr addr;
|
|
415
512
|
socklen_t len;
|
|
416
|
-
|
|
417
|
-
|
|
513
|
+
__s32 result = 0;
|
|
514
|
+
__u32 flags = 0;
|
|
515
|
+
|
|
418
516
|
io_uring_prep_accept(sqe, fd, &addr, &len, 0);
|
|
419
517
|
op->state = OP_submitted;
|
|
420
518
|
|
|
421
519
|
um_await_op(machine, op, &result, &flags);
|
|
520
|
+
|
|
521
|
+
discard_op_if_completed(machine, op);
|
|
422
522
|
um_raise_on_system_error(result);
|
|
423
523
|
return INT2FIX(result);
|
|
424
524
|
}
|
|
425
525
|
|
|
426
526
|
VALUE um_accept_each_safe_loop(VALUE arg) {
|
|
427
527
|
struct op_ensure_ctx *ctx = (struct op_ensure_ctx *)arg;
|
|
428
|
-
|
|
429
|
-
|
|
528
|
+
__s32 result = 0;
|
|
529
|
+
__u32 flags = 0;
|
|
430
530
|
|
|
431
531
|
while (1) {
|
|
432
|
-
um_await_op(ctx->machine, ctx->op,
|
|
532
|
+
um_await_op(ctx->machine, ctx->op, &result, &flags);
|
|
433
533
|
if (!ctx->op->results_head) {
|
|
434
|
-
//
|
|
435
|
-
|
|
534
|
+
// this shouldn't happen!
|
|
535
|
+
rb_raise(rb_eRuntimeError, "no result found for accept_each loop");
|
|
436
536
|
}
|
|
537
|
+
|
|
437
538
|
while (um_op_result_shift(ctx->machine, ctx->op, &result, &flags)) {
|
|
539
|
+
um_raise_on_system_error(result);
|
|
438
540
|
if (likely(result > 0))
|
|
439
541
|
rb_yield(INT2FIX(result));
|
|
440
542
|
else
|
|
@@ -446,12 +548,102 @@ VALUE um_accept_each_safe_loop(VALUE arg) {
|
|
|
446
548
|
VALUE um_accept_each(struct um *machine, int fd) {
|
|
447
549
|
struct um_op *op = um_op_checkout(machine);
|
|
448
550
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
449
|
-
|
|
450
|
-
socklen_t len;
|
|
451
|
-
io_uring_prep_multishot_accept(sqe, fd, &addr, &len, 0);
|
|
551
|
+
io_uring_prep_multishot_accept(sqe, fd, NULL, NULL, 0);
|
|
452
552
|
op->state = OP_submitted;
|
|
453
553
|
op->is_multishot = 1;
|
|
454
554
|
|
|
455
|
-
struct op_ensure_ctx ctx = { .machine = machine, .op = op };
|
|
555
|
+
struct op_ensure_ctx ctx = { .machine = machine, .op = op, .read_buf = NULL };
|
|
456
556
|
return rb_ensure(um_accept_each_safe_loop, (VALUE)&ctx, um_multishot_ensure, (VALUE)&ctx);
|
|
457
557
|
}
|
|
558
|
+
|
|
559
|
+
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags) {
|
|
560
|
+
struct um_op *op = um_op_checkout(machine);
|
|
561
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
562
|
+
int result = 0;
|
|
563
|
+
|
|
564
|
+
io_uring_prep_socket(sqe, domain, type, protocol, flags);
|
|
565
|
+
op->state = OP_submitted;
|
|
566
|
+
|
|
567
|
+
um_await_op(machine, op, &result, NULL);
|
|
568
|
+
|
|
569
|
+
discard_op_if_completed(machine, op);
|
|
570
|
+
um_raise_on_system_error(result);
|
|
571
|
+
return INT2FIX(result);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
|
575
|
+
struct um_op *op = um_op_checkout(machine);
|
|
576
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
577
|
+
int result = 0;
|
|
578
|
+
|
|
579
|
+
io_uring_prep_connect(sqe, fd, addr, addrlen);
|
|
580
|
+
op->state = OP_submitted;
|
|
581
|
+
|
|
582
|
+
um_await_op(machine, op, &result, NULL);
|
|
583
|
+
|
|
584
|
+
discard_op_if_completed(machine, op);
|
|
585
|
+
um_raise_on_system_error(result);
|
|
586
|
+
return INT2FIX(result);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
|
590
|
+
struct um_op *op = um_op_checkout(machine);
|
|
591
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
592
|
+
int result = 0;
|
|
593
|
+
|
|
594
|
+
io_uring_prep_send(sqe, fd, RSTRING_PTR(buffer), len, flags);
|
|
595
|
+
op->state = OP_submitted;
|
|
596
|
+
|
|
597
|
+
um_await_op(machine, op, &result, NULL);
|
|
598
|
+
|
|
599
|
+
discard_op_if_completed(machine, op);
|
|
600
|
+
um_raise_on_system_error(result);
|
|
601
|
+
return INT2FIX(result);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
|
605
|
+
struct um_op *op = um_op_checkout(machine);
|
|
606
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
607
|
+
int result = 0;
|
|
608
|
+
|
|
609
|
+
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
|
|
610
|
+
io_uring_prep_recv(sqe, fd, ptr, maxlen, flags);
|
|
611
|
+
op->state = OP_submitted;
|
|
612
|
+
|
|
613
|
+
um_await_op(machine, op, &result, NULL);
|
|
614
|
+
|
|
615
|
+
discard_op_if_completed(machine, op);
|
|
616
|
+
um_raise_on_system_error(result);
|
|
617
|
+
um_update_read_buffer(machine, buffer, 0, result, flags);
|
|
618
|
+
return INT2FIX(result);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen) {
|
|
622
|
+
struct um_op *op = um_op_checkout(machine);
|
|
623
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
624
|
+
int result = 0;
|
|
625
|
+
|
|
626
|
+
io_uring_prep_bind(sqe, fd, addr, addrlen);
|
|
627
|
+
op->state = OP_submitted;
|
|
628
|
+
|
|
629
|
+
um_await_op(machine, op, &result, NULL);
|
|
630
|
+
|
|
631
|
+
discard_op_if_completed(machine, op);
|
|
632
|
+
um_raise_on_system_error(result);
|
|
633
|
+
return INT2FIX(result);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
VALUE um_listen(struct um *machine, int fd, int backlog) {
|
|
637
|
+
struct um_op *op = um_op_checkout(machine);
|
|
638
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
639
|
+
int result = 0;
|
|
640
|
+
|
|
641
|
+
io_uring_prep_listen(sqe, fd, backlog);
|
|
642
|
+
op->state = OP_submitted;
|
|
643
|
+
|
|
644
|
+
um_await_op(machine, op, &result, NULL);
|
|
645
|
+
|
|
646
|
+
discard_op_if_completed(machine, op);
|
|
647
|
+
um_raise_on_system_error(result);
|
|
648
|
+
return INT2FIX(result);
|
|
649
|
+
}
|
data/ext/um/um.h
CHANGED
|
@@ -32,8 +32,8 @@ enum op_state {
|
|
|
32
32
|
struct um_result_entry {
|
|
33
33
|
struct um_result_entry *next;
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
__s32 result;
|
|
36
|
+
__u32 flags;
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
struct um_op {
|
|
@@ -44,12 +44,12 @@ struct um_op {
|
|
|
44
44
|
// linked list for multishot results
|
|
45
45
|
struct um_result_entry *results_head;
|
|
46
46
|
struct um_result_entry *results_tail;
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
VALUE fiber;
|
|
49
49
|
VALUE resume_value;
|
|
50
50
|
int is_multishot;
|
|
51
51
|
struct __kernel_timespec ts;
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
int cqe_result;
|
|
54
54
|
int cqe_flags;
|
|
55
55
|
};
|
|
@@ -59,7 +59,8 @@ struct buf_ring_descriptor {
|
|
|
59
59
|
size_t br_size;
|
|
60
60
|
unsigned buf_count;
|
|
61
61
|
unsigned buf_size;
|
|
62
|
-
|
|
62
|
+
unsigned buf_mask;
|
|
63
|
+
void *buf_base;
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
#define BUFFER_RING_MAX_COUNT 10
|
|
@@ -94,16 +95,18 @@ VALUE um_raise_exception(VALUE v);
|
|
|
94
95
|
void um_raise_on_system_error(int result);
|
|
95
96
|
|
|
96
97
|
void * um_prepare_read_buffer(VALUE buffer, unsigned len, int ofs);
|
|
97
|
-
void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset,
|
|
98
|
-
|
|
98
|
+
void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, __s32 result, __u32 flags);
|
|
99
|
+
|
|
100
|
+
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
|
|
101
|
+
VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
|
99
102
|
|
|
100
103
|
VALUE um_fiber_switch(struct um *machine);
|
|
101
104
|
VALUE um_await(struct um *machine);
|
|
102
105
|
|
|
103
106
|
void um_op_checkin(struct um *machine, struct um_op *op);
|
|
104
107
|
struct um_op* um_op_checkout(struct um *machine);
|
|
105
|
-
void um_op_result_push(struct um *machine, struct um_op *op,
|
|
106
|
-
int um_op_result_shift(struct um *machine, struct um_op *op,
|
|
108
|
+
void um_op_result_push(struct um *machine, struct um_op *op, __s32 result, __u32 flags);
|
|
109
|
+
int um_op_result_shift(struct um *machine, struct um_op *op, __s32 *result, __u32 *flags);
|
|
107
110
|
|
|
108
111
|
struct um_op *um_runqueue_find_by_fiber(struct um *machine, VALUE fiber);
|
|
109
112
|
void um_runqueue_push(struct um *machine, struct um_op *op);
|
|
@@ -118,8 +121,17 @@ VALUE um_sleep(struct um *machine, double duration);
|
|
|
118
121
|
VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset);
|
|
119
122
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
|
120
123
|
VALUE um_write(struct um *machine, int fd, VALUE buffer, int len);
|
|
124
|
+
VALUE um_close(struct um *machine, int fd);
|
|
121
125
|
|
|
122
126
|
VALUE um_accept(struct um *machine, int fd);
|
|
123
127
|
VALUE um_accept_each(struct um *machine, int fd);
|
|
128
|
+
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags);
|
|
129
|
+
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen);
|
|
130
|
+
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags);
|
|
131
|
+
VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags);
|
|
132
|
+
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen);
|
|
133
|
+
VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
134
|
+
|
|
135
|
+
void um_define_net_constants(VALUE mod);
|
|
124
136
|
|
|
125
137
|
#endif // UM_H
|