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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bce8525371c9f0aa2b279b815d04456573319b3eddaae14b79ddbf20ece1189f
4
- data.tar.gz: dc1e70ca4101d607f2c04df639dabc917c379e3765a12c5440682a72cbb24316
3
+ metadata.gz: 1b3778bbf3b35b2f0855c5fdbe441df909a43866c56ceed16cacf502956566ba
4
+ data.tar.gz: 82b580cb610c11d5d05e69ab868ba70265fec92851cbdca7cf340bbde09c0b2c
5
5
  SHA512:
6
- metadata.gz: 258605dfe54482f5330a7795e18efa3397692b0a306cf7fd1ad6a2408fe8c7e098abca78d66baaddd78faac74aae6beeda9fe6a3d2e39ab4e196b585810bc212
7
- data.tar.gz: 6110908bf2c3d8a404f015429835dfb585ae711f14457b785d7e298f6caf2449341ca62ab3fa560054f51c9de6031195e8ead20afabace47cfe24cdf9fd6ae48
6
+ metadata.gz: 82fbdc455e76bd1adaf4668ae0d43c8c1e84f9c168c1d3e2f7a4924e672d5b77617ce720ac6fcb9257cc8e8edcf419f4267acdd7128d72a5d03c0b808f85ab4b
7
+ data.tar.gz: d56ba947a2d6ba974faa7e0594b506e0f7520815a995e263a7a9acf0658b73c057bd7d13f32e035376a4871dea6ff7824d04a621957707cb56a6f7e92581af1d
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 2025-06-24 Version 0.15
2
+
3
+ - Add support for sleeping forever when sleep duration is lte 0
4
+
5
+ # 2025-06-09 Version 0.14
6
+
7
+ - Add `#close_async`, `#shutdown_async`
8
+
1
9
  # 2025-06-07 Version 0.13
2
10
 
3
11
  - Add `#write_async`
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
- switch (kind) {
259
- case OP_ACCEPT_MULTISHOT:
260
- case OP_READ_MULTISHOT:
261
- case OP_RECV_MULTISHOT:
262
- case OP_TIMEOUT_MULTISHOT:
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
- memset(op, 0, sizeof(struct um_op));
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(
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.13'
4
+ VERSION = '0.15'
5
5
  end
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
- return results.values if !pending
39
-
40
- while !pending.empty?
41
- f = self.shift(queue)
42
- pending.delete(f)
43
- results[f] = f.result
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 [42], res
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 [:foo], res
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
- res = machine.join(f)
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
- 2.times { machine.snooze }
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
- class ShutdownTest < UMBaseTest
575
- def make_socket_pair
576
- port = 10000 + rand(30000)
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
- client_conn_fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
583
- @machine.connect(client_conn_fd, '127.0.0.1', port)
597
+ assert_raises(Errno::EBADF) { machine.close(w.fileno) }
598
+ end
599
+ end
584
600
 
585
- server_conn_fd = @machine.accept(server_fd)
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
- @machine.close(server_fd)
588
- [client_conn_fd, server_conn_fd]
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
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.13'
4
+ version: '0.15'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner