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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18144dad22716ba83fde0f2ec1d3bffbb1a13684044f99f279eba183a70e7181
4
- data.tar.gz: 0e742fa4e8ac06475fa7bfab120239863b76f47f5ca33c2a9cc3d0c26ef27bc8
3
+ metadata.gz: 2e4b4b986a75268a9de9dbafacd7d2a5c31cc08058b86a9681757be698fe697e
4
+ data.tar.gz: 99007eb49069d9cfebc70ce6da9c45cbbd5e7c4d518892869ddcb55c401b1cdb
5
5
  SHA512:
6
- metadata.gz: fe981430bc6dace32cb166e3e8177ab5b4cf90f86021ee14990fa01b573459fbace2f17484e2307a9cf8ee83b59b547ae5e2c051774fcb8a444297293214d1e4
7
- data.tar.gz: 8cc7d29d54de95ab70d197db9c1a035d6302750ca86d2ecfb94599e9bed5e3b4f1119eefc8e4804f89f09a20242cd35c0fe277b1a214f2742fce7642b6b83c97
6
+ metadata.gz: f7c55065ac4aef687f91236bf5cb55be4756dee002e61e627775a93d74d069a8ca45372c43cc71d31efce4b33cfb623443a7ef53b929563b48ec8a0e59cbdf92
7
+ data.tar.gz: 066a85ff0f7218e410abdc89e63cc20ae1ff858ecbc857a84f83ab812286fb1f6dd099d44e254452f466d66569046de3cffe0ba9d7d4f52bb1717670a34c5398
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.19 2025-10-27
2
+
3
+ - Fix usage of `RAISE_IF_EXCEPTION` after `RB_GC_GUARD`
4
+
1
5
  # 0.18 2025-08-30
2
6
 
3
7
  - Fix `#write_async` to properly mark the given string
data/TODO.md CHANGED
@@ -16,7 +16,7 @@
16
16
  - splice / - tee
17
17
  - sendto
18
18
  - recvfrom
19
- - poll_add / poll_remove / poll_multishot / poll_update
19
+ - poll_multishot
20
20
  - fsync
21
21
  - mkdir / mkdirat
22
22
  - link / linkat / unlink / unlinkat / symlink
@@ -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 v = um_fiber_switch(machine);
256
- return raise_if_exception(v);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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
- raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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 raise_if_exception(ret);
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
- return raise_if_exception(ret);
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
- return raise_if_exception(ret);
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
- return raise_if_exception(ret);
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
- return raise_if_exception(ret);
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 raise_if_exception(v) (um_value_is_exception_p(v) ? um_raise_exception(v) : v)
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
- raise_if_exception(ret);
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;
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.18'
4
+ VERSION = '0.19'
5
5
  end
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.18'
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.6.9
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: []