uringmachine 0.3 → 0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|