uringmachine 0.13 → 0.15
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 +56 -41
- data/ext/um/um.h +5 -1
- data/ext/um/um_async_op.c +1 -2
- data/ext/um/um_class.c +12 -1
- 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 +73 -16
- 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: 1b3778bbf3b35b2f0855c5fdbe441df909a43866c56ceed16cacf502956566ba
|
4
|
+
data.tar.gz: 82b580cb610c11d5d05e69ab868ba70265fec92851cbdca7cf340bbde09c0b2c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82fbdc455e76bd1adaf4668ae0d43c8c1e84f9c168c1d3e2f7a4924e672d5b77617ce720ac6fcb9257cc8e8edcf419f4267acdd7128d72a5d03c0b808f85ab4b
|
7
|
+
data.tar.gz: d56ba947a2d6ba974faa7e0594b506e0f7520815a995e263a7a9acf0658b73c057bd7d13f32e035376a4871dea6ff7824d04a621957707cb56a6f7e92581af1d
|
data/CHANGELOG.md
CHANGED
data/ext/um/um.c
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#include <float.h>
|
1
2
|
#include "um.h"
|
2
3
|
#include "ruby/thread.h"
|
3
4
|
|
@@ -252,20 +253,14 @@ inline VALUE um_await(struct um *machine) {
|
|
252
253
|
return raise_if_exception(v);
|
253
254
|
}
|
254
255
|
|
255
|
-
inline void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind) {
|
256
|
+
inline void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind, unsigned flags) {
|
256
257
|
memset(op, 0, sizeof(struct um_op));
|
257
258
|
op->kind = kind;
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
case OP_SLEEP_MULTISHOT:
|
264
|
-
op->flags |= OP_F_MULTISHOT;
|
265
|
-
default:
|
266
|
-
}
|
267
|
-
RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
|
268
|
-
op->value = Qnil;
|
259
|
+
op->flags = flags;
|
260
|
+
|
261
|
+
VALUE fiber = (flags & OP_F_FREE_ON_COMPLETE) ? Qnil : rb_fiber_current();
|
262
|
+
RB_OBJ_WRITE(machine->self, &op->fiber, fiber);
|
263
|
+
RB_OBJ_WRITE(machine->self, &op->value, Qnil);
|
269
264
|
}
|
270
265
|
|
271
266
|
inline void um_schedule(struct um *machine, VALUE fiber, VALUE value) {
|
@@ -307,7 +302,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
307
302
|
if (!ID_new) ID_new = rb_intern("new");
|
308
303
|
|
309
304
|
struct um_op *op = um_op_alloc(machine);
|
310
|
-
um_prep_op(machine, op, OP_TIMEOUT);
|
305
|
+
um_prep_op(machine, op, OP_TIMEOUT, 0);
|
311
306
|
op->ts = um_double_to_timespec(NUM2DBL(interval));
|
312
307
|
RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
|
313
308
|
RB_OBJ_WRITE(machine->self, &op->value, rb_funcall(class, ID_new, 0));
|
@@ -323,9 +318,13 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
|
|
323
318
|
blocking singleshot ops
|
324
319
|
*******************************************************************************/
|
325
320
|
|
321
|
+
#define SLEEP_FOREVER_DURATION (86400*10000)
|
322
|
+
|
326
323
|
VALUE um_sleep(struct um *machine, double duration) {
|
324
|
+
if (duration <= 0) duration = SLEEP_FOREVER_DURATION;
|
325
|
+
|
327
326
|
struct um_op op;
|
328
|
-
um_prep_op(machine, &op, OP_SLEEP);
|
327
|
+
um_prep_op(machine, &op, OP_SLEEP, 0);
|
329
328
|
op.ts = um_double_to_timespec(duration);
|
330
329
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
331
330
|
io_uring_prep_timeout(sqe, &op.ts, 0, 0);
|
@@ -344,7 +343,7 @@ VALUE um_sleep(struct um *machine, double duration) {
|
|
344
343
|
|
345
344
|
inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset) {
|
346
345
|
struct um_op op;
|
347
|
-
um_prep_op(machine, &op, OP_READ);
|
346
|
+
um_prep_op(machine, &op, OP_READ, 0);
|
348
347
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
349
348
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, buffer_offset);
|
350
349
|
io_uring_prep_read(sqe, fd, ptr, maxlen, -1);
|
@@ -363,7 +362,7 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
|
|
363
362
|
|
364
363
|
inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen) {
|
365
364
|
struct um_op op;
|
366
|
-
um_prep_op(machine, &op, OP_READ);
|
365
|
+
um_prep_op(machine, &op, OP_READ, 0);
|
367
366
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
368
367
|
io_uring_prep_read(sqe, fd, buffer, maxlen, -1);
|
369
368
|
|
@@ -379,7 +378,7 @@ inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen)
|
|
379
378
|
|
380
379
|
VALUE um_write(struct um *machine, int fd, VALUE str, int len) {
|
381
380
|
struct um_op op;
|
382
|
-
um_prep_op(machine, &op, OP_WRITE);
|
381
|
+
um_prep_op(machine, &op, OP_WRITE, 0);
|
383
382
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
384
383
|
const int str_len = RSTRING_LEN(str);
|
385
384
|
if (len > str_len) len = str_len;
|
@@ -397,10 +396,7 @@ VALUE um_write(struct um *machine, int fd, VALUE str, int len) {
|
|
397
396
|
|
398
397
|
VALUE um_write_async(struct um *machine, int fd, VALUE str) {
|
399
398
|
struct um_op *op = um_op_alloc(machine);
|
400
|
-
|
401
|
-
op->kind = OP_WRITE_ASYNC;
|
402
|
-
op->flags = OP_F_FREE_ON_COMPLETE;
|
403
|
-
op->fiber = Qnil;
|
399
|
+
um_prep_op(machine, op, OP_WRITE_ASYNC, OP_F_FREE_ON_COMPLETE);
|
404
400
|
RB_OBJ_WRITE(machine->self, &op->value, str);
|
405
401
|
|
406
402
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
@@ -410,7 +406,7 @@ VALUE um_write_async(struct um *machine, int fd, VALUE str) {
|
|
410
406
|
|
411
407
|
VALUE um_close(struct um *machine, int fd) {
|
412
408
|
struct um_op op;
|
413
|
-
um_prep_op(machine, &op, OP_CLOSE);
|
409
|
+
um_prep_op(machine, &op, OP_CLOSE, 0);
|
414
410
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
415
411
|
io_uring_prep_close(sqe, fd);
|
416
412
|
|
@@ -422,9 +418,19 @@ VALUE um_close(struct um *machine, int fd) {
|
|
422
418
|
return raise_if_exception(ret);
|
423
419
|
}
|
424
420
|
|
421
|
+
VALUE um_close_async(struct um *machine, int fd) {
|
422
|
+
struct um_op *op = um_op_alloc(machine);
|
423
|
+
um_prep_op(machine, op, OP_CLOSE_ASYNC, OP_F_FREE_ON_COMPLETE);
|
424
|
+
|
425
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
426
|
+
io_uring_prep_close(sqe, fd);
|
427
|
+
|
428
|
+
return INT2NUM(fd);
|
429
|
+
}
|
430
|
+
|
425
431
|
VALUE um_accept(struct um *machine, int fd) {
|
426
432
|
struct um_op op;
|
427
|
-
um_prep_op(machine, &op, OP_ACCEPT);
|
433
|
+
um_prep_op(machine, &op, OP_ACCEPT, 0);
|
428
434
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
429
435
|
io_uring_prep_accept(sqe, fd, NULL, NULL, 0);
|
430
436
|
|
@@ -438,7 +444,7 @@ VALUE um_accept(struct um *machine, int fd) {
|
|
438
444
|
|
439
445
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags) {
|
440
446
|
struct um_op op;
|
441
|
-
um_prep_op(machine, &op, OP_SOCKET);
|
447
|
+
um_prep_op(machine, &op, OP_SOCKET, 0);
|
442
448
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
443
449
|
io_uring_prep_socket(sqe, domain, type, protocol, flags);
|
444
450
|
|
@@ -452,7 +458,7 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
|
|
452
458
|
|
453
459
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
454
460
|
struct um_op op;
|
455
|
-
um_prep_op(machine, &op, OP_CONNECT);
|
461
|
+
um_prep_op(machine, &op, OP_CONNECT, 0);
|
456
462
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
457
463
|
io_uring_prep_connect(sqe, fd, addr, addrlen);
|
458
464
|
|
@@ -466,7 +472,7 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
|
|
466
472
|
|
467
473
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
468
474
|
struct um_op op;
|
469
|
-
um_prep_op(machine, &op, OP_SEND);
|
475
|
+
um_prep_op(machine, &op, OP_SEND, 0);
|
470
476
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
471
477
|
io_uring_prep_send(sqe, fd, RSTRING_PTR(buffer), len, flags);
|
472
478
|
|
@@ -481,7 +487,7 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
|
481
487
|
|
482
488
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
483
489
|
struct um_op op;
|
484
|
-
um_prep_op(machine, &op, OP_RECV);
|
490
|
+
um_prep_op(machine, &op, OP_RECV, 0);
|
485
491
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
486
492
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
|
487
493
|
io_uring_prep_recv(sqe, fd, ptr, maxlen, flags);
|
@@ -499,7 +505,7 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
|
499
505
|
|
500
506
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen) {
|
501
507
|
struct um_op op;
|
502
|
-
um_prep_op(machine, &op, OP_BIND);
|
508
|
+
um_prep_op(machine, &op, OP_BIND, 0);
|
503
509
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
504
510
|
io_uring_prep_bind(sqe, fd, addr, addrlen);
|
505
511
|
|
@@ -513,7 +519,7 @@ VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrl
|
|
513
519
|
|
514
520
|
VALUE um_listen(struct um *machine, int fd, int backlog) {
|
515
521
|
struct um_op op;
|
516
|
-
um_prep_op(machine, &op, OP_BIND);
|
522
|
+
um_prep_op(machine, &op, OP_BIND, 0);
|
517
523
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
518
524
|
io_uring_prep_listen(sqe, fd, backlog);
|
519
525
|
|
@@ -531,7 +537,7 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
531
537
|
|
532
538
|
#ifdef HAVE_IO_URING_PREP_CMD_SOCK
|
533
539
|
struct um_op op;
|
534
|
-
um_prep_op(machine, &op, OP_GETSOCKOPT);
|
540
|
+
um_prep_op(machine, &op, OP_GETSOCKOPT, 0);
|
535
541
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
536
542
|
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_GETSOCKOPT, fd, level, opt, &value, sizeof(value));
|
537
543
|
|
@@ -555,7 +561,7 @@ VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
555
561
|
|
556
562
|
#ifdef HAVE_IO_URING_PREP_CMD_SOCK
|
557
563
|
struct um_op op;
|
558
|
-
um_prep_op(machine, &op, OP_SETSOCKOPT);
|
564
|
+
um_prep_op(machine, &op, OP_SETSOCKOPT, 0);
|
559
565
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
560
566
|
io_uring_prep_cmd_sock(sqe, SOCKET_URING_OP_SETSOCKOPT, fd, level, opt, &value, sizeof(value));
|
561
567
|
|
@@ -577,7 +583,7 @@ VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
577
583
|
VALUE ret = Qnil;
|
578
584
|
|
579
585
|
struct um_op op;
|
580
|
-
um_prep_op(machine, &op, OP_SHUTDOWN);
|
586
|
+
um_prep_op(machine, &op, OP_SHUTDOWN, 0);
|
581
587
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
582
588
|
io_uring_prep_shutdown(sqe, fd, how);
|
583
589
|
|
@@ -589,9 +595,19 @@ VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
589
595
|
return raise_if_exception(ret);
|
590
596
|
}
|
591
597
|
|
598
|
+
VALUE um_shutdown_async(struct um *machine, int fd, int how) {
|
599
|
+
struct um_op *op = um_op_alloc(machine);
|
600
|
+
um_prep_op(machine, op, OP_SHUTDOWN_ASYNC, OP_F_FREE_ON_COMPLETE);
|
601
|
+
|
602
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
603
|
+
io_uring_prep_shutdown(sqe, fd, how);
|
604
|
+
|
605
|
+
return INT2NUM(fd);
|
606
|
+
}
|
607
|
+
|
592
608
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
593
609
|
struct um_op op;
|
594
|
-
um_prep_op(machine, &op, OP_OPEN);
|
610
|
+
um_prep_op(machine, &op, OP_OPEN, 0);
|
595
611
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
596
612
|
io_uring_prep_open(sqe, StringValueCStr(pathname), flags, mode);
|
597
613
|
|
@@ -605,7 +621,7 @@ VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
|
605
621
|
|
606
622
|
VALUE um_waitpid(struct um *machine, int pid, int options) {
|
607
623
|
struct um_op op;
|
608
|
-
um_prep_op(machine, &op, OP_WAITPID);
|
624
|
+
um_prep_op(machine, &op, OP_WAITPID, 0);
|
609
625
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
610
626
|
|
611
627
|
siginfo_t infop;
|
@@ -646,7 +662,7 @@ VALUE statx_to_hash(struct statx *stat) {
|
|
646
662
|
|
647
663
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask) {
|
648
664
|
struct um_op op;
|
649
|
-
um_prep_op(machine, &op, OP_STATX);
|
665
|
+
um_prep_op(machine, &op, OP_STATX, 0);
|
650
666
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
651
667
|
|
652
668
|
struct statx stat;
|
@@ -721,7 +737,7 @@ VALUE multishot_complete(VALUE arg) {
|
|
721
737
|
|
722
738
|
VALUE um_accept_each(struct um *machine, int fd) {
|
723
739
|
struct um_op op;
|
724
|
-
um_prep_op(machine, &op, OP_ACCEPT_MULTISHOT);
|
740
|
+
um_prep_op(machine, &op, OP_ACCEPT_MULTISHOT, OP_F_MULTISHOT);
|
725
741
|
|
726
742
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .read_buf = NULL };
|
727
743
|
return rb_ensure(accept_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
@@ -734,7 +750,7 @@ int um_read_each_singleshot_loop(struct op_ctx *ctx) {
|
|
734
750
|
int total = 0;
|
735
751
|
|
736
752
|
while (1) {
|
737
|
-
um_prep_op(ctx->machine, ctx->op, OP_READ);
|
753
|
+
um_prep_op(ctx->machine, ctx->op, OP_READ, 0);
|
738
754
|
struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
|
739
755
|
io_uring_prep_read(sqe, ctx->fd, ctx->read_buf, ctx->read_maxlen, -1);
|
740
756
|
|
@@ -824,7 +840,7 @@ VALUE read_recv_each_start(VALUE arg) {
|
|
824
840
|
|
825
841
|
VALUE um_read_each(struct um *machine, int fd, int bgid) {
|
826
842
|
struct um_op op;
|
827
|
-
um_prep_op(machine, &op, OP_READ_MULTISHOT);
|
843
|
+
um_prep_op(machine, &op, OP_READ_MULTISHOT, OP_F_MULTISHOT);
|
828
844
|
|
829
845
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .bgid = bgid, .read_buf = NULL };
|
830
846
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
@@ -832,7 +848,7 @@ VALUE um_read_each(struct um *machine, int fd, int bgid) {
|
|
832
848
|
|
833
849
|
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags) {
|
834
850
|
struct um_op op;
|
835
|
-
um_prep_op(machine, &op, OP_RECV_MULTISHOT);
|
851
|
+
um_prep_op(machine, &op, OP_RECV_MULTISHOT, OP_F_MULTISHOT);
|
836
852
|
|
837
853
|
struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .bgid = bgid, .read_buf = NULL, .flags = flags };
|
838
854
|
return rb_ensure(read_recv_each_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
@@ -871,10 +887,9 @@ VALUE periodically_start(VALUE arg) {
|
|
871
887
|
|
872
888
|
VALUE um_periodically(struct um *machine, double interval) {
|
873
889
|
struct um_op op;
|
874
|
-
um_prep_op(machine, &op, OP_SLEEP_MULTISHOT);
|
890
|
+
um_prep_op(machine, &op, OP_SLEEP_MULTISHOT, OP_F_MULTISHOT);
|
875
891
|
op.ts = um_double_to_timespec(interval);
|
876
892
|
|
877
893
|
struct op_ctx ctx = { .machine = machine, .op = &op, .ts = op.ts, .read_buf = NULL };
|
878
894
|
return rb_ensure(periodically_start, (VALUE)&ctx, multishot_complete, (VALUE)&ctx);
|
879
895
|
}
|
880
|
-
|
data/ext/um/um.h
CHANGED
@@ -30,6 +30,7 @@ enum op_kind {
|
|
30
30
|
OP_WRITE,
|
31
31
|
OP_WRITE_ASYNC,
|
32
32
|
OP_CLOSE,
|
33
|
+
OP_CLOSE_ASYNC,
|
33
34
|
OP_STATX,
|
34
35
|
|
35
36
|
OP_ACCEPT,
|
@@ -42,6 +43,7 @@ enum op_kind {
|
|
42
43
|
OP_GETSOCKOPT,
|
43
44
|
OP_SETSOCKOPT,
|
44
45
|
OP_SHUTDOWN,
|
46
|
+
OP_SHUTDOWN_ASYNC,
|
45
47
|
|
46
48
|
OP_WAITPID,
|
47
49
|
|
@@ -202,7 +204,7 @@ VALUE um_raise_exception(VALUE v);
|
|
202
204
|
|
203
205
|
#define raise_if_exception(v) (um_value_is_exception_p(v) ? um_raise_exception(v) : v)
|
204
206
|
|
205
|
-
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);
|
206
208
|
void um_raise_on_error_result(int result);
|
207
209
|
void * um_prepare_read_buffer(VALUE buffer, unsigned len, int ofs);
|
208
210
|
void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, __s32 result, __u32 flags);
|
@@ -229,6 +231,7 @@ size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen);
|
|
229
231
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
230
232
|
VALUE um_write(struct um *machine, int fd, VALUE str, int len);
|
231
233
|
VALUE um_close(struct um *machine, int fd);
|
234
|
+
VALUE um_close_async(struct um *machine, int fd);
|
232
235
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode);
|
233
236
|
VALUE um_waitpid(struct um *machine, int pid, int options);
|
234
237
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask);
|
@@ -246,6 +249,7 @@ VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
246
249
|
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
|
247
250
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
|
248
251
|
VALUE um_shutdown(struct um *machine, int fd, int how);
|
252
|
+
VALUE um_shutdown_async(struct um *machine, int fd, int how);
|
249
253
|
|
250
254
|
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
|
251
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
@@ -44,7 +44,7 @@ inline struct um *um_get_machine(VALUE self) {
|
|
44
44
|
struct um *um;
|
45
45
|
TypedData_Get_Struct(self, struct um, &UringMachine_type, um);
|
46
46
|
if (!um->ring_initialized) rb_raise(rb_eRuntimeError, "Machine not initialized");
|
47
|
-
|
47
|
+
|
48
48
|
return um;
|
49
49
|
}
|
50
50
|
|
@@ -146,6 +146,11 @@ VALUE UM_close(VALUE self, VALUE fd) {
|
|
146
146
|
return um_close(machine, NUM2INT(fd));
|
147
147
|
}
|
148
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
|
+
|
149
154
|
VALUE UM_accept(VALUE self, VALUE fd) {
|
150
155
|
struct um *machine = um_get_machine(self);
|
151
156
|
return um_accept(machine, NUM2INT(fd));
|
@@ -164,7 +169,11 @@ VALUE UM_socket(VALUE self, VALUE domain, VALUE type, VALUE protocol, VALUE flag
|
|
164
169
|
VALUE UM_shutdown(VALUE self, VALUE fd, VALUE how) {
|
165
170
|
struct um *machine = um_get_machine(self);
|
166
171
|
return um_shutdown(machine, NUM2INT(fd), NUM2INT(how));
|
172
|
+
}
|
167
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));
|
168
177
|
}
|
169
178
|
|
170
179
|
VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
|
@@ -347,6 +356,7 @@ void Init_UM(void) {
|
|
347
356
|
rb_define_method(cUM, "yield", UM_yield, 0);
|
348
357
|
|
349
358
|
rb_define_method(cUM, "close", UM_close, 1);
|
359
|
+
rb_define_method(cUM, "close_async", UM_close_async, 1);
|
350
360
|
rb_define_method(cUM, "open", UM_open, 2);
|
351
361
|
rb_define_method(cUM, "read", UM_read, -1);
|
352
362
|
rb_define_method(cUM, "read_each", UM_read_each, 2);
|
@@ -370,6 +380,7 @@ void Init_UM(void) {
|
|
370
380
|
rb_define_method(cUM, "setsockopt", UM_setsockopt, 4);
|
371
381
|
rb_define_method(cUM, "socket", UM_socket, 4);
|
372
382
|
rb_define_method(cUM, "shutdown", UM_shutdown, 2);
|
383
|
+
rb_define_method(cUM, "shutdown_async", UM_shutdown_async, 2);
|
373
384
|
|
374
385
|
rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
|
375
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
|
@@ -228,6 +234,20 @@ class SleepTest < UMBaseTest
|
|
228
234
|
assert_in_range 0.02..0.04, t1 - t0
|
229
235
|
assert_kind_of D, ret
|
230
236
|
end
|
237
|
+
|
238
|
+
def test_sleep_forever
|
239
|
+
t0 = monotonic_clock
|
240
|
+
ret = begin
|
241
|
+
machine.timeout(0.03, D) do
|
242
|
+
machine.sleep 0
|
243
|
+
end
|
244
|
+
rescue => e
|
245
|
+
e
|
246
|
+
end
|
247
|
+
t1 = monotonic_clock
|
248
|
+
assert_in_range 0.02..0.04, t1 - t0
|
249
|
+
assert_kind_of D, ret
|
250
|
+
end
|
231
251
|
end
|
232
252
|
|
233
253
|
class PeriodicallyTest < UMBaseTest
|
@@ -271,7 +291,7 @@ class PeriodicallyTest < UMBaseTest
|
|
271
291
|
rescue Cancel
|
272
292
|
cancel = 1
|
273
293
|
end
|
274
|
-
|
294
|
+
5.times { machine.snooze }
|
275
295
|
assert_equal 0, machine.pending_count
|
276
296
|
t1 = monotonic_clock
|
277
297
|
assert_in_range 0.05..0.08, t1 - t0
|
@@ -569,25 +589,31 @@ class CloseTest < UMBaseTest
|
|
569
589
|
|
570
590
|
assert_raises(Errno::EBADF) { machine.close(w.fileno) }
|
571
591
|
end
|
572
|
-
end
|
573
592
|
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
server_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
578
|
-
@machine.setsockopt(server_fd, UM::SOL_SOCKET, UM::SO_REUSEADDR, true)
|
579
|
-
@machine.bind(server_fd, '127.0.0.1', port)
|
580
|
-
@machine.listen(server_fd, UM::SOMAXCONN)
|
593
|
+
def test_close_bad_fd
|
594
|
+
r, w = IO.pipe
|
595
|
+
machine.close(w.fileno)
|
581
596
|
|
582
|
-
|
583
|
-
|
597
|
+
assert_raises(Errno::EBADF) { machine.close(w.fileno) }
|
598
|
+
end
|
599
|
+
end
|
584
600
|
|
585
|
-
|
601
|
+
class CloseAsyncTest < UMBaseTest
|
602
|
+
def test_close_async
|
603
|
+
r, w = IO.pipe
|
604
|
+
machine.write(w.fileno, 'foo')
|
605
|
+
assert_equal 'foo', r.readpartial(3)
|
586
606
|
|
587
|
-
|
588
|
-
|
607
|
+
assert_equal 0, machine.pending_count
|
608
|
+
machine.close_async(w.fileno)
|
609
|
+
assert_equal 1, machine.pending_count
|
610
|
+
machine.snooze
|
611
|
+
assert_equal 0, machine.pending_count
|
612
|
+
assert_equal '', r.read
|
589
613
|
end
|
614
|
+
end
|
590
615
|
|
616
|
+
class ShutdownTest < UMBaseTest
|
591
617
|
def test_shutdown
|
592
618
|
c_fd, s_fd = make_socket_pair
|
593
619
|
res = @machine.send(c_fd, 'abc', 3, 0)
|
@@ -619,6 +645,37 @@ class ShutdownTest < UMBaseTest
|
|
619
645
|
end
|
620
646
|
end
|
621
647
|
|
648
|
+
class ShutdownAsyncTest < UMBaseTest
|
649
|
+
def test_shutdown_async
|
650
|
+
c_fd, s_fd = make_socket_pair
|
651
|
+
res = @machine.send(c_fd, 'abc', 3, 0)
|
652
|
+
assert_equal 3, res
|
653
|
+
|
654
|
+
buf = +''
|
655
|
+
res = @machine.recv(s_fd, buf, 256, 0)
|
656
|
+
assert_equal 3, res
|
657
|
+
assert_equal 'abc', buf
|
658
|
+
|
659
|
+
res = @machine.shutdown_async(c_fd, UM::SHUT_WR)
|
660
|
+
assert_equal c_fd, res
|
661
|
+
|
662
|
+
machine.sleep(0.01)
|
663
|
+
assert_raises(Errno::EPIPE) { @machine.send(c_fd, 'abc', 3, 0) }
|
664
|
+
|
665
|
+
res = @machine.shutdown_async(s_fd, UM::SHUT_RD)
|
666
|
+
assert_equal s_fd, res
|
667
|
+
|
668
|
+
res = @machine.recv(s_fd, buf, 256, 0)
|
669
|
+
assert_equal 0, res
|
670
|
+
|
671
|
+
res = @machine.shutdown_async(c_fd, UM::SHUT_RDWR)
|
672
|
+
assert_equal c_fd, res
|
673
|
+
ensure
|
674
|
+
@machine.close(c_fd)
|
675
|
+
@machine.close(s_fd)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
622
679
|
class AcceptTest < UMBaseTest
|
623
680
|
def setup
|
624
681
|
super
|
@@ -1273,7 +1330,7 @@ class WaitTest < UMBaseTest
|
|
1273
1330
|
ret = machine.read(rfd, buf, 8192)
|
1274
1331
|
assert_equal msg.bytesize, ret
|
1275
1332
|
assert_equal msg, buf
|
1276
|
-
|
1333
|
+
|
1277
1334
|
ensure
|
1278
1335
|
Process.wait(pid) rescue Errno::ECHILD
|
1279
1336
|
end
|
@@ -1361,4 +1418,4 @@ class ForkTest < UMBaseTest
|
|
1361
1418
|
Process.wait(child_pid) rescue Errno::ECHILD
|
1362
1419
|
end
|
1363
1420
|
|
1364
|
-
end
|
1421
|
+
end
|