uringmachine 0.12.1 → 0.14
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 +8 -0
- data/ext/um/um.c +65 -36
- data/ext/um/um.h +8 -1
- data/ext/um/um_async_op.c +1 -2
- data/ext/um/um_class.c +17 -0
- data/ext/um/um_sync.c +2 -2
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +8 -7
- data/test/helper.rb +16 -0
- data/test/test_fiber.rb +3 -4
- data/test/test_um.rb +82 -15
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 38a9b75f18075a31aa179cc63b67e7e80b75b3797a701e1b2164831f4c20c352
|
4
|
+
data.tar.gz: 50432253c8aca2713b7eeaf8ae69c72c1e4efece1c85285076cf91c97011a887
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7426118f51b6b3460d7ec46cc6e64e8a3aaa50e2552d2c44f718cfa79a9624310d9d68148f030be5a03582abf3fe520389e7a27fb814cff141c78f327f4f76a
|
7
|
+
data.tar.gz: a2e0ce93138435f99f84956ba82004fe06b4c7f530c37aa6585d998f2a4f6c448eac406ef0c7c602335bc776c5d40b543288f6e5cf16b1fe8bab1141fe7569c6
|
data/CHANGELOG.md
CHANGED
data/ext/um/um.c
CHANGED
@@ -72,6 +72,11 @@ static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe)
|
|
72
72
|
// op, op->kind, op->flags, cqe->res, cqe->flags, machine->pending_count
|
73
73
|
// );
|
74
74
|
|
75
|
+
if (op->flags & OP_F_FREE_ON_COMPLETE) {
|
76
|
+
um_op_free(machine, op);
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
|
75
80
|
if (unlikely((cqe->res == -ECANCELED) && (op->flags & OP_F_IGNORE_CANCELED))) return;
|
76
81
|
|
77
82
|
op->flags |= OP_F_COMPLETED;
|
@@ -247,20 +252,14 @@ inline VALUE um_await(struct um *machine) {
|
|
247
252
|
return raise_if_exception(v);
|
248
253
|
}
|
249
254
|
|
250
|
-
inline void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind) {
|
255
|
+
inline void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind, unsigned flags) {
|
251
256
|
memset(op, 0, sizeof(struct um_op));
|
252
257
|
op->kind = kind;
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
case OP_SLEEP_MULTISHOT:
|
259
|
-
op->flags |= OP_F_MULTISHOT;
|
260
|
-
default:
|
261
|
-
}
|
262
|
-
RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
|
263
|
-
op->value = Qnil;
|
258
|
+
op->flags = flags;
|
259
|
+
|
260
|
+
VALUE fiber = (flags & OP_F_FREE_ON_COMPLETE) ? Qnil : rb_fiber_current();
|
261
|
+
RB_OBJ_WRITE(machine->self, &op->fiber, fiber);
|
262
|
+
RB_OBJ_WRITE(machine->self, &op->value, Qnil);
|
264
263
|
}
|
265
264
|
|
266
265
|
inline void um_schedule(struct um *machine, VALUE fiber, VALUE value) {
|
@@ -302,7 +301,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
302
301
|
if (!ID_new) ID_new = rb_intern("new");
|
303
302
|
|
304
303
|
struct um_op *op = um_op_alloc(machine);
|
305
|
-
um_prep_op(machine, op, OP_TIMEOUT);
|
304
|
+
um_prep_op(machine, op, OP_TIMEOUT, 0);
|
306
305
|
op->ts = um_double_to_timespec(NUM2DBL(interval));
|
307
306
|
RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
|
308
307
|
RB_OBJ_WRITE(machine->self, &op->value, rb_funcall(class, ID_new, 0));
|
@@ -320,7 +319,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
320
319
|
|
321
320
|
VALUE um_sleep(struct um *machine, double duration) {
|
322
321
|
struct um_op op;
|
323
|
-
um_prep_op(machine, &op, OP_SLEEP);
|
322
|
+
um_prep_op(machine, &op, OP_SLEEP, 0);
|
324
323
|
op.ts = um_double_to_timespec(duration);
|
325
324
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
326
325
|
io_uring_prep_timeout(sqe, &op.ts, 0, 0);
|
@@ -339,7 +338,7 @@ VALUE um_sleep(struct um *machine, double duration) {
|
|
339
338
|
|
340
339
|
inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset) {
|
341
340
|
struct um_op op;
|
342
|
-
um_prep_op(machine, &op, OP_READ);
|
341
|
+
um_prep_op(machine, &op, OP_READ, 0);
|
343
342
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
344
343
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, buffer_offset);
|
345
344
|
io_uring_prep_read(sqe, fd, ptr, maxlen, -1);
|
@@ -358,7 +357,7 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
|
|
358
357
|
|
359
358
|
inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen) {
|
360
359
|
struct um_op op;
|
361
|
-
um_prep_op(machine, &op, OP_READ);
|
360
|
+
um_prep_op(machine, &op, OP_READ, 0);
|
362
361
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
363
362
|
io_uring_prep_read(sqe, fd, buffer, maxlen, -1);
|
364
363
|
|
@@ -374,7 +373,7 @@ inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen)
|
|
374
373
|
|
375
374
|
VALUE um_write(struct um *machine, int fd, VALUE str, int len) {
|
376
375
|
struct um_op op;
|
377
|
-
um_prep_op(machine, &op, OP_WRITE);
|
376
|
+
um_prep_op(machine, &op, OP_WRITE, 0);
|
378
377
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
379
378
|
const int str_len = RSTRING_LEN(str);
|
380
379
|
if (len > str_len) len = str_len;
|
@@ -390,9 +389,19 @@ VALUE um_write(struct um *machine, int fd, VALUE str, int len) {
|
|
390
389
|
return raise_if_exception(ret);
|
391
390
|
}
|
392
391
|
|
392
|
+
VALUE um_write_async(struct um *machine, int fd, VALUE str) {
|
393
|
+
struct um_op *op = um_op_alloc(machine);
|
394
|
+
um_prep_op(machine, op, OP_WRITE_ASYNC, OP_F_FREE_ON_COMPLETE);
|
395
|
+
RB_OBJ_WRITE(machine->self, &op->value, str);
|
396
|
+
|
397
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
398
|
+
io_uring_prep_write(sqe, fd, RSTRING_PTR(str), RSTRING_LEN(str), -1);
|
399
|
+
return str;
|
400
|
+
}
|
401
|
+
|
393
402
|
VALUE um_close(struct um *machine, int fd) {
|
394
403
|
struct um_op op;
|
395
|
-
um_prep_op(machine, &op, OP_CLOSE);
|
404
|
+
um_prep_op(machine, &op, OP_CLOSE, 0);
|
396
405
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
397
406
|
io_uring_prep_close(sqe, fd);
|
398
407
|
|
@@ -404,9 +413,19 @@ VALUE um_close(struct um *machine, int fd) {
|
|
404
413
|
return raise_if_exception(ret);
|
405
414
|
}
|
406
415
|
|
416
|
+
VALUE um_close_async(struct um *machine, int fd) {
|
417
|
+
struct um_op *op = um_op_alloc(machine);
|
418
|
+
um_prep_op(machine, op, OP_CLOSE_ASYNC, OP_F_FREE_ON_COMPLETE);
|
419
|
+
|
420
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
421
|
+
io_uring_prep_close(sqe, fd);
|
422
|
+
|
423
|
+
return INT2NUM(fd);
|
424
|
+
}
|
425
|
+
|
407
426
|
VALUE um_accept(struct um *machine, int fd) {
|
408
427
|
struct um_op op;
|
409
|
-
um_prep_op(machine, &op, OP_ACCEPT);
|
428
|
+
um_prep_op(machine, &op, OP_ACCEPT, 0);
|
410
429
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
411
430
|
io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
|
412
431
|
|
@@ -420,7 +439,7 @@ VALUE um_accept(struct um *machine, int fd) {
|
|
420
439
|
|
421
440
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags) {
|
422
441
|
struct um_op op;
|
423
|
-
um_prep_op(machine, &op, OP_SOCKET);
|
442
|
+
um_prep_op(machine, &op, OP_SOCKET, 0);
|
424
443
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
425
444
|
io_uring_prep_socket(sqe, domain, type, protocol, flags);
|
426
445
|
|
@@ -434,7 +453,7 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
|
|
434
453
|
|
435
454
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
436
455
|
struct um_op op;
|
437
|
-
um_prep_op(machine, &op, OP_CONNECT);
|
456
|
+
um_prep_op(machine, &op, OP_CONNECT, 0);
|
438
457
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
439
458
|
io_uring_prep_connect(sqe, fd, addr, addrlen);
|
440
459
|
|
@@ -448,7 +467,7 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
|
|
448
467
|
|
449
468
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
450
469
|
struct um_op op;
|
451
|
-
um_prep_op(machine, &op, OP_SEND);
|
470
|
+
um_prep_op(machine, &op, OP_SEND, 0);
|
452
471
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
453
472
|
io_uring_prep_send(sqe, fd, RSTRING_PTR(buffer), len, flags);
|
454
473
|
|
@@ -463,7 +482,7 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
|
463
482
|
|
464
483
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
465
484
|
struct um_op op;
|
466
|
-
um_prep_op(machine, &op, OP_RECV);
|
485
|
+
um_prep_op(machine, &op, OP_RECV, 0);
|
467
486
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
468
487
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
|
469
488
|
io_uring_prep_recv(sqe, fd, ptr, maxlen, flags);
|
@@ -481,7 +500,7 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
|
481
500
|
|
482
501
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen) {
|
483
502
|
struct um_op op;
|
484
|
-
um_prep_op(machine, &op, OP_BIND);
|
503
|
+
um_prep_op(machine, &op, OP_BIND, 0);
|
485
504
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
486
505
|
io_uring_prep_bind(sqe, fd, addr, addrlen);
|
487
506
|
|
@@ -495,7 +514,7 @@ VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrl
|
|
495
514
|
|
496
515
|
VALUE um_listen(struct um *machine, int fd, int backlog) {
|
497
516
|
struct um_op op;
|
498
|
-
um_prep_op(machine, &op, OP_BIND);
|
517
|
+
um_prep_op(machine, &op, OP_BIND, 0);
|
499
518
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
500
519
|
io_uring_prep_listen(sqe, fd, backlog);
|
501
520
|
|
@@ -513,7 +532,7 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
513
532
|
|
514
533
|
#ifdef HAVE_IO_URING_PREP_CMD_SOCK
|
515
534
|
struct um_op op;
|
516
|
-
um_prep_op(machine, &op, OP_GETSOCKOPT);
|
535
|
+
um_prep_op(machine, &op, OP_GETSOCKOPT, 0);
|
517
536
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
518
537
|
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_GETSOCKOPT, fd, level, opt, &value, sizeof(value));
|
519
538
|
|
@@ -537,7 +556,7 @@ VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
537
556
|
|
538
557
|
#ifdef HAVE_IO_URING_PREP_CMD_SOCK
|
539
558
|
struct um_op op;
|
540
|
-
um_prep_op(machine, &op, OP_SETSOCKOPT);
|
559
|
+
um_prep_op(machine, &op, OP_SETSOCKOPT, 0);
|
541
560
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
542
561
|
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_SETSOCKOPT, fd, level, opt, &value, sizeof(value));
|
543
562
|
|
@@ -559,7 +578,7 @@ VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
559
578
|
VALUE ret = Qnil;
|
560
579
|
|
561
580
|
struct um_op op;
|
562
|
-
um_prep_op(machine, &op, OP_SHUTDOWN);
|
581
|
+
um_prep_op(machine, &op, OP_SHUTDOWN, 0);
|
563
582
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
564
583
|
io_uring_prep_shutdown(sqe, fd, how);
|
565
584
|
|
@@ -571,9 +590,19 @@ VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
571
590
|
return raise_if_exception(ret);
|
572
591
|
}
|
573
592
|
|
593
|
+
VALUE um_shutdown_async(struct um *machine, int fd, int how) {
|
594
|
+
struct um_op *op = um_op_alloc(machine);
|
595
|
+
um_prep_op(machine, op, OP_SHUTDOWN_ASYNC, OP_F_FREE_ON_COMPLETE);
|
596
|
+
|
597
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
598
|
+
io_uring_prep_shutdown(sqe, fd, how);
|
599
|
+
|
600
|
+
return INT2NUM(fd);
|
601
|
+
}
|
602
|
+
|
574
603
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
575
604
|
struct um_op op;
|
576
|
-
um_prep_op(machine, &op, OP_OPEN);
|
605
|
+
um_prep_op(machine, &op, OP_OPEN, 0);
|
577
606
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
578
607
|
io_uring_prep_open(sqe, StringValueCStr(pathname), flags, mode);
|
579
608
|
|
@@ -587,7 +616,7 @@ VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
|
587
616
|
|
588
617
|
VALUE um_waitpid(struct um *machine, int pid, int options) {
|
589
618
|
struct um_op op;
|
590
|
-
um_prep_op(machine, &op, OP_WAITPID);
|
619
|
+
um_prep_op(machine, &op, OP_WAITPID, 0);
|
591
620
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
592
621
|
|
593
622
|
siginfo_t infop;
|
@@ -628,7 +657,7 @@ VALUE statx_to_hash(struct statx *stat) {
|
|
628
657
|
|
629
658
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask) {
|
630
659
|
struct um_op op;
|
631
|
-
um_prep_op(machine, &op, OP_STATX);
|
660
|
+
um_prep_op(machine, &op, OP_STATX, 0);
|
632
661
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
633
662
|
|
634
663
|
struct statx stat;
|
@@ -703,7 +732,7 @@ VALUE multishot_complete(VALUE arg) {
|
|
703
732
|
|
704
733
|
VALUE um_accept_each(struct um *machine, int fd) {
|
705
734
|
struct um_op op;
|
706
|
-
um_prep_op(machine, &op, OP_ACCEPT_MULTISHOT);
|
735
|
+
um_prep_op(machine, &op, OP_ACCEPT_MULTISHOT, OP_F_MULTISHOT);
|
707
736
|
|
708
737
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .read_buf = NULL };
|
709
738
|
return rb_ensure(accept_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
@@ -716,7 +745,7 @@ int um_read_each_singleshot_loop(struct op_ctx *ctx) {
|
|
716
745
|
int total = 0;
|
717
746
|
|
718
747
|
while (1) {
|
719
|
-
um_prep_op(ctx->machine, ctx->op, OP_READ);
|
748
|
+
um_prep_op(ctx->machine, ctx->op, OP_READ, 0);
|
720
749
|
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
|
721
750
|
io_uring_prep_read(sqe, ctx->fd, ctx->read_buf, ctx->read_maxlen, -1);
|
722
751
|
|
@@ -806,7 +835,7 @@ VALUE read_recv_each_start(VALUE arg) {
|
|
806
835
|
|
807
836
|
VALUE um_read_each(struct um *machine, int fd, int bgid) {
|
808
837
|
struct um_op op;
|
809
|
-
um_prep_op(machine, &op, OP_READ_MULTISHOT);
|
838
|
+
um_prep_op(machine, &op, OP_READ_MULTISHOT, OP_F_MULTISHOT);
|
810
839
|
|
811
840
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .bgid = bgid, .read_buf = NULL };
|
812
841
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
@@ -814,7 +843,7 @@ VALUE um_read_each(struct um *machine, int fd, int bgid) {
|
|
814
843
|
|
815
844
|
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags) {
|
816
845
|
struct um_op op;
|
817
|
-
um_prep_op(machine, &op, OP_RECV_MULTISHOT);
|
846
|
+
um_prep_op(machine, &op, OP_RECV_MULTISHOT, OP_F_MULTISHOT);
|
818
847
|
|
819
848
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .bgid = bgid, .read_buf = NULL, .flags = flags };
|
820
849
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
@@ -853,7 +882,7 @@ VALUE periodically_start(VALUE arg) {
|
|
853
882
|
|
854
883
|
VALUE um_periodically(struct um *machine, double interval) {
|
855
884
|
struct um_op op;
|
856
|
-
um_prep_op(machine, &op, OP_SLEEP_MULTISHOT);
|
885
|
+
um_prep_op(machine, &op, OP_SLEEP_MULTISHOT, OP_F_MULTISHOT);
|
857
886
|
op.ts = um_double_to_timespec(interval);
|
858
887
|
|
859
888
|
struct op_ctx ctx = { .machine = machine, .op = &op, .ts = op.ts, .read_buf = NULL };
|
data/ext/um/um.h
CHANGED
@@ -28,7 +28,9 @@ enum op_kind {
|
|
28
28
|
OP_OPEN,
|
29
29
|
OP_READ,
|
30
30
|
OP_WRITE,
|
31
|
+
OP_WRITE_ASYNC,
|
31
32
|
OP_CLOSE,
|
33
|
+
OP_CLOSE_ASYNC,
|
32
34
|
OP_STATX,
|
33
35
|
|
34
36
|
OP_ACCEPT,
|
@@ -41,6 +43,7 @@ enum op_kind {
|
|
41
43
|
OP_GETSOCKOPT,
|
42
44
|
OP_SETSOCKOPT,
|
43
45
|
OP_SHUTDOWN,
|
46
|
+
OP_SHUTDOWN_ASYNC,
|
44
47
|
|
45
48
|
OP_WAITPID,
|
46
49
|
|
@@ -59,6 +62,7 @@ enum op_kind {
|
|
59
62
|
#define OP_F_ASYNC (1U << 2) // op belongs to an AsyncOp
|
60
63
|
#define OP_F_IGNORE_CANCELED (1U << 3) // CQE with -ECANCEL should be ignored
|
61
64
|
#define OP_F_MULTISHOT (1U << 4) // op is multishot
|
65
|
+
#define OP_F_FREE_ON_COMPLETE (1U << 5) // op should be freed on receiving CQE
|
62
66
|
|
63
67
|
struct um_op_result {
|
64
68
|
__s32 res;
|
@@ -200,7 +204,7 @@ VALUE um_raise_exception(VALUE v);
|
|
200
204
|
|
201
205
|
#define raise_if_exception(v) (um_value_is_exception_p(v) ? um_raise_exception(v) : v)
|
202
206
|
|
203
|
-
void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind);
|
207
|
+
void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind, unsigned flags);
|
204
208
|
void um_raise_on_error_result(int result);
|
205
209
|
void * um_prepare_read_buffer(VALUE buffer, unsigned len, int ofs);
|
206
210
|
void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, __s32 result, __u32 flags);
|
@@ -227,9 +231,11 @@ size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen);
|
|
227
231
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
228
232
|
VALUE um_write(struct um *machine, int fd, VALUE str, int len);
|
229
233
|
VALUE um_close(struct um *machine, int fd);
|
234
|
+
VALUE um_close_async(struct um *machine, int fd);
|
230
235
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode);
|
231
236
|
VALUE um_waitpid(struct um *machine, int pid, int options);
|
232
237
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask);
|
238
|
+
VALUE um_write_async(struct um *machine, int fd, VALUE str);
|
233
239
|
|
234
240
|
VALUE um_accept(struct um *machine, int fd);
|
235
241
|
VALUE um_accept_each(struct um *machine, int fd);
|
@@ -243,6 +249,7 @@ VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
243
249
|
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
|
244
250
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
|
245
251
|
VALUE um_shutdown(struct um *machine, int fd, int how);
|
252
|
+
VALUE um_shutdown_async(struct um *machine, int fd, int how);
|
246
253
|
|
247
254
|
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
|
248
255
|
VALUE um_async_op_await(struct um_async_op *async_op);
|
data/ext/um/um_async_op.c
CHANGED
@@ -6,9 +6,8 @@ VALUE um_prep_timeout(struct um *machine, double interval) {
|
|
6
6
|
if (!ID_new) ID_new = rb_intern("new");
|
7
7
|
|
8
8
|
struct um_op *op = malloc(sizeof(struct um_op));
|
9
|
-
um_prep_op(machine, op, OP_TIMEOUT);
|
9
|
+
um_prep_op(machine, op, OP_TIMEOUT, OP_F_TRANSIENT | OP_F_ASYNC);
|
10
10
|
op->ts = um_double_to_timespec(interval);
|
11
|
-
op->flags = OP_F_TRANSIENT | OP_F_ASYNC;
|
12
11
|
|
13
12
|
VALUE obj = rb_funcall(cAsyncOp, rb_intern_const("new"), 0);
|
14
13
|
um_async_op_set(obj, machine, op);
|
data/ext/um/um_class.c
CHANGED
@@ -131,6 +131,11 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
131
131
|
return um_write(machine, NUM2INT(fd), buffer, bytes);
|
132
132
|
}
|
133
133
|
|
134
|
+
VALUE UM_write_async(VALUE self, VALUE fd, VALUE str) {
|
135
|
+
struct um *machine = um_get_machine(self);
|
136
|
+
return um_write_async(machine, NUM2INT(fd), str);
|
137
|
+
}
|
138
|
+
|
134
139
|
VALUE UM_statx(VALUE self, VALUE dirfd, VALUE path, VALUE flags, VALUE mask) {
|
135
140
|
struct um *machine = um_get_machine(self);
|
136
141
|
return um_statx(machine, NUM2INT(dirfd), path, NUM2INT(flags), NUM2UINT(mask));
|
@@ -141,6 +146,11 @@ VALUE UM_close(VALUE self, VALUE fd) {
|
|
141
146
|
return um_close(machine, NUM2INT(fd));
|
142
147
|
}
|
143
148
|
|
149
|
+
VALUE UM_close_async(VALUE self, VALUE fd) {
|
150
|
+
struct um *machine = um_get_machine(self);
|
151
|
+
return um_close_async(machine, NUM2INT(fd));
|
152
|
+
}
|
153
|
+
|
144
154
|
VALUE UM_accept(VALUE self, VALUE fd) {
|
145
155
|
struct um *machine = um_get_machine(self);
|
146
156
|
return um_accept(machine, NUM2INT(fd));
|
@@ -159,7 +169,11 @@ VALUE UM_socket(VALUE self, VALUE domain, VALUE type, VALUE protocol, VALUE flag
|
|
159
169
|
VALUE UM_shutdown(VALUE self, VALUE fd, VALUE how) {
|
160
170
|
struct um *machine = um_get_machine(self);
|
161
171
|
return um_shutdown(machine, NUM2INT(fd), NUM2INT(how));
|
172
|
+
}
|
162
173
|
|
174
|
+
VALUE UM_shutdown_async(VALUE self, VALUE fd, VALUE how) {
|
175
|
+
struct um *machine = um_get_machine(self);
|
176
|
+
return um_shutdown_async(machine, NUM2INT(fd), NUM2INT(how));
|
163
177
|
}
|
164
178
|
|
165
179
|
VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
|
@@ -342,12 +356,14 @@ void Init_UM(void) {
|
|
342
356
|
rb_define_method(cUM, "yield", UM_yield, 0);
|
343
357
|
|
344
358
|
rb_define_method(cUM, "close", UM_close, 1);
|
359
|
+
rb_define_method(cUM, "close_async", UM_close_async, 1);
|
345
360
|
rb_define_method(cUM, "open", UM_open, 2);
|
346
361
|
rb_define_method(cUM, "read", UM_read, -1);
|
347
362
|
rb_define_method(cUM, "read_each", UM_read_each, 2);
|
348
363
|
rb_define_method(cUM, "sleep", UM_sleep, 1);
|
349
364
|
rb_define_method(cUM, "periodically", UM_periodically, 1);
|
350
365
|
rb_define_method(cUM, "write", UM_write, -1);
|
366
|
+
rb_define_method(cUM, "write_async", UM_write_async, 2);
|
351
367
|
rb_define_method(cUM, "statx", UM_statx, 4);
|
352
368
|
|
353
369
|
rb_define_method(cUM, "waitpid", UM_waitpid, 2);
|
@@ -364,6 +380,7 @@ void Init_UM(void) {
|
|
364
380
|
rb_define_method(cUM, "setsockopt", UM_setsockopt, 4);
|
365
381
|
rb_define_method(cUM, "socket", UM_socket, 4);
|
366
382
|
rb_define_method(cUM, "shutdown", UM_shutdown, 2);
|
383
|
+
rb_define_method(cUM, "shutdown_async", UM_shutdown_async, 2);
|
367
384
|
|
368
385
|
rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
|
369
386
|
|
data/ext/um/um_sync.c
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t expect) {
|
8
8
|
struct um_op op;
|
9
|
-
um_prep_op(machine, &op, OP_FUTEX_WAIT);
|
9
|
+
um_prep_op(machine, &op, OP_FUTEX_WAIT, 0);
|
10
10
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
11
11
|
io_uring_prep_futex_wait(
|
12
12
|
sqe, (uint32_t *)futex, expect, FUTEX_BITSET_MATCH_ANY,
|
@@ -27,7 +27,7 @@ void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t expect) {
|
|
27
27
|
|
28
28
|
void um_futex_wake(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
29
29
|
struct um_op op;
|
30
|
-
um_prep_op(machine, &op, OP_FUTEX_WAKE);
|
30
|
+
um_prep_op(machine, &op, OP_FUTEX_WAKE, 0);
|
31
31
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
32
32
|
// submit futex_wait
|
33
33
|
io_uring_prep_futex_wake(
|
data/lib/uringmachine/version.rb
CHANGED
data/lib/uringmachine.rb
CHANGED
@@ -35,14 +35,15 @@ class UringMachine
|
|
35
35
|
f.add_done_listener(queue)
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
if pending
|
39
|
+
while !pending.empty?
|
40
|
+
f = self.shift(queue)
|
41
|
+
pending.delete(f)
|
42
|
+
results[f] = f.result
|
43
|
+
end
|
44
44
|
end
|
45
|
-
results.values
|
45
|
+
values = results.values
|
46
|
+
fibers.size == 1 ? values.first : values
|
46
47
|
end
|
47
48
|
|
48
49
|
def resolve(hostname, type = :A)
|
data/test/helper.rb
CHANGED
@@ -74,4 +74,20 @@ class UMBaseTest < Minitest::Test
|
|
74
74
|
@@port += 1
|
75
75
|
end
|
76
76
|
end
|
77
|
+
|
78
|
+
def make_socket_pair
|
79
|
+
port = 10000 + rand(30000)
|
80
|
+
server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
81
|
+
@machine.setsockopt(server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
|
82
|
+
@machine.bind(server_fd, '127.0.0.1', port)
|
83
|
+
@machine.listen(server_fd, UM::SOMAXCONN)
|
84
|
+
|
85
|
+
client_conn_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
86
|
+
@machine.connect(client_conn_fd, '127.0.0.1', port)
|
87
|
+
|
88
|
+
server_conn_fd = @machine.accept(server_fd)
|
89
|
+
|
90
|
+
@machine.close(server_fd)
|
91
|
+
[client_conn_fd, server_conn_fd]
|
92
|
+
end
|
77
93
|
end
|
data/test/test_fiber.rb
CHANGED
@@ -88,7 +88,7 @@ class FiberJoinTest < UMBaseTest
|
|
88
88
|
res = machine.join(f)
|
89
89
|
assert_equal 0, x
|
90
90
|
assert_equal 3, machine.shift(q)
|
91
|
-
assert_equal
|
91
|
+
assert_equal 42, res
|
92
92
|
end
|
93
93
|
|
94
94
|
def test_join_multiple
|
@@ -125,7 +125,7 @@ class FiberJoinTest < UMBaseTest
|
|
125
125
|
f = machine.shift(q)
|
126
126
|
assert_kind_of Fiber, f
|
127
127
|
res = machine.join(f)
|
128
|
-
assert_equal
|
128
|
+
assert_equal :foo, res
|
129
129
|
ensure
|
130
130
|
t2.join
|
131
131
|
end
|
@@ -135,8 +135,7 @@ class FiberJoinTest < UMBaseTest
|
|
135
135
|
raise "Foobar"
|
136
136
|
end
|
137
137
|
|
138
|
-
|
139
|
-
e = res.first
|
138
|
+
e = machine.join(f)
|
140
139
|
assert_kind_of RuntimeError, e
|
141
140
|
assert_equal 'Foobar', e.message
|
142
141
|
end
|
data/test/test_um.rb
CHANGED
@@ -25,6 +25,12 @@ class SpinTest < UMBaseTest
|
|
25
25
|
|
26
26
|
assert_equal :foo, x
|
27
27
|
end
|
28
|
+
|
29
|
+
def test_spin_with_unhandled_exception
|
30
|
+
f = machine.spin { raise 'foo' }
|
31
|
+
result = machine.join(f)
|
32
|
+
assert_kind_of RuntimeError, result
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
class SnoozeTest < UMBaseTest
|
@@ -271,7 +277,7 @@ class PeriodicallyTest < UMBaseTest
|
|
271
277
|
rescue Cancel
|
272
278
|
cancel = 1
|
273
279
|
end
|
274
|
-
|
280
|
+
5.times { machine.snooze }
|
275
281
|
assert_equal 0, machine.pending_count
|
276
282
|
t1 = monotonic_clock
|
277
283
|
assert_in_range 0.05..0.08, t1 - t0
|
@@ -532,6 +538,30 @@ class WriteTest < UMBaseTest
|
|
532
538
|
end
|
533
539
|
end
|
534
540
|
|
541
|
+
class WriteAsyncTest < UMBaseTest
|
542
|
+
def test_write_async
|
543
|
+
r, w = IO.pipe
|
544
|
+
|
545
|
+
assert_equal 0, machine.pending_count
|
546
|
+
machine.write_async(w.fileno, 'foo')
|
547
|
+
assert_equal 1, machine.pending_count
|
548
|
+
|
549
|
+
machine.snooze
|
550
|
+
assert_equal 0, machine.pending_count
|
551
|
+
assert_equal 'foo', r.readpartial(3)
|
552
|
+
end
|
553
|
+
|
554
|
+
def test_write_async_bad_fd
|
555
|
+
r, _w = IO.pipe
|
556
|
+
|
557
|
+
assert_equal 0, machine.pending_count
|
558
|
+
machine.write_async(r.fileno, 'foo')
|
559
|
+
assert_equal 1, machine.pending_count
|
560
|
+
machine.snooze
|
561
|
+
assert_equal 0, machine.pending_count
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
535
565
|
class CloseTest < UMBaseTest
|
536
566
|
def test_close
|
537
567
|
r, w = IO.pipe
|
@@ -545,25 +575,31 @@ class CloseTest < UMBaseTest
|
|
545
575
|
|
546
576
|
assert_raises(Errno::EBADF) { machine.close(w.fileno) }
|
547
577
|
end
|
548
|
-
end
|
549
|
-
|
550
|
-
class ShutdownTest < UMBaseTest
|
551
|
-
def make_socket_pair
|
552
|
-
port = 10000 + rand(30000)
|
553
|
-
server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
554
|
-
@machine.setsockopt(server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
|
555
|
-
@machine.bind(server_fd, '127.0.0.1', port)
|
556
|
-
@machine.listen(server_fd, UM::SOMAXCONN)
|
557
578
|
|
558
|
-
|
559
|
-
|
579
|
+
def test_close_bad_fd
|
580
|
+
r, w = IO.pipe
|
581
|
+
machine.close(w.fileno)
|
582
|
+
|
583
|
+
assert_raises(Errno::EBADF) { machine.close(w.fileno) }
|
584
|
+
end
|
585
|
+
end
|
560
586
|
|
561
|
-
|
587
|
+
class CloseAsyncTest < UMBaseTest
|
588
|
+
def test_close_async
|
589
|
+
r, w = IO.pipe
|
590
|
+
machine.write(w.fileno, 'foo')
|
591
|
+
assert_equal 'foo', r.readpartial(3)
|
562
592
|
|
563
|
-
|
564
|
-
|
593
|
+
assert_equal 0, machine.pending_count
|
594
|
+
machine.close_async(w.fileno)
|
595
|
+
assert_equal 1, machine.pending_count
|
596
|
+
machine.snooze
|
597
|
+
assert_equal 0, machine.pending_count
|
598
|
+
assert_equal '', r.read
|
565
599
|
end
|
600
|
+
end
|
566
601
|
|
602
|
+
class ShutdownTest < UMBaseTest
|
567
603
|
def test_shutdown
|
568
604
|
c_fd, s_fd = make_socket_pair
|
569
605
|
res = @machine.send(c_fd, 'abc', 3, 0)
|
@@ -595,6 +631,37 @@ class ShutdownTest < UMBaseTest
|
|
595
631
|
end
|
596
632
|
end
|
597
633
|
|
634
|
+
class ShutdownAsyncTest < UMBaseTest
|
635
|
+
def test_shutdown_async
|
636
|
+
c_fd, s_fd = make_socket_pair
|
637
|
+
res = @machine.send(c_fd, 'abc', 3, 0)
|
638
|
+
assert_equal 3, res
|
639
|
+
|
640
|
+
buf = +''
|
641
|
+
res = @machine.recv(s_fd, buf, 256, 0)
|
642
|
+
assert_equal 3, res
|
643
|
+
assert_equal 'abc', buf
|
644
|
+
|
645
|
+
res = @machine.shutdown_async(c_fd, UM::SHUT_WR)
|
646
|
+
assert_equal c_fd, res
|
647
|
+
|
648
|
+
machine.sleep(0.01)
|
649
|
+
assert_raises(Errno::EPIPE) { @machine.send(c_fd, 'abc', 3, 0) }
|
650
|
+
|
651
|
+
res = @machine.shutdown_async(s_fd, UM::SHUT_RD)
|
652
|
+
assert_equal s_fd, res
|
653
|
+
|
654
|
+
res = @machine.recv(s_fd, buf, 256, 0)
|
655
|
+
assert_equal 0, res
|
656
|
+
|
657
|
+
res = @machine.shutdown_async(c_fd, UM::SHUT_RDWR)
|
658
|
+
assert_equal c_fd, res
|
659
|
+
ensure
|
660
|
+
@machine.close(c_fd)
|
661
|
+
@machine.close(s_fd)
|
662
|
+
end
|
663
|
+
end
|
664
|
+
|
598
665
|
class AcceptTest < UMBaseTest
|
599
666
|
def setup
|
600
667
|
super
|