uringmachine 0.18 → 0.19
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 +4 -0
- data/TODO.md +1 -1
- data/examples/fiber_scheduler_demo.rb +71 -0
- data/ext/um/um.c +82 -38
- data/ext/um/um.h +4 -2
- data/ext/um/um_async_op.c +2 -1
- data/ext/um/um_class.c +6 -0
- data/ext/um/um_const.c +5 -2
- data/ext/um/um_stream.c +8 -8
- data/ext/um/um_stream_class.c +1 -1
- data/ext/um/um_sync.c +2 -2
- data/ext/um/um_utils.c +1 -1
- data/lib/uringmachine/fiber_scheduler.rb +104 -0
- data/lib/uringmachine/version.rb +1 -1
- data/test/test_stream.rb +3 -3
- data/test/test_um.rb +53 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2e4b4b986a75268a9de9dbafacd7d2a5c31cc08058b86a9681757be698fe697e
|
|
4
|
+
data.tar.gz: 99007eb49069d9cfebc70ce6da9c45cbbd5e7c4d518892869ddcb55c401b1cdb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f7c55065ac4aef687f91236bf5cb55be4756dee002e61e627775a93d74d069a8ca45372c43cc71d31efce4b33cfb623443a7ef53b929563b48ec8a0e59cbdf92
|
|
7
|
+
data.tar.gz: 066a85ff0f7218e410abdc89e63cc20ae1ff858ecbc857a84f83ab812286fb1f6dd099d44e254452f466d66569046de3cffe0ba9d7d4f52bb1717670a34c5398
|
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../lib/uringmachine'
|
|
4
|
+
require_relative '../lib/uringmachine/fiber_scheduler'
|
|
5
|
+
require 'net/http'
|
|
6
|
+
|
|
7
|
+
machine = UringMachine.new
|
|
8
|
+
scheduler = UM::FiberScheduler.new(machine)
|
|
9
|
+
Fiber.set_scheduler scheduler
|
|
10
|
+
|
|
11
|
+
i, o = IO.pipe
|
|
12
|
+
|
|
13
|
+
f1 = Fiber.schedule do
|
|
14
|
+
# sleep 0.4
|
|
15
|
+
# o.write 'Hello, world!'
|
|
16
|
+
# o.close
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
f2 = Fiber.schedule do
|
|
20
|
+
# puts "hi"
|
|
21
|
+
# 10.times do
|
|
22
|
+
# sleep 0.1
|
|
23
|
+
# puts "."
|
|
24
|
+
# end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Fiber.schedule do
|
|
28
|
+
# scheduler.block(:wait)
|
|
29
|
+
# end
|
|
30
|
+
|
|
31
|
+
f3 = Fiber.schedule do
|
|
32
|
+
# message = i.read
|
|
33
|
+
# puts message
|
|
34
|
+
# rescue => e
|
|
35
|
+
# scheduler.p e
|
|
36
|
+
# scheduler.p e.backtrace
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
f4 = Fiber.schedule do
|
|
40
|
+
puts '*' * 40
|
|
41
|
+
# tcp = TCPSocket.new('noteflakes.com', 80)
|
|
42
|
+
# tcp.timeout = 10
|
|
43
|
+
# scheduler.p tcp
|
|
44
|
+
# tcp << "GET / HTTP/1.1\r\nHost: noteflakes.com\r\n\r\n"
|
|
45
|
+
# s = tcp.read
|
|
46
|
+
# scheduler.p s: s
|
|
47
|
+
ret = Net::HTTP.get('noteflakes.com', '/ping')
|
|
48
|
+
scheduler.p ret: ret
|
|
49
|
+
rescue => e
|
|
50
|
+
scheduler.p e
|
|
51
|
+
scheduler.p e.backtrace
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
scheduler.join(f1, f2, f3, f4)
|
|
55
|
+
|
|
56
|
+
__END__
|
|
57
|
+
|
|
58
|
+
stdout_fd = STDOUT.fileno
|
|
59
|
+
stdin_fd = STDIN.fileno
|
|
60
|
+
machine.write(stdout_fd, "Hello, world!\n")
|
|
61
|
+
|
|
62
|
+
loop do
|
|
63
|
+
machine.write(stdout_fd, "Say something: ")
|
|
64
|
+
buf = +''
|
|
65
|
+
res = machine.read(stdin_fd, buf, 8192)
|
|
66
|
+
if res > 0
|
|
67
|
+
machine.write(stdout_fd, "You said: #{buf}")
|
|
68
|
+
else
|
|
69
|
+
break
|
|
70
|
+
end
|
|
71
|
+
end
|
data/ext/um/um.c
CHANGED
|
@@ -252,8 +252,10 @@ inline int um_check_completion(struct um *machine, struct um_op *op) {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
inline VALUE um_await(struct um *machine) {
|
|
255
|
-
VALUE
|
|
256
|
-
|
|
255
|
+
VALUE ret = um_fiber_switch(machine);
|
|
256
|
+
RAISE_IF_EXCEPTION(ret);
|
|
257
|
+
RB_GC_GUARD(ret);
|
|
258
|
+
return ret;
|
|
257
259
|
}
|
|
258
260
|
|
|
259
261
|
inline void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind, unsigned flags) {
|
|
@@ -340,8 +342,9 @@ VALUE um_sleep(struct um *machine, double duration) {
|
|
|
340
342
|
ret = DBL2NUM(duration);
|
|
341
343
|
}
|
|
342
344
|
|
|
345
|
+
RAISE_IF_EXCEPTION(ret);
|
|
343
346
|
RB_GC_GUARD(ret);
|
|
344
|
-
return
|
|
347
|
+
return ret;
|
|
345
348
|
}
|
|
346
349
|
|
|
347
350
|
inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset) {
|
|
@@ -357,10 +360,11 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
|
|
|
357
360
|
ret = INT2NUM(op.result.res);
|
|
358
361
|
|
|
359
362
|
}
|
|
360
|
-
|
|
361
363
|
RB_GC_GUARD(buffer);
|
|
364
|
+
|
|
365
|
+
RAISE_IF_EXCEPTION(ret);
|
|
362
366
|
RB_GC_GUARD(ret);
|
|
363
|
-
return
|
|
367
|
+
return ret;
|
|
364
368
|
}
|
|
365
369
|
|
|
366
370
|
inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen) {
|
|
@@ -375,7 +379,8 @@ inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen)
|
|
|
375
379
|
|
|
376
380
|
}
|
|
377
381
|
|
|
378
|
-
|
|
382
|
+
RAISE_IF_EXCEPTION(ret);
|
|
383
|
+
RB_GC_GUARD(ret);
|
|
379
384
|
return 0;
|
|
380
385
|
}
|
|
381
386
|
|
|
@@ -393,8 +398,10 @@ VALUE um_write(struct um *machine, int fd, VALUE str, int len) {
|
|
|
393
398
|
ret = INT2NUM(op.result.res);
|
|
394
399
|
|
|
395
400
|
RB_GC_GUARD(str);
|
|
401
|
+
|
|
402
|
+
RAISE_IF_EXCEPTION(ret);
|
|
396
403
|
RB_GC_GUARD(ret);
|
|
397
|
-
return
|
|
404
|
+
return ret;
|
|
398
405
|
}
|
|
399
406
|
|
|
400
407
|
VALUE um_write_async(struct um *machine, int fd, VALUE str) {
|
|
@@ -419,8 +426,9 @@ VALUE um_close(struct um *machine, int fd) {
|
|
|
419
426
|
if (um_check_completion(machine, &op))
|
|
420
427
|
ret = INT2NUM(fd);
|
|
421
428
|
|
|
429
|
+
RAISE_IF_EXCEPTION(ret);
|
|
422
430
|
RB_GC_GUARD(ret);
|
|
423
|
-
return
|
|
431
|
+
return ret;
|
|
424
432
|
}
|
|
425
433
|
|
|
426
434
|
VALUE um_close_async(struct um *machine, int fd) {
|
|
@@ -443,8 +451,9 @@ VALUE um_accept(struct um *machine, int fd) {
|
|
|
443
451
|
if (um_check_completion(machine, &op))
|
|
444
452
|
ret = INT2NUM(op.result.res);
|
|
445
453
|
|
|
454
|
+
RAISE_IF_EXCEPTION(ret);
|
|
446
455
|
RB_GC_GUARD(ret);
|
|
447
|
-
return
|
|
456
|
+
return ret;
|
|
448
457
|
}
|
|
449
458
|
|
|
450
459
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags) {
|
|
@@ -457,8 +466,9 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
|
|
|
457
466
|
if (um_check_completion(machine, &op))
|
|
458
467
|
ret = INT2NUM(op.result.res);
|
|
459
468
|
|
|
469
|
+
RAISE_IF_EXCEPTION(ret);
|
|
460
470
|
RB_GC_GUARD(ret);
|
|
461
|
-
return
|
|
471
|
+
return ret;
|
|
462
472
|
}
|
|
463
473
|
|
|
464
474
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen) {
|
|
@@ -471,8 +481,9 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
|
|
|
471
481
|
if (um_check_completion(machine, &op))
|
|
472
482
|
ret = INT2NUM(op.result.res);
|
|
473
483
|
|
|
484
|
+
RAISE_IF_EXCEPTION(ret);
|
|
474
485
|
RB_GC_GUARD(ret);
|
|
475
|
-
return
|
|
486
|
+
return ret;
|
|
476
487
|
}
|
|
477
488
|
|
|
478
489
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
|
@@ -486,8 +497,10 @@ VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags) {
|
|
|
486
497
|
ret = INT2NUM(op.result.res);
|
|
487
498
|
|
|
488
499
|
RB_GC_GUARD(buffer);
|
|
500
|
+
|
|
501
|
+
RAISE_IF_EXCEPTION(ret);
|
|
489
502
|
RB_GC_GUARD(ret);
|
|
490
|
-
return
|
|
503
|
+
return ret;
|
|
491
504
|
}
|
|
492
505
|
|
|
493
506
|
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings) {
|
|
@@ -505,10 +518,8 @@ VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings) {
|
|
|
505
518
|
if (um_check_completion(machine, &op))
|
|
506
519
|
ret = INT2NUM(op.result.res);
|
|
507
520
|
|
|
521
|
+
RAISE_IF_EXCEPTION(ret);
|
|
508
522
|
RB_GC_GUARD(ret);
|
|
509
|
-
return raise_if_exception(ret);
|
|
510
|
-
|
|
511
|
-
|
|
512
523
|
return ret;
|
|
513
524
|
}
|
|
514
525
|
|
|
@@ -526,8 +537,10 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
|
|
526
537
|
}
|
|
527
538
|
|
|
528
539
|
RB_GC_GUARD(buffer);
|
|
540
|
+
|
|
541
|
+
RAISE_IF_EXCEPTION(ret);
|
|
529
542
|
RB_GC_GUARD(ret);
|
|
530
|
-
return
|
|
543
|
+
return ret;
|
|
531
544
|
}
|
|
532
545
|
|
|
533
546
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen) {
|
|
@@ -540,8 +553,9 @@ VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrl
|
|
|
540
553
|
if (um_check_completion(machine, &op))
|
|
541
554
|
ret = INT2NUM(op.result.res);
|
|
542
555
|
|
|
556
|
+
RAISE_IF_EXCEPTION(ret);
|
|
543
557
|
RB_GC_GUARD(ret);
|
|
544
|
-
return
|
|
558
|
+
return ret;
|
|
545
559
|
}
|
|
546
560
|
|
|
547
561
|
VALUE um_listen(struct um *machine, int fd, int backlog) {
|
|
@@ -554,8 +568,9 @@ VALUE um_listen(struct um *machine, int fd, int backlog) {
|
|
|
554
568
|
if (um_check_completion(machine, &op))
|
|
555
569
|
ret = INT2NUM(op.result.res);
|
|
556
570
|
|
|
571
|
+
RAISE_IF_EXCEPTION(ret);
|
|
557
572
|
RB_GC_GUARD(ret);
|
|
558
|
-
return
|
|
573
|
+
return ret;
|
|
559
574
|
}
|
|
560
575
|
|
|
561
576
|
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
@@ -579,8 +594,9 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
|
579
594
|
ret = INT2NUM(value);
|
|
580
595
|
#endif
|
|
581
596
|
|
|
597
|
+
RAISE_IF_EXCEPTION(ret);
|
|
582
598
|
RB_GC_GUARD(ret);
|
|
583
|
-
return
|
|
599
|
+
return ret;
|
|
584
600
|
}
|
|
585
601
|
|
|
586
602
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
@@ -602,8 +618,9 @@ VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
|
602
618
|
ret = INT2NUM(0);
|
|
603
619
|
#endif
|
|
604
620
|
|
|
621
|
+
RAISE_IF_EXCEPTION(ret);
|
|
605
622
|
RB_GC_GUARD(ret);
|
|
606
|
-
return
|
|
623
|
+
return ret;
|
|
607
624
|
}
|
|
608
625
|
|
|
609
626
|
VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
@@ -618,14 +635,14 @@ VALUE um_shutdown(struct um *machine, int fd, int how) {
|
|
|
618
635
|
if (um_check_completion(machine, &op))
|
|
619
636
|
ret = INT2NUM(op.result.res);
|
|
620
637
|
|
|
638
|
+
RAISE_IF_EXCEPTION(ret);
|
|
621
639
|
RB_GC_GUARD(ret);
|
|
622
|
-
return
|
|
640
|
+
return ret;
|
|
623
641
|
}
|
|
624
642
|
|
|
625
643
|
VALUE um_shutdown_async(struct um *machine, int fd, int how) {
|
|
626
644
|
struct um_op *op = um_op_alloc(machine);
|
|
627
645
|
um_prep_op(machine, op, OP_SHUTDOWN_ASYNC, OP_F_FREE_ON_COMPLETE);
|
|
628
|
-
|
|
629
646
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
630
647
|
io_uring_prep_shutdown(sqe, fd, how);
|
|
631
648
|
|
|
@@ -642,8 +659,24 @@ VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
|
|
642
659
|
if (um_check_completion(machine, &op))
|
|
643
660
|
ret = INT2NUM(op.result.res);
|
|
644
661
|
|
|
662
|
+
RAISE_IF_EXCEPTION(ret);
|
|
645
663
|
RB_GC_GUARD(ret);
|
|
646
|
-
return
|
|
664
|
+
return ret;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
VALUE um_poll(struct um *machine, int fd, unsigned mask) {
|
|
668
|
+
struct um_op op;
|
|
669
|
+
um_prep_op(machine, &op, OP_POLL, 0);
|
|
670
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
671
|
+
io_uring_prep_poll_add(sqe, fd, mask);
|
|
672
|
+
|
|
673
|
+
VALUE ret = um_fiber_switch(machine);
|
|
674
|
+
if (um_check_completion(machine, &op))
|
|
675
|
+
ret = INT2NUM(op.result.res);
|
|
676
|
+
|
|
677
|
+
RAISE_IF_EXCEPTION(ret);
|
|
678
|
+
RB_GC_GUARD(ret);
|
|
679
|
+
return ret;
|
|
647
680
|
}
|
|
648
681
|
|
|
649
682
|
VALUE um_waitpid(struct um *machine, int pid, int options) {
|
|
@@ -658,8 +691,8 @@ VALUE um_waitpid(struct um *machine, int pid, int options) {
|
|
|
658
691
|
if (um_check_completion(machine, &op))
|
|
659
692
|
ret = INT2NUM(op.result.res);
|
|
660
693
|
|
|
694
|
+
RAISE_IF_EXCEPTION(ret);
|
|
661
695
|
RB_GC_GUARD(ret);
|
|
662
|
-
raise_if_exception(ret);
|
|
663
696
|
|
|
664
697
|
return rb_ary_new_from_args(2, INT2NUM(infop.si_pid), INT2NUM(infop.si_status));
|
|
665
698
|
}
|
|
@@ -688,24 +721,23 @@ VALUE statx_to_hash(struct statx *stat) {
|
|
|
688
721
|
}
|
|
689
722
|
|
|
690
723
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask) {
|
|
724
|
+
static char empty_path[] = "";
|
|
725
|
+
|
|
691
726
|
struct um_op op;
|
|
692
727
|
um_prep_op(machine, &op, OP_STATX, 0);
|
|
693
728
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
694
729
|
|
|
730
|
+
char *path_ptr = NIL_P(path) ? empty_path : StringValueCStr(path);
|
|
695
731
|
struct statx stat;
|
|
696
732
|
memset(&stat, 0, sizeof(stat));
|
|
697
|
-
|
|
698
|
-
if (NIL_P(path))
|
|
699
|
-
path = rb_str_new_literal("");
|
|
700
|
-
|
|
701
|
-
io_uring_prep_statx(sqe, dirfd, StringValueCStr(path), flags, mask, &stat);
|
|
733
|
+
io_uring_prep_statx(sqe, dirfd, path_ptr, flags, mask, &stat);
|
|
702
734
|
|
|
703
735
|
VALUE ret = um_fiber_switch(machine);
|
|
704
736
|
if (um_check_completion(machine, &op))
|
|
705
737
|
ret = INT2NUM(op.result.res);
|
|
706
738
|
|
|
739
|
+
RAISE_IF_EXCEPTION(ret);
|
|
707
740
|
RB_GC_GUARD(ret);
|
|
708
|
-
raise_if_exception(ret);
|
|
709
741
|
|
|
710
742
|
return statx_to_hash(&stat);
|
|
711
743
|
}
|
|
@@ -721,8 +753,11 @@ VALUE accept_each_start(VALUE arg) {
|
|
|
721
753
|
|
|
722
754
|
while (true) {
|
|
723
755
|
VALUE ret = um_fiber_switch(ctx->machine);
|
|
724
|
-
if (!um_op_completed_p(ctx->op))
|
|
725
|
-
|
|
756
|
+
if (!um_op_completed_p(ctx->op)) {
|
|
757
|
+
RAISE_IF_EXCEPTION(ret);
|
|
758
|
+
return ret;
|
|
759
|
+
}
|
|
760
|
+
RB_GC_GUARD(ret);
|
|
726
761
|
|
|
727
762
|
int more = false;
|
|
728
763
|
struct um_op_result *result = &ctx->op->result;
|
|
@@ -791,8 +826,11 @@ int um_read_each_singleshot_loop(struct op_ctx *ctx) {
|
|
|
791
826
|
rb_yield(buf);
|
|
792
827
|
RB_GC_GUARD(buf);
|
|
793
828
|
}
|
|
794
|
-
else
|
|
795
|
-
|
|
829
|
+
else {
|
|
830
|
+
RAISE_IF_EXCEPTION(ret);
|
|
831
|
+
return ret;
|
|
832
|
+
}
|
|
833
|
+
RB_GC_GUARD(ret);
|
|
796
834
|
}
|
|
797
835
|
}
|
|
798
836
|
|
|
@@ -840,8 +878,11 @@ VALUE read_recv_each_start(VALUE arg) {
|
|
|
840
878
|
|
|
841
879
|
while (true) {
|
|
842
880
|
VALUE ret = um_fiber_switch(ctx->machine);
|
|
843
|
-
if (!um_op_completed_p(ctx->op))
|
|
844
|
-
|
|
881
|
+
if (!um_op_completed_p(ctx->op)) {
|
|
882
|
+
RAISE_IF_EXCEPTION(ret);
|
|
883
|
+
return ret;
|
|
884
|
+
}
|
|
885
|
+
RB_GC_GUARD(ret);
|
|
845
886
|
|
|
846
887
|
int more = false;
|
|
847
888
|
struct um_op_result *result = &ctx->op->result;
|
|
@@ -888,8 +929,11 @@ VALUE periodically_start(VALUE arg) {
|
|
|
888
929
|
|
|
889
930
|
while (true) {
|
|
890
931
|
VALUE ret = um_fiber_switch(ctx->machine);
|
|
891
|
-
if (!um_op_completed_p(ctx->op))
|
|
892
|
-
|
|
932
|
+
if (!um_op_completed_p(ctx->op)) {
|
|
933
|
+
RAISE_IF_EXCEPTION(ret);
|
|
934
|
+
return ret;
|
|
935
|
+
}
|
|
936
|
+
RB_GC_GUARD(ret);
|
|
893
937
|
|
|
894
938
|
int more = false;
|
|
895
939
|
struct um_op_result *result = &ctx->op->result;
|
data/ext/um/um.h
CHANGED
|
@@ -45,7 +45,8 @@ enum op_kind {
|
|
|
45
45
|
OP_SETSOCKOPT,
|
|
46
46
|
OP_SHUTDOWN,
|
|
47
47
|
OP_SHUTDOWN_ASYNC,
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
OP_POLL,
|
|
49
50
|
OP_WAITPID,
|
|
50
51
|
|
|
51
52
|
OP_FUTEX_WAIT,
|
|
@@ -203,7 +204,7 @@ double um_timestamp_to_double(__s64 tv_sec, __u32 tv_nsec);
|
|
|
203
204
|
int um_value_is_exception_p(VALUE v);
|
|
204
205
|
VALUE um_raise_exception(VALUE v);
|
|
205
206
|
|
|
206
|
-
#define
|
|
207
|
+
#define RAISE_IF_EXCEPTION(v) if (um_value_is_exception_p(v)) { um_raise_exception(v); }
|
|
207
208
|
|
|
208
209
|
void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind, unsigned flags);
|
|
209
210
|
void um_raise_on_error_result(int result);
|
|
@@ -235,6 +236,7 @@ VALUE um_write(struct um *machine, int fd, VALUE str, int len);
|
|
|
235
236
|
VALUE um_close(struct um *machine, int fd);
|
|
236
237
|
VALUE um_close_async(struct um *machine, int fd);
|
|
237
238
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode);
|
|
239
|
+
VALUE um_poll(struct um *machine, int fd, unsigned mask);
|
|
238
240
|
VALUE um_waitpid(struct um *machine, int pid, int options);
|
|
239
241
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask);
|
|
240
242
|
VALUE um_write_async(struct um *machine, int fd, VALUE str);
|
data/ext/um/um_async_op.c
CHANGED
|
@@ -30,7 +30,8 @@ VALUE um_async_op_await(struct um_async_op *async_op) {
|
|
|
30
30
|
if (!um_op_completed_p(async_op->op))
|
|
31
31
|
um_cancel_and_wait(async_op->machine, async_op->op);
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
RAISE_IF_EXCEPTION(ret);
|
|
34
|
+
RB_GC_GUARD(ret);
|
|
34
35
|
return INT2NUM(async_op->op->result.res);
|
|
35
36
|
}
|
|
36
37
|
|
data/ext/um/um_class.c
CHANGED
|
@@ -327,6 +327,11 @@ VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) {
|
|
|
327
327
|
return fd;
|
|
328
328
|
}
|
|
329
329
|
|
|
330
|
+
VALUE UM_poll(VALUE self, VALUE fd, VALUE mask) {
|
|
331
|
+
struct um *machine = um_get_machine(self);
|
|
332
|
+
return um_poll(machine, NUM2INT(fd), NUM2UINT(mask));
|
|
333
|
+
}
|
|
334
|
+
|
|
330
335
|
VALUE UM_waitpid(VALUE self, VALUE pid, VALUE options) {
|
|
331
336
|
struct um *machine = um_get_machine(self);
|
|
332
337
|
return um_waitpid(machine, NUM2INT(pid), NUM2INT(options));
|
|
@@ -382,6 +387,7 @@ void Init_UM(void) {
|
|
|
382
387
|
rb_define_method(cUM, "write_async", UM_write_async, 2);
|
|
383
388
|
rb_define_method(cUM, "statx", UM_statx, 4);
|
|
384
389
|
|
|
390
|
+
rb_define_method(cUM, "poll", UM_poll, 2);
|
|
385
391
|
rb_define_method(cUM, "waitpid", UM_waitpid, 2);
|
|
386
392
|
|
|
387
393
|
rb_define_method(cUM, "accept", UM_accept, 1);
|
data/ext/um/um_const.c
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
#include <netinet/udp.h>
|
|
13
13
|
#include <netdb.h>
|
|
14
14
|
#include <net/if.h>
|
|
15
|
-
|
|
15
|
+
#include <poll.h>
|
|
16
16
|
|
|
17
17
|
#define DEF_CONST_INT(mod, v) rb_define_const(mod, #v, INT2NUM(v))
|
|
18
18
|
|
|
@@ -258,6 +258,10 @@ void um_define_net_constants(VALUE mod) {
|
|
|
258
258
|
|
|
259
259
|
DEF_CONST_INT(mod, SOMAXCONN);
|
|
260
260
|
|
|
261
|
+
DEF_CONST_INT(mod, POLLIN);
|
|
262
|
+
DEF_CONST_INT(mod, POLLOUT);
|
|
263
|
+
DEF_CONST_INT(mod, POLLERR);
|
|
264
|
+
|
|
261
265
|
DEF_CONST_INT(mod, EPERM);
|
|
262
266
|
DEF_CONST_INT(mod, ENOENT);
|
|
263
267
|
DEF_CONST_INT(mod, ESRCH);
|
|
@@ -387,5 +391,4 @@ void um_define_net_constants(VALUE mod) {
|
|
|
387
391
|
DEF_CONST_INT(mod, EKEYREJECTED);
|
|
388
392
|
DEF_CONST_INT(mod, EOWNERDEAD);
|
|
389
393
|
DEF_CONST_INT(mod, ENOTRECOVERABLE);
|
|
390
|
-
|
|
391
394
|
}
|
data/ext/um/um_stream.c
CHANGED
|
@@ -26,7 +26,7 @@ int stream_read_more(struct um_stream *stream) {
|
|
|
26
26
|
size_t capa = rb_str_capacity(stream->buffer);
|
|
27
27
|
if (capa - stream->pos < maxlen)
|
|
28
28
|
rb_str_modify_expand(stream->buffer, maxlen - (capa - stream->pos));
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
rb_str_modify(stream->buffer);
|
|
31
31
|
char *ptr = RSTRING_PTR(stream->buffer) + stream->pos;
|
|
32
32
|
size_t ret = um_read_raw(stream->machine, stream->fd, ptr, maxlen);
|
|
@@ -94,7 +94,7 @@ VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len) {
|
|
|
94
94
|
|
|
95
95
|
abslen = stream->len - stream->pos;
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
|
99
99
|
stream->pos += abslen;
|
|
100
100
|
|
|
@@ -137,7 +137,7 @@ VALUE resp_get_string(struct um_stream *stream, ulong len, VALUE out_buffer) {
|
|
|
137
137
|
|
|
138
138
|
while (stream->len - stream->pos < read_len)
|
|
139
139
|
if (!stream_read_more(stream)) return Qnil;
|
|
140
|
-
|
|
140
|
+
|
|
141
141
|
char *start = RSTRING_PTR(stream->buffer) + stream->pos;
|
|
142
142
|
stream->pos += read_len;
|
|
143
143
|
|
|
@@ -198,7 +198,7 @@ static inline VALUE resp_decode_string_with_encoding(struct um_stream *stream, V
|
|
|
198
198
|
|
|
199
199
|
static inline VALUE resp_decode_integer(char *ptr) {
|
|
200
200
|
long value = strtol(ptr + 1, NULL, 10);
|
|
201
|
-
return LONG2NUM(value);
|
|
201
|
+
return LONG2NUM(value);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
static inline VALUE resp_decode_float(char *ptr) {
|
|
@@ -234,13 +234,13 @@ VALUE resp_decode(struct um_stream *stream, VALUE out_buffer) {
|
|
|
234
234
|
ulong len = RSTRING_LEN(msg);
|
|
235
235
|
ulong data_len;
|
|
236
236
|
if (len == 0) return Qnil;
|
|
237
|
-
|
|
237
|
+
|
|
238
238
|
switch (ptr[0]) {
|
|
239
239
|
case '%': // hash
|
|
240
240
|
case '|': // attributes hash
|
|
241
241
|
data_len = resp_parse_length_field(ptr, len);
|
|
242
242
|
return resp_decode_hash(stream, out_buffer, data_len);
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
case '*': // array
|
|
245
245
|
case '~': // set
|
|
246
246
|
case '>': // pub/sub push
|
|
@@ -276,7 +276,7 @@ VALUE resp_decode(struct um_stream *stream, VALUE out_buffer) {
|
|
|
276
276
|
default:
|
|
277
277
|
rb_raise(rb_eRuntimeError, "Invalid character encountered");
|
|
278
278
|
}
|
|
279
|
-
|
|
279
|
+
|
|
280
280
|
RB_GC_GUARD(msg);
|
|
281
281
|
}
|
|
282
282
|
|
|
@@ -284,7 +284,7 @@ void write_buffer_init(struct um_write_buffer *buf, VALUE str) {
|
|
|
284
284
|
size_t capa = 1 << 12;
|
|
285
285
|
size_t len = RSTRING_LEN(str);
|
|
286
286
|
while (capa < len) capa += 1 << 12;
|
|
287
|
-
|
|
287
|
+
|
|
288
288
|
rb_str_resize(str, capa);
|
|
289
289
|
rb_str_set_len(str, len);
|
|
290
290
|
buf->str = str;
|
data/ext/um/um_stream_class.c
CHANGED
|
@@ -88,7 +88,7 @@ void Init_Stream(void) {
|
|
|
88
88
|
rb_define_alloc_func(cStream, Stream_allocate);
|
|
89
89
|
|
|
90
90
|
rb_define_method(cStream, "initialize", Stream_initialize, 2);
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
rb_define_method(cStream, "get_line", Stream_get_line, 2);
|
|
93
93
|
rb_define_method(cStream, "get_string", Stream_get_string, 2);
|
|
94
94
|
|
data/ext/um/um_sync.c
CHANGED
|
@@ -21,8 +21,8 @@ void um_futex_wait(struct um *machine, uint32_t *futex, uint32_t expect) {
|
|
|
21
21
|
um_raise_on_error_result(op.result.res);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
RAISE_IF_EXCEPTION(ret);
|
|
24
25
|
RB_GC_GUARD(ret);
|
|
25
|
-
raise_if_exception(ret);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
void um_futex_wake(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
|
@@ -38,8 +38,8 @@ void um_futex_wake(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
|
|
38
38
|
VALUE ret = um_fiber_switch(machine);
|
|
39
39
|
um_check_completion(machine, &op);
|
|
40
40
|
|
|
41
|
+
RAISE_IF_EXCEPTION(ret);
|
|
41
42
|
RB_GC_GUARD(ret);
|
|
42
|
-
raise_if_exception(ret);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
void um_futex_wake_transient(struct um *machine, uint32_t *futex, uint32_t num_waiters) {
|
data/ext/um/um_utils.c
CHANGED
|
@@ -129,7 +129,7 @@ inline void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE st
|
|
|
129
129
|
ulong count = RARRAY_LEN(strings);
|
|
130
130
|
VALUE str = Qnil;
|
|
131
131
|
VALUE converted = Qnil;
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
for (ulong i = 0; i < count; i++) {
|
|
134
134
|
str = rb_ary_entry(strings, i);
|
|
135
135
|
if (TYPE(str) != T_STRING) {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class UringMachine
|
|
4
|
+
class FiberScheduler
|
|
5
|
+
def initialize(machine)
|
|
6
|
+
@machine = machine
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def p(o)
|
|
10
|
+
@machine.write(1, "#{o.inspect}\n")
|
|
11
|
+
rescue Errno::EINTR
|
|
12
|
+
retry
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def join(*)
|
|
16
|
+
@machine.join(*)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def block(blocker, timeout)
|
|
20
|
+
p block: [blocker, timeout]
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def unblock(blocker, fiber)
|
|
25
|
+
p unblock: [blocker, fiber]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def kernel_sleep(duration = nil)
|
|
29
|
+
# p sleep: [duration]
|
|
30
|
+
if duration
|
|
31
|
+
@machine.sleep(duration)
|
|
32
|
+
else
|
|
33
|
+
@machine.yield
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def io_wait(io, events, timeout = nil)
|
|
38
|
+
timeout ||= io.timeout
|
|
39
|
+
p timeout: timeout
|
|
40
|
+
if timeout
|
|
41
|
+
p 1
|
|
42
|
+
@machine.timeout(timeout, Timeout::Error) {
|
|
43
|
+
p 2
|
|
44
|
+
@machine.poll(io.fileno, events).tap { p 3 }
|
|
45
|
+
}.tap { p 4 }
|
|
46
|
+
else
|
|
47
|
+
p 5
|
|
48
|
+
@machine.poll(io.fileno, events).tap { p 6 }
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
rescue => e
|
|
52
|
+
p e: e
|
|
53
|
+
raise
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def fiber(&block)
|
|
57
|
+
f = @machine.spin(&block)
|
|
58
|
+
@machine.snooze
|
|
59
|
+
f
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def io_write(io, buffer, length, offset)
|
|
63
|
+
p io_write: [io, buffer.get_string, length, offset]
|
|
64
|
+
@machine.write(io.fileno, buffer.get_string)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def io_read(io, buffer, length, offset)
|
|
68
|
+
# p io_read: [io, buffer, length, offset]
|
|
69
|
+
s = +''
|
|
70
|
+
length = buffer.size if length == 0
|
|
71
|
+
bytes = @machine.read(io.fileno, s, length)
|
|
72
|
+
buffer.set_string(s)
|
|
73
|
+
bytes
|
|
74
|
+
rescue SystemCallError => e
|
|
75
|
+
-e.errno
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def io_pwrite(io, buffer, from, length, offset)
|
|
79
|
+
p io_pwrite: [io, buffer, from, length, offset]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def io_pread(io, buffer, from, length, offset)
|
|
83
|
+
p io_pread: [io, buffer, from, length, offset]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# def fiber(&block)
|
|
87
|
+
# fiber = Fiber.new(blocking: false, &block)
|
|
88
|
+
# unblock(nil, fiber)
|
|
89
|
+
# # fiber.resume
|
|
90
|
+
# return fiber
|
|
91
|
+
# end
|
|
92
|
+
|
|
93
|
+
# def kernel_sleep(duration = nil)
|
|
94
|
+
# block(:sleep, duration)
|
|
95
|
+
# end
|
|
96
|
+
|
|
97
|
+
# def process_wait(pid, flags)
|
|
98
|
+
# # This is a very simple way to implement a non-blocking wait:
|
|
99
|
+
# Thread.new do
|
|
100
|
+
# Process::Status.wait(pid, flags)
|
|
101
|
+
# end.value
|
|
102
|
+
# end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/lib/uringmachine/version.rb
CHANGED
data/test/test_stream.rb
CHANGED
|
@@ -7,7 +7,7 @@ class StreamBaseTest < UMBaseTest
|
|
|
7
7
|
super
|
|
8
8
|
@rfd, @wfd = UM.pipe
|
|
9
9
|
@stream = UM::Stream.new(@machine, @rfd)
|
|
10
|
-
end
|
|
10
|
+
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
class StreamTest < StreamBaseTest
|
|
@@ -166,7 +166,7 @@ class StreamRespTest < StreamBaseTest
|
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
def test_resp_encode
|
|
169
|
-
s = UM::Stream
|
|
169
|
+
s = UM::Stream
|
|
170
170
|
assert_equal "_\r\n", s.resp_encode(+'', nil)
|
|
171
171
|
assert_equal "#t\r\n", s.resp_encode(+'', true)
|
|
172
172
|
assert_equal "#f\r\n", s.resp_encode(+'', false)
|
|
@@ -174,7 +174,7 @@ class StreamRespTest < StreamBaseTest
|
|
|
174
174
|
assert_equal ",42.1\r\n", s.resp_encode(+'', 42.1)
|
|
175
175
|
assert_equal "$6\r\nfoobar\r\n", s.resp_encode(+'', 'foobar')
|
|
176
176
|
assert_equal "$10\r\nפובאר\r\n", s.resp_encode(+'', 'פובאר')
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
|
|
179
179
|
s.resp_encode(+'', ['foo', 'bar'])
|
|
180
180
|
|
data/test/test_um.rb
CHANGED
|
@@ -169,6 +169,17 @@ class ScheduleTest < UMBaseTest
|
|
|
169
169
|
assert_equal 0, machine.pending_count
|
|
170
170
|
end
|
|
171
171
|
|
|
172
|
+
def test_timeout_with_no_timeout
|
|
173
|
+
_r, w = UM.pipe
|
|
174
|
+
v = machine.timeout(0.1, TOError) { machine.write(w, 'foo') }
|
|
175
|
+
|
|
176
|
+
assert_equal 3, v
|
|
177
|
+
|
|
178
|
+
assert_equal 1, machine.pending_count
|
|
179
|
+
machine.sleep 0.01 # wait for cancelled CQE
|
|
180
|
+
assert_equal 0, machine.pending_count
|
|
181
|
+
end
|
|
182
|
+
|
|
172
183
|
class TO2Error < RuntimeError; end
|
|
173
184
|
class TO3Error < RuntimeError; end
|
|
174
185
|
|
|
@@ -1299,6 +1310,37 @@ class PipeTest < UMBaseTest
|
|
|
1299
1310
|
end
|
|
1300
1311
|
end
|
|
1301
1312
|
|
|
1313
|
+
class PollTest < UMBaseTest
|
|
1314
|
+
def test_poll
|
|
1315
|
+
rfd, wfd = UM.pipe
|
|
1316
|
+
|
|
1317
|
+
events = []
|
|
1318
|
+
f1 = machine.spin do
|
|
1319
|
+
events << :pre
|
|
1320
|
+
events << machine.poll(rfd, UM::POLLIN)
|
|
1321
|
+
events << :post
|
|
1322
|
+
end
|
|
1323
|
+
|
|
1324
|
+
machine.snooze
|
|
1325
|
+
assert_equal [:pre], events
|
|
1326
|
+
|
|
1327
|
+
machine.write(wfd, 'foo')
|
|
1328
|
+
machine.snooze
|
|
1329
|
+
assert_equal [:pre, UM::POLLIN, :post], events
|
|
1330
|
+
|
|
1331
|
+
ret = machine.poll(wfd, UM::POLLOUT)
|
|
1332
|
+
assert_equal UM::POLLOUT, ret
|
|
1333
|
+
|
|
1334
|
+
machine.close(rfd)
|
|
1335
|
+
ret = machine.poll(wfd, UM::POLLOUT | UM::POLLERR)
|
|
1336
|
+
assert_equal UM::POLLOUT | UM::POLLERR, ret
|
|
1337
|
+
end
|
|
1338
|
+
|
|
1339
|
+
def test_poll_bad_fd
|
|
1340
|
+
assert_raises(Errno::EBADF) { machine.poll(9876, POLLIN) }
|
|
1341
|
+
end
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1302
1344
|
class WaitTest < UMBaseTest
|
|
1303
1345
|
def test_waitpid
|
|
1304
1346
|
skip if UM.kernel_version < 607
|
|
@@ -1396,6 +1438,17 @@ class StatxTest < UMBaseTest
|
|
|
1396
1438
|
io.close
|
|
1397
1439
|
end
|
|
1398
1440
|
|
|
1441
|
+
def test_statx_mask
|
|
1442
|
+
fd = @machine.open(__FILE__, UM::O_RDONLY)
|
|
1443
|
+
ustat = machine.statx(fd, nil, UM::AT_EMPTY_PATH, UM::STATX_MTIME | UM::STATX_SIZE)
|
|
1444
|
+
rstat = File.stat(__FILE__)
|
|
1445
|
+
|
|
1446
|
+
assert_equal rstat.size, ustat[:size]
|
|
1447
|
+
assert_equal rstat.mtime.to_i, ustat[:mtime].to_i
|
|
1448
|
+
ensure
|
|
1449
|
+
@machine.close_async(fd)
|
|
1450
|
+
end
|
|
1451
|
+
|
|
1399
1452
|
def test_statx_bad_path
|
|
1400
1453
|
assert_raises(Errno::ENOENT) { machine.statx(UM::AT_FDCWD, 'foobar', 0, UM::STATX_ALL) }
|
|
1401
1454
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: uringmachine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '0.
|
|
4
|
+
version: '0.19'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sharon Rosner
|
|
@@ -92,6 +92,7 @@ files:
|
|
|
92
92
|
- examples/bm_write.rb
|
|
93
93
|
- examples/dns_client.rb
|
|
94
94
|
- examples/echo_server.rb
|
|
95
|
+
- examples/fiber_scheduler_demo.rb
|
|
95
96
|
- examples/http_server.rb
|
|
96
97
|
- examples/inout.rb
|
|
97
98
|
- examples/nc.rb
|
|
@@ -119,6 +120,7 @@ files:
|
|
|
119
120
|
- lib/uringmachine.rb
|
|
120
121
|
- lib/uringmachine/actor.rb
|
|
121
122
|
- lib/uringmachine/dns_resolver.rb
|
|
123
|
+
- lib/uringmachine/fiber_scheduler.rb
|
|
122
124
|
- lib/uringmachine/version.rb
|
|
123
125
|
- supressions/ruby.supp
|
|
124
126
|
- test/helper.rb
|
|
@@ -673,7 +675,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
673
675
|
- !ruby/object:Gem::Version
|
|
674
676
|
version: '0'
|
|
675
677
|
requirements: []
|
|
676
|
-
rubygems_version: 3.
|
|
678
|
+
rubygems_version: 3.7.0.dev
|
|
677
679
|
specification_version: 4
|
|
678
680
|
summary: A lean, mean io_uring machine
|
|
679
681
|
test_files: []
|