uringmachine 0.19.1 → 0.20.0
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 +12 -1
- data/TODO.md +0 -1
- data/examples/bm_fileno.rb +33 -0
- data/examples/bm_mutex.rb +85 -0
- data/examples/bm_mutex_single.rb +33 -0
- data/examples/bm_queue.rb +27 -28
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/fiber_scheduler_demo.rb +15 -51
- data/examples/fiber_scheduler_fork.rb +24 -0
- data/examples/nc_ssl.rb +71 -0
- data/ext/um/extconf.rb +5 -15
- data/ext/um/um.c +57 -41
- data/ext/um/um.h +21 -11
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +94 -23
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_queue_class.c +1 -1
- data/ext/um/um_stream.c +5 -5
- data/ext/um/um_stream_class.c +3 -0
- data/ext/um/um_sync.c +22 -27
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +229 -0
- data/grant-2025/tasks.md +66 -0
- data/lib/uringmachine/fiber_scheduler.rb +180 -48
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +138 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +427 -34
- data/vendor/liburing/.github/workflows/ci.yml +94 -1
- data/vendor/liburing/.github/workflows/test_build.c +9 -0
- data/vendor/liburing/configure +27 -0
- data/vendor/liburing/examples/Makefile +6 -0
- data/vendor/liburing/examples/helpers.c +8 -0
- data/vendor/liburing/examples/helpers.h +5 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +9 -3
- data/vendor/liburing/src/include/liburing/barrier.h +11 -5
- data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
- data/vendor/liburing/src/include/liburing/io_uring.h +50 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +445 -121
- data/vendor/liburing/src/liburing-ffi.map +15 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/sanitize.c +4 -1
- data/vendor/liburing/src/setup.c +7 -4
- data/vendor/liburing/test/232c93d07b74.c +4 -16
- data/vendor/liburing/test/Makefile +15 -1
- data/vendor/liburing/test/accept.c +2 -13
- data/vendor/liburing/test/conn-unreach.c +132 -0
- data/vendor/liburing/test/fd-pass.c +32 -7
- data/vendor/liburing/test/fdinfo.c +39 -12
- data/vendor/liburing/test/fifo-futex-poll.c +114 -0
- data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
- data/vendor/liburing/test/futex.c +1 -1
- data/vendor/liburing/test/helpers.c +99 -2
- data/vendor/liburing/test/helpers.h +9 -0
- data/vendor/liburing/test/io_uring_passthrough.c +6 -12
- data/vendor/liburing/test/mock_file.c +379 -0
- data/vendor/liburing/test/mock_file.h +47 -0
- data/vendor/liburing/test/nop.c +2 -2
- data/vendor/liburing/test/nop32-overflow.c +150 -0
- data/vendor/liburing/test/nop32.c +126 -0
- data/vendor/liburing/test/pipe.c +166 -0
- data/vendor/liburing/test/poll-race-mshot.c +13 -1
- data/vendor/liburing/test/recv-mshot-fair.c +81 -34
- data/vendor/liburing/test/recvsend_bundle.c +1 -1
- data/vendor/liburing/test/resize-rings.c +2 -0
- data/vendor/liburing/test/ring-query.c +322 -0
- data/vendor/liburing/test/ringbuf-loop.c +87 -0
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +102 -32
- data/vendor/liburing/test/shutdown.c +2 -12
- data/vendor/liburing/test/socket-nb.c +3 -14
- data/vendor/liburing/test/socket-rw-eagain.c +2 -12
- data/vendor/liburing/test/socket-rw-offset.c +2 -12
- data/vendor/liburing/test/socket-rw.c +2 -12
- data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
- data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
- data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
- data/vendor/liburing/test/timestamp.c +56 -19
- data/vendor/liburing/test/vec-regbuf.c +2 -4
- data/vendor/liburing/test/wq-aff.c +7 -0
- metadata +24 -2
data/ext/um/um.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#include <float.h>
|
|
2
2
|
#include "um.h"
|
|
3
|
-
#include
|
|
3
|
+
#include <ruby/thread.h>
|
|
4
4
|
|
|
5
5
|
void um_setup(VALUE self, struct um *machine) {
|
|
6
6
|
memset(machine, 0, sizeof(struct um));
|
|
@@ -43,7 +43,7 @@ inline struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op) {
|
|
|
43
43
|
sqe = io_uring_get_sqe(&machine->ring);
|
|
44
44
|
if (likely(sqe)) goto done;
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
um_raise_internal_error("Failed to get SQE");
|
|
47
47
|
|
|
48
48
|
// TODO: retry getting SQE?
|
|
49
49
|
|
|
@@ -353,7 +353,7 @@ VALUE um_sleep(struct um *machine, double duration) {
|
|
|
353
353
|
return ret;
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
-
|
|
356
|
+
VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t buffer_offset) {
|
|
357
357
|
struct um_op op;
|
|
358
358
|
um_prep_op(machine, &op, OP_READ, 0);
|
|
359
359
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
@@ -366,14 +366,13 @@ inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int b
|
|
|
366
366
|
ret = INT2NUM(op.result.res);
|
|
367
367
|
|
|
368
368
|
}
|
|
369
|
-
RB_GC_GUARD(buffer);
|
|
370
369
|
|
|
371
370
|
RAISE_IF_EXCEPTION(ret);
|
|
372
371
|
RB_GC_GUARD(ret);
|
|
373
372
|
return ret;
|
|
374
373
|
}
|
|
375
374
|
|
|
376
|
-
|
|
375
|
+
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen) {
|
|
377
376
|
struct um_op op;
|
|
378
377
|
um_prep_op(machine, &op, OP_READ, 0);
|
|
379
378
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
@@ -390,38 +389,43 @@ inline size_t um_read_raw(struct um *machine, int fd, char *buffer, int maxlen)
|
|
|
390
389
|
return 0;
|
|
391
390
|
}
|
|
392
391
|
|
|
393
|
-
VALUE um_write(struct um *machine, int fd, VALUE
|
|
392
|
+
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len) {
|
|
394
393
|
struct um_op op;
|
|
395
394
|
um_prep_op(machine, &op, OP_WRITE, 0);
|
|
396
395
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
397
|
-
const int str_len = RSTRING_LEN(str);
|
|
398
|
-
if (len > str_len) len = str_len;
|
|
399
396
|
|
|
400
|
-
|
|
397
|
+
const void *base;
|
|
398
|
+
size_t size;
|
|
399
|
+
um_get_buffer_bytes_for_writing(buffer, &base, &size);
|
|
400
|
+
if ((len == (size_t)-1) || (len > size)) len = size;
|
|
401
|
+
|
|
402
|
+
io_uring_prep_write(sqe, fd, base, len, -1);
|
|
401
403
|
|
|
402
404
|
VALUE ret = um_fiber_switch(machine);
|
|
403
405
|
if (um_check_completion(machine, &op))
|
|
404
406
|
ret = INT2NUM(op.result.res);
|
|
405
407
|
|
|
406
|
-
RB_GC_GUARD(str);
|
|
407
|
-
|
|
408
408
|
RAISE_IF_EXCEPTION(ret);
|
|
409
409
|
RB_GC_GUARD(ret);
|
|
410
410
|
return ret;
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
VALUE um_write_async(struct um *machine, int fd, VALUE
|
|
413
|
+
VALUE um_write_async(struct um *machine, int fd, VALUE buffer) {
|
|
414
414
|
struct um_op *op = um_op_alloc(machine);
|
|
415
415
|
um_prep_op(machine, op, OP_WRITE_ASYNC, OP_F_TRANSIENT | OP_F_FREE_ON_COMPLETE);
|
|
416
416
|
RB_OBJ_WRITE(machine->self, &op->fiber, Qnil);
|
|
417
|
-
RB_OBJ_WRITE(machine->self, &op->value,
|
|
417
|
+
RB_OBJ_WRITE(machine->self, &op->value, buffer);
|
|
418
418
|
RB_OBJ_WRITE(machine->self, &op->async_op, Qnil);
|
|
419
419
|
|
|
420
|
+
const void *base;
|
|
421
|
+
size_t size;
|
|
422
|
+
um_get_buffer_bytes_for_writing(buffer, &base, &size);
|
|
423
|
+
|
|
420
424
|
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
421
|
-
io_uring_prep_write(sqe, fd,
|
|
425
|
+
io_uring_prep_write(sqe, fd, base, size, -1);
|
|
422
426
|
um_op_transient_add(machine, op);
|
|
423
427
|
|
|
424
|
-
return
|
|
428
|
+
return buffer;
|
|
425
429
|
}
|
|
426
430
|
|
|
427
431
|
VALUE um_close(struct um *machine, int fd) {
|
|
@@ -497,18 +501,22 @@ VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, sockle
|
|
|
497
501
|
return ret;
|
|
498
502
|
}
|
|
499
503
|
|
|
500
|
-
VALUE um_send(struct um *machine, int fd, VALUE buffer,
|
|
504
|
+
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags) {
|
|
501
505
|
struct um_op op;
|
|
502
506
|
um_prep_op(machine, &op, OP_SEND, 0);
|
|
503
507
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
504
|
-
|
|
508
|
+
|
|
509
|
+
const void *base;
|
|
510
|
+
size_t size;
|
|
511
|
+
um_get_buffer_bytes_for_writing(buffer, &base, &size);
|
|
512
|
+
if ((len == (size_t)-1) || (len > size)) len = size;
|
|
513
|
+
|
|
514
|
+
io_uring_prep_send(sqe, fd, base, len, flags);
|
|
505
515
|
|
|
506
516
|
VALUE ret = um_fiber_switch(machine);
|
|
507
517
|
if (um_check_completion(machine, &op))
|
|
508
518
|
ret = INT2NUM(op.result.res);
|
|
509
519
|
|
|
510
|
-
RB_GC_GUARD(buffer);
|
|
511
|
-
|
|
512
520
|
RAISE_IF_EXCEPTION(ret);
|
|
513
521
|
RB_GC_GUARD(ret);
|
|
514
522
|
return ret;
|
|
@@ -534,11 +542,12 @@ VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings) {
|
|
|
534
542
|
return ret;
|
|
535
543
|
}
|
|
536
544
|
|
|
537
|
-
VALUE um_recv(struct um *machine, int fd, VALUE buffer,
|
|
545
|
+
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags) {
|
|
538
546
|
struct um_op op;
|
|
539
547
|
um_prep_op(machine, &op, OP_RECV, 0);
|
|
540
548
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
541
549
|
void *ptr = um_prepare_read_buffer(buffer, maxlen, 0);
|
|
550
|
+
|
|
542
551
|
io_uring_prep_recv(sqe, fd, ptr, maxlen, flags);
|
|
543
552
|
|
|
544
553
|
VALUE ret = um_fiber_switch(machine);
|
|
@@ -547,8 +556,6 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags) {
|
|
|
547
556
|
ret = INT2NUM(op.result.res);
|
|
548
557
|
}
|
|
549
558
|
|
|
550
|
-
RB_GC_GUARD(buffer);
|
|
551
|
-
|
|
552
559
|
RAISE_IF_EXCEPTION(ret);
|
|
553
560
|
RB_GC_GUARD(ret);
|
|
554
561
|
return ret;
|
|
@@ -588,7 +595,6 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
|
588
595
|
VALUE ret = Qnil;
|
|
589
596
|
int value;
|
|
590
597
|
|
|
591
|
-
#ifdef HAVE_IO_URING_PREP_CMD_SOCK
|
|
592
598
|
struct um_op op;
|
|
593
599
|
um_prep_op(machine, &op, OP_GETSOCKOPT, 0);
|
|
594
600
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
@@ -597,13 +603,6 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
|
597
603
|
ret = um_fiber_switch(machine);
|
|
598
604
|
if (um_check_completion(machine, &op))
|
|
599
605
|
ret = INT2NUM(value);
|
|
600
|
-
#else
|
|
601
|
-
socklen_t nvalue = sizeof(value);
|
|
602
|
-
int res = getsockopt(fd, level, opt, &value, &nvalue);
|
|
603
|
-
if (res)
|
|
604
|
-
rb_syserr_fail(errno, strerror(errno));
|
|
605
|
-
ret = INT2NUM(value);
|
|
606
|
-
#endif
|
|
607
606
|
|
|
608
607
|
RAISE_IF_EXCEPTION(ret);
|
|
609
608
|
RB_GC_GUARD(ret);
|
|
@@ -613,7 +612,6 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt) {
|
|
|
613
612
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
614
613
|
VALUE ret = Qnil;
|
|
615
614
|
|
|
616
|
-
#ifdef HAVE_IO_URING_PREP_CMD_SOCK
|
|
617
615
|
struct um_op op;
|
|
618
616
|
um_prep_op(machine, &op, OP_SETSOCKOPT, 0);
|
|
619
617
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
@@ -622,12 +620,6 @@ VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value) {
|
|
|
622
620
|
ret = um_fiber_switch(machine);
|
|
623
621
|
if (um_check_completion(machine, &op))
|
|
624
622
|
ret = INT2NUM(op.result.res);
|
|
625
|
-
#else
|
|
626
|
-
int res = setsockopt(fd, level, opt, &value, sizeof(value));
|
|
627
|
-
if (res)
|
|
628
|
-
rb_syserr_fail(errno, strerror(errno));
|
|
629
|
-
ret = INT2NUM(0);
|
|
630
|
-
#endif
|
|
631
623
|
|
|
632
624
|
RAISE_IF_EXCEPTION(ret);
|
|
633
625
|
RB_GC_GUARD(ret);
|
|
@@ -694,13 +686,34 @@ VALUE um_poll(struct um *machine, int fd, unsigned mask) {
|
|
|
694
686
|
return ret;
|
|
695
687
|
}
|
|
696
688
|
|
|
697
|
-
VALUE
|
|
689
|
+
VALUE um_waitid(struct um *machine, int idtype, int id, int options) {
|
|
690
|
+
struct um_op op;
|
|
691
|
+
um_prep_op(machine, &op, OP_WAITID, 0);
|
|
692
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
693
|
+
|
|
694
|
+
siginfo_t infop;
|
|
695
|
+
io_uring_prep_waitid(sqe, idtype, id, &infop, options, 0);
|
|
696
|
+
|
|
697
|
+
VALUE ret = um_fiber_switch(machine);
|
|
698
|
+
if (um_check_completion(machine, &op))
|
|
699
|
+
ret = INT2NUM(op.result.res);
|
|
700
|
+
|
|
701
|
+
RAISE_IF_EXCEPTION(ret);
|
|
702
|
+
RB_GC_GUARD(ret);
|
|
703
|
+
|
|
704
|
+
return rb_ary_new_from_args(
|
|
705
|
+
3, INT2NUM(infop.si_pid), INT2NUM(infop.si_status), INT2NUM(infop.si_code)
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
VALUE um_waitid_status(struct um *machine, int idtype, int id, int options) {
|
|
710
|
+
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
698
711
|
struct um_op op;
|
|
699
|
-
um_prep_op(machine, &op,
|
|
712
|
+
um_prep_op(machine, &op, OP_WAITID, 0);
|
|
700
713
|
struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
|
|
701
714
|
|
|
702
715
|
siginfo_t infop;
|
|
703
|
-
io_uring_prep_waitid(sqe,
|
|
716
|
+
io_uring_prep_waitid(sqe, idtype, id, &infop, options | WNOWAIT, 0);
|
|
704
717
|
|
|
705
718
|
VALUE ret = um_fiber_switch(machine);
|
|
706
719
|
if (um_check_completion(machine, &op))
|
|
@@ -709,7 +722,10 @@ VALUE um_waitpid(struct um *machine, int pid, int options) {
|
|
|
709
722
|
RAISE_IF_EXCEPTION(ret);
|
|
710
723
|
RB_GC_GUARD(ret);
|
|
711
724
|
|
|
712
|
-
return
|
|
725
|
+
return rb_process_status_new(infop.si_pid, (infop.si_status & 0xff) << 8, 0);
|
|
726
|
+
#else
|
|
727
|
+
rb_raise(rb_eNotImpError, "Missing rb_process_status_new");
|
|
728
|
+
#endif
|
|
713
729
|
}
|
|
714
730
|
|
|
715
731
|
#define hash_set(h, sym, v) rb_hash_aset(h, ID2SYM(rb_intern(sym)), v)
|
data/ext/um/um.h
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
#define likely(cond) __builtin_expect(!!(cond), 1)
|
|
21
21
|
#endif
|
|
22
22
|
|
|
23
|
+
#define IO_BUFFER_P(buffer) \
|
|
24
|
+
(TYPE(buffer) == RUBY_T_DATA) && rb_obj_is_instance_of(buffer, rb_cIOBuffer)
|
|
25
|
+
|
|
23
26
|
enum op_kind {
|
|
24
27
|
OP_TIMEOUT,
|
|
25
28
|
OP_SCHEDULE,
|
|
@@ -47,7 +50,7 @@ enum op_kind {
|
|
|
47
50
|
OP_SHUTDOWN_ASYNC,
|
|
48
51
|
|
|
49
52
|
OP_POLL,
|
|
50
|
-
|
|
53
|
+
OP_WAITID,
|
|
51
54
|
|
|
52
55
|
OP_FUTEX_WAIT,
|
|
53
56
|
OP_FUTEX_WAKE,
|
|
@@ -131,6 +134,7 @@ struct um {
|
|
|
131
134
|
|
|
132
135
|
struct um_mutex {
|
|
133
136
|
uint32_t state;
|
|
137
|
+
uint32_t num_waiters;
|
|
134
138
|
};
|
|
135
139
|
|
|
136
140
|
struct um_queue_entry {
|
|
@@ -173,9 +177,11 @@ struct um_write_buffer {
|
|
|
173
177
|
};
|
|
174
178
|
|
|
175
179
|
extern VALUE cUM;
|
|
180
|
+
extern VALUE eUMError;
|
|
176
181
|
extern VALUE cMutex;
|
|
177
182
|
extern VALUE cQueue;
|
|
178
183
|
extern VALUE cAsyncOp;
|
|
184
|
+
extern VALUE eStreamRESPError;
|
|
179
185
|
|
|
180
186
|
struct um *um_get_machine(VALUE self);
|
|
181
187
|
void um_setup(VALUE self, struct um *machine);
|
|
@@ -208,8 +214,9 @@ VALUE um_raise_exception(VALUE v);
|
|
|
208
214
|
|
|
209
215
|
void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind, unsigned flags);
|
|
210
216
|
void um_raise_on_error_result(int result);
|
|
211
|
-
void
|
|
212
|
-
void
|
|
217
|
+
void um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size);
|
|
218
|
+
void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
|
|
219
|
+
void um_update_read_buffer(struct um *machine, VALUE buffer, ssize_t buffer_offset, __s32 result, __u32 flags);
|
|
213
220
|
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
|
|
214
221
|
VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
|
215
222
|
void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE strings);
|
|
@@ -229,25 +236,26 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
|
|
|
229
236
|
|
|
230
237
|
VALUE um_sleep(struct um *machine, double duration);
|
|
231
238
|
VALUE um_periodically(struct um *machine, double interval);
|
|
232
|
-
VALUE um_read(struct um *machine, int fd, VALUE buffer,
|
|
233
|
-
size_t um_read_raw(struct um *machine, int fd, char *buffer,
|
|
239
|
+
VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t buffer_offset);
|
|
240
|
+
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen);
|
|
234
241
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
|
235
|
-
VALUE um_write(struct um *machine, int fd, VALUE
|
|
242
|
+
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len);
|
|
243
|
+
VALUE um_write_async(struct um *machine, int fd, VALUE buffer);
|
|
236
244
|
VALUE um_close(struct um *machine, int fd);
|
|
237
245
|
VALUE um_close_async(struct um *machine, int fd);
|
|
238
246
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode);
|
|
239
247
|
VALUE um_poll(struct um *machine, int fd, unsigned mask);
|
|
240
|
-
VALUE
|
|
248
|
+
VALUE um_waitid(struct um *machine, int idtype, int id, int options);
|
|
249
|
+
VALUE um_waitid_status(struct um *machine, int idtype, int id, int options);
|
|
241
250
|
VALUE um_statx(struct um *machine, int dirfd, VALUE path, int flags, unsigned int mask);
|
|
242
|
-
VALUE um_write_async(struct um *machine, int fd, VALUE str);
|
|
243
251
|
|
|
244
252
|
VALUE um_accept(struct um *machine, int fd);
|
|
245
253
|
VALUE um_accept_each(struct um *machine, int fd);
|
|
246
254
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags);
|
|
247
255
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen);
|
|
248
|
-
VALUE um_send(struct um *machine, int fd, VALUE buffer,
|
|
256
|
+
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags);
|
|
249
257
|
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings);
|
|
250
|
-
VALUE um_recv(struct um *machine, int fd, VALUE buffer,
|
|
258
|
+
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags);
|
|
251
259
|
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags);
|
|
252
260
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen);
|
|
253
261
|
VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
@@ -266,7 +274,7 @@ struct um_mutex *Mutex_data(VALUE self);
|
|
|
266
274
|
struct um_queue *Queue_data(VALUE self);
|
|
267
275
|
|
|
268
276
|
void um_mutex_init(struct um_mutex *mutex);
|
|
269
|
-
VALUE um_mutex_synchronize(struct um *machine,
|
|
277
|
+
VALUE um_mutex_synchronize(struct um *machine, struct um_mutex *mutex);
|
|
270
278
|
|
|
271
279
|
void um_queue_init(struct um_queue *queue);
|
|
272
280
|
void um_queue_free(struct um_queue *queue);
|
|
@@ -282,6 +290,8 @@ VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
|
|
|
282
290
|
VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
|
|
283
291
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
|
284
292
|
|
|
293
|
+
__attribute__((noreturn)) void um_raise_internal_error(const char *msg);
|
|
294
|
+
|
|
285
295
|
void write_buffer_init(struct um_write_buffer *buf, VALUE str);
|
|
286
296
|
void write_buffer_update_len(struct um_write_buffer *buf);
|
|
287
297
|
|
data/ext/um/um_async_op_class.c
CHANGED
|
@@ -52,7 +52,7 @@ void um_async_op_set(VALUE self, struct um *machine, struct um_op *op) {
|
|
|
52
52
|
|
|
53
53
|
inline void raise_on_missing_op(struct um_async_op *async_op) {
|
|
54
54
|
if (!async_op->op)
|
|
55
|
-
|
|
55
|
+
um_raise_internal_error("Missing op");
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
inline int async_op_is_done(struct um_async_op *async_op) {
|
|
@@ -67,7 +67,7 @@ VALUE AsyncOp_kind(VALUE self) {
|
|
|
67
67
|
case OP_TIMEOUT:
|
|
68
68
|
return SYM_timeout;
|
|
69
69
|
default:
|
|
70
|
-
|
|
70
|
+
um_raise_internal_error("Invalid op kind");
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
data/ext/um/um_buffer.c
CHANGED
|
@@ -28,7 +28,7 @@ inline struct um_buffer *um_buffer_checkout(struct um *machine, int len) {
|
|
|
28
28
|
|
|
29
29
|
buffer->len = buffer_size(len);
|
|
30
30
|
if (posix_memalign(&buffer->ptr, 4096, buffer->len))
|
|
31
|
-
|
|
31
|
+
um_raise_internal_error("Failed to allocate buffer");
|
|
32
32
|
}
|
|
33
33
|
return buffer;
|
|
34
34
|
}
|
data/ext/um/um_class.c
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
#include "um.h"
|
|
2
2
|
#include <arpa/inet.h>
|
|
3
|
+
#include <ruby/io.h>
|
|
4
|
+
#include <sys/syscall.h>
|
|
5
|
+
#include <unistd.h>
|
|
3
6
|
|
|
4
7
|
VALUE cUM;
|
|
8
|
+
VALUE eUMError;
|
|
9
|
+
|
|
10
|
+
static ID id_fileno;
|
|
5
11
|
|
|
6
12
|
static void UM_mark(void *ptr) {
|
|
7
13
|
struct um *machine = ptr;
|
|
@@ -43,7 +49,7 @@ static VALUE UM_allocate(VALUE klass) {
|
|
|
43
49
|
inline struct um *um_get_machine(VALUE self) {
|
|
44
50
|
struct um *um;
|
|
45
51
|
TypedData_Get_Struct(self, struct um, &UringMachine_type, um);
|
|
46
|
-
if (!um->ring_initialized)
|
|
52
|
+
if (!um->ring_initialized) um_raise_internal_error("Machine not initialized");
|
|
47
53
|
|
|
48
54
|
return um;
|
|
49
55
|
}
|
|
@@ -103,21 +109,17 @@ VALUE UM_read(int argc, VALUE *argv, VALUE self) {
|
|
|
103
109
|
VALUE buffer;
|
|
104
110
|
VALUE maxlen;
|
|
105
111
|
VALUE buffer_offset;
|
|
106
|
-
rb_scan_args(argc, argv, "
|
|
112
|
+
rb_scan_args(argc, argv, "22", &fd, &buffer, &maxlen, &buffer_offset);
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
);
|
|
114
|
+
ssize_t maxlen_i = NIL_P(maxlen) ? -1 : NUM2INT(maxlen);
|
|
115
|
+
ssize_t buffer_offset_i = NIL_P(buffer_offset) ? 0 : NUM2INT(buffer_offset);
|
|
116
|
+
|
|
117
|
+
return um_read(machine, NUM2INT(fd), buffer, maxlen_i, buffer_offset_i);
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) {
|
|
115
|
-
#ifdef HAVE_IO_URING_PREP_READ_MULTISHOT
|
|
116
121
|
struct um *machine = um_get_machine(self);
|
|
117
122
|
return um_read_each(machine, NUM2INT(fd), NUM2INT(bgid));
|
|
118
|
-
#else
|
|
119
|
-
rb_raise(rb_eRuntimeError, "Not supported by kernel");
|
|
120
|
-
#endif
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
@@ -127,13 +129,13 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
|
127
129
|
VALUE len;
|
|
128
130
|
rb_scan_args(argc, argv, "21", &fd, &buffer, &len);
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
size_t bytes = NIL_P(len) ? (size_t)-1 : NUM2UINT(len);
|
|
131
133
|
return um_write(machine, NUM2INT(fd), buffer, bytes);
|
|
132
134
|
}
|
|
133
135
|
|
|
134
|
-
VALUE UM_write_async(VALUE self, VALUE fd, VALUE
|
|
136
|
+
VALUE UM_write_async(VALUE self, VALUE fd, VALUE buffer) {
|
|
135
137
|
struct um *machine = um_get_machine(self);
|
|
136
|
-
return um_write_async(machine, NUM2INT(fd),
|
|
138
|
+
return um_write_async(machine, NUM2INT(fd), buffer);
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
VALUE UM_statx(VALUE self, VALUE dirfd, VALUE path, VALUE flags, VALUE mask) {
|
|
@@ -270,12 +272,10 @@ VALUE UM_setsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt, VALUE value) {
|
|
|
270
272
|
return um_setsockopt(machine, NUM2INT(fd), NUM2INT(level), NUM2INT(opt), numeric_value(value));
|
|
271
273
|
}
|
|
272
274
|
|
|
273
|
-
#ifdef HAVE_IO_URING_PREP_FUTEX
|
|
274
|
-
|
|
275
275
|
VALUE UM_mutex_synchronize(VALUE self, VALUE mutex) {
|
|
276
276
|
struct um *machine = um_get_machine(self);
|
|
277
277
|
struct um_mutex *mutex_data = Mutex_data(mutex);
|
|
278
|
-
return um_mutex_synchronize(machine,
|
|
278
|
+
return um_mutex_synchronize(machine, mutex_data);
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
VALUE UM_queue_push(VALUE self, VALUE queue, VALUE value) {
|
|
@@ -302,8 +302,6 @@ VALUE UM_queue_shift(VALUE self, VALUE queue) {
|
|
|
302
302
|
return um_queue_shift(machine, que);
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
#endif
|
|
306
|
-
|
|
307
305
|
struct um_open_ctx {
|
|
308
306
|
VALUE self;
|
|
309
307
|
VALUE fd;
|
|
@@ -332,11 +330,18 @@ VALUE UM_poll(VALUE self, VALUE fd, VALUE mask) {
|
|
|
332
330
|
return um_poll(machine, NUM2INT(fd), NUM2UINT(mask));
|
|
333
331
|
}
|
|
334
332
|
|
|
335
|
-
VALUE
|
|
333
|
+
VALUE UM_waitid(VALUE self, VALUE idtype, VALUE id, VALUE options) {
|
|
336
334
|
struct um *machine = um_get_machine(self);
|
|
337
|
-
return
|
|
335
|
+
return um_waitid(machine, NUM2INT(idtype), NUM2INT(id), NUM2INT(options));
|
|
338
336
|
}
|
|
339
337
|
|
|
338
|
+
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
339
|
+
VALUE UM_waitid_status(VALUE self, VALUE idtype, VALUE id, VALUE options) {
|
|
340
|
+
struct um *machine = um_get_machine(self);
|
|
341
|
+
return um_waitid_status(machine, NUM2INT(idtype), NUM2INT(id), NUM2INT(options));
|
|
342
|
+
}
|
|
343
|
+
#endif
|
|
344
|
+
|
|
340
345
|
VALUE UM_prep_timeout(VALUE self, VALUE interval) {
|
|
341
346
|
struct um *machine = um_get_machine(self);
|
|
342
347
|
return um_prep_timeout(machine, NUM2DBL(interval));
|
|
@@ -353,10 +358,65 @@ VALUE UM_pipe(VALUE self) {
|
|
|
353
358
|
return rb_ary_new_from_args(2, INT2NUM(fds[0]), INT2NUM(fds[1]));
|
|
354
359
|
}
|
|
355
360
|
|
|
361
|
+
VALUE UM_pidfd_open(VALUE self, VALUE pid) {
|
|
362
|
+
int fd = syscall(SYS_pidfd_open, NUM2INT(pid), 0);
|
|
363
|
+
if (fd == -1) {
|
|
364
|
+
int e = errno;
|
|
365
|
+
rb_syserr_fail(e, strerror(e));
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return INT2NUM(fd);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
VALUE UM_pidfd_send_signal(VALUE self, VALUE fd, VALUE sig) {
|
|
372
|
+
int ret = syscall(
|
|
373
|
+
SYS_pidfd_send_signal, NUM2INT(fd), NUM2INT(sig), NULL, 0
|
|
374
|
+
);
|
|
375
|
+
if (ret) {
|
|
376
|
+
int e = errno;
|
|
377
|
+
rb_syserr_fail(e, strerror(e));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return fd;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
VALUE UM_io_nonblock_p(VALUE self, VALUE io) {
|
|
384
|
+
int fd = rb_io_descriptor(io);
|
|
385
|
+
int oflags = fcntl(fd, F_GETFL);
|
|
386
|
+
if (oflags == -1) return Qnil;
|
|
387
|
+
|
|
388
|
+
return (oflags & O_NONBLOCK) ? Qtrue : Qfalse;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
VALUE UM_io_set_nonblock(VALUE self, VALUE io, VALUE nonblock) {
|
|
392
|
+
int fd = rb_io_descriptor(io);
|
|
393
|
+
int oflags = fcntl(fd, F_GETFL);
|
|
394
|
+
if (oflags == -1) return Qnil;
|
|
395
|
+
|
|
396
|
+
if (RTEST(nonblock)) {
|
|
397
|
+
if (!(oflags & O_NONBLOCK)) {
|
|
398
|
+
oflags |= O_NONBLOCK;
|
|
399
|
+
fcntl(fd, F_SETFL, oflags);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
if (oflags & O_NONBLOCK) {
|
|
404
|
+
oflags &= ~O_NONBLOCK;
|
|
405
|
+
fcntl(fd, F_SETFL, oflags);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return nonblock;
|
|
409
|
+
}
|
|
410
|
+
|
|
356
411
|
VALUE UM_kernel_version(VALUE self) {
|
|
357
412
|
return INT2NUM(UM_KERNEL_VERSION);
|
|
358
413
|
}
|
|
359
414
|
|
|
415
|
+
VALUE UM_debug(VALUE self, VALUE str) {
|
|
416
|
+
printf("%s\n", StringValueCStr(str));
|
|
417
|
+
return Qnil;
|
|
418
|
+
}
|
|
419
|
+
|
|
360
420
|
void Init_UM(void) {
|
|
361
421
|
rb_ext_ractor_safe(true);
|
|
362
422
|
|
|
@@ -368,7 +428,13 @@ void Init_UM(void) {
|
|
|
368
428
|
rb_define_method(cUM, "setup_buffer_ring", UM_setup_buffer_ring, 2);
|
|
369
429
|
|
|
370
430
|
rb_define_singleton_method(cUM, "pipe", UM_pipe, 0);
|
|
431
|
+
rb_define_singleton_method(cUM, "pidfd_open", UM_pidfd_open, 1);
|
|
432
|
+
rb_define_singleton_method(cUM, "pidfd_send_signal", UM_pidfd_send_signal, 2);
|
|
433
|
+
|
|
434
|
+
rb_define_singleton_method(cUM, "io_nonblock?", UM_io_nonblock_p, 1);
|
|
435
|
+
rb_define_singleton_method(cUM, "io_set_nonblock", UM_io_set_nonblock, 2);
|
|
371
436
|
rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0);
|
|
437
|
+
rb_define_singleton_method(cUM, "debug", UM_debug, 1);
|
|
372
438
|
|
|
373
439
|
|
|
374
440
|
rb_define_method(cUM, "schedule", UM_schedule, 2);
|
|
@@ -388,7 +454,10 @@ void Init_UM(void) {
|
|
|
388
454
|
rb_define_method(cUM, "statx", UM_statx, 4);
|
|
389
455
|
|
|
390
456
|
rb_define_method(cUM, "poll", UM_poll, 2);
|
|
391
|
-
rb_define_method(cUM, "
|
|
457
|
+
rb_define_method(cUM, "waitid", UM_waitid, 3);
|
|
458
|
+
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
459
|
+
rb_define_method(cUM, "waitid_status", UM_waitid_status, 3);
|
|
460
|
+
#endif
|
|
392
461
|
|
|
393
462
|
rb_define_method(cUM, "accept", UM_accept, 1);
|
|
394
463
|
rb_define_method(cUM, "accept_each", UM_accept_each, 1);
|
|
@@ -407,13 +476,15 @@ void Init_UM(void) {
|
|
|
407
476
|
|
|
408
477
|
rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
|
|
409
478
|
|
|
410
|
-
#ifdef HAVE_IO_URING_PREP_FUTEX
|
|
411
479
|
rb_define_method(cUM, "pop", UM_queue_pop, 1);
|
|
412
480
|
rb_define_method(cUM, "push", UM_queue_push, 2);
|
|
413
481
|
rb_define_method(cUM, "shift", UM_queue_shift, 1);
|
|
414
482
|
rb_define_method(cUM, "synchronize", UM_mutex_synchronize, 1);
|
|
415
483
|
rb_define_method(cUM, "unshift", UM_queue_unshift, 2);
|
|
416
|
-
|
|
484
|
+
|
|
485
|
+
eUMError = rb_define_class_under(cUM, "Error", rb_eStandardError);
|
|
417
486
|
|
|
418
487
|
um_define_net_constants(cUM);
|
|
488
|
+
|
|
489
|
+
id_fileno = rb_intern_const("fileno");
|
|
419
490
|
}
|
data/ext/um/um_const.c
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
#include <netdb.h>
|
|
14
14
|
#include <net/if.h>
|
|
15
15
|
#include <poll.h>
|
|
16
|
+
#include <signal.h>
|
|
16
17
|
|
|
17
18
|
#define DEF_CONST_INT(mod, v) rb_define_const(mod, #v, INT2NUM(v))
|
|
18
19
|
|
|
@@ -88,12 +89,12 @@ void um_define_net_constants(VALUE mod) {
|
|
|
88
89
|
DEF_CONST_INT(mod, O_TRUNC);
|
|
89
90
|
DEF_CONST_INT(mod, O_WRONLY);
|
|
90
91
|
|
|
91
|
-
DEF_CONST_INT(mod, WNOHANG);
|
|
92
|
-
DEF_CONST_INT(mod, WUNTRACED);
|
|
93
92
|
DEF_CONST_INT(mod, WCONTINUED);
|
|
94
93
|
DEF_CONST_INT(mod, WEXITED);
|
|
95
|
-
DEF_CONST_INT(mod,
|
|
94
|
+
DEF_CONST_INT(mod, WNOHANG);
|
|
96
95
|
DEF_CONST_INT(mod, WNOWAIT);
|
|
96
|
+
DEF_CONST_INT(mod, WSTOPPED);
|
|
97
|
+
DEF_CONST_INT(mod, WUNTRACED);
|
|
97
98
|
|
|
98
99
|
DEF_CONST_INT(mod, SOCK_STREAM);
|
|
99
100
|
DEF_CONST_INT(mod, SOCK_DGRAM);
|
|
@@ -391,4 +392,51 @@ void um_define_net_constants(VALUE mod) {
|
|
|
391
392
|
DEF_CONST_INT(mod, EKEYREJECTED);
|
|
392
393
|
DEF_CONST_INT(mod, EOWNERDEAD);
|
|
393
394
|
DEF_CONST_INT(mod, ENOTRECOVERABLE);
|
|
395
|
+
|
|
396
|
+
DEF_CONST_INT(mod, P_PID);
|
|
397
|
+
DEF_CONST_INT(mod, P_PIDFD);
|
|
398
|
+
DEF_CONST_INT(mod, P_PGID);
|
|
399
|
+
DEF_CONST_INT(mod, P_ALL);
|
|
400
|
+
|
|
401
|
+
DEF_CONST_INT(mod, CLD_EXITED);
|
|
402
|
+
DEF_CONST_INT(mod, CLD_KILLED);
|
|
403
|
+
DEF_CONST_INT(mod, CLD_DUMPED);
|
|
404
|
+
DEF_CONST_INT(mod, CLD_STOPPED);
|
|
405
|
+
DEF_CONST_INT(mod, CLD_TRAPPED);
|
|
406
|
+
DEF_CONST_INT(mod, CLD_CONTINUED);
|
|
407
|
+
|
|
408
|
+
DEF_CONST_INT(mod, SIGHUP);
|
|
409
|
+
DEF_CONST_INT(mod, SIGINT);
|
|
410
|
+
DEF_CONST_INT(mod, SIGQUIT);
|
|
411
|
+
DEF_CONST_INT(mod, SIGILL);
|
|
412
|
+
DEF_CONST_INT(mod, SIGTRAP);
|
|
413
|
+
DEF_CONST_INT(mod, SIGABRT);
|
|
414
|
+
DEF_CONST_INT(mod, SIGIOT);
|
|
415
|
+
DEF_CONST_INT(mod, SIGFPE);
|
|
416
|
+
DEF_CONST_INT(mod, SIGKILL);
|
|
417
|
+
DEF_CONST_INT(mod, SIGBUS);
|
|
418
|
+
DEF_CONST_INT(mod, SIGSEGV);
|
|
419
|
+
DEF_CONST_INT(mod, SIGSYS);
|
|
420
|
+
DEF_CONST_INT(mod, SIGPIPE);
|
|
421
|
+
DEF_CONST_INT(mod, SIGALRM);
|
|
422
|
+
DEF_CONST_INT(mod, SIGTERM);
|
|
423
|
+
DEF_CONST_INT(mod, SIGURG);
|
|
424
|
+
DEF_CONST_INT(mod, SIGSTOP);
|
|
425
|
+
DEF_CONST_INT(mod, SIGTSTP);
|
|
426
|
+
DEF_CONST_INT(mod, SIGCONT);
|
|
427
|
+
DEF_CONST_INT(mod, SIGCHLD);
|
|
428
|
+
DEF_CONST_INT(mod, SIGCLD);
|
|
429
|
+
DEF_CONST_INT(mod, SIGTTIN);
|
|
430
|
+
DEF_CONST_INT(mod, SIGTTOU);
|
|
431
|
+
DEF_CONST_INT(mod, SIGIO);
|
|
432
|
+
DEF_CONST_INT(mod, SIGXCPU);
|
|
433
|
+
DEF_CONST_INT(mod, SIGXFSZ);
|
|
434
|
+
DEF_CONST_INT(mod, SIGVTALRM);
|
|
435
|
+
DEF_CONST_INT(mod, SIGPROF);
|
|
436
|
+
DEF_CONST_INT(mod, SIGWINCH);
|
|
437
|
+
DEF_CONST_INT(mod, SIGUSR1);
|
|
438
|
+
DEF_CONST_INT(mod, SIGUSR2);
|
|
439
|
+
DEF_CONST_INT(mod, SIGPWR);
|
|
440
|
+
DEF_CONST_INT(mod, SIGPOLL);
|
|
441
|
+
|
|
394
442
|
}
|
data/ext/um/um_mutex_class.c
CHANGED
|
@@ -11,7 +11,7 @@ static const rb_data_type_t Mutex_type = {
|
|
|
11
11
|
.dsize = NULL,
|
|
12
12
|
.dcompact = NULL
|
|
13
13
|
},
|
|
14
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
14
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
static VALUE Mutex_allocate(VALUE klass) {
|
data/ext/um/um_queue_class.c
CHANGED
|
@@ -26,7 +26,7 @@ static const rb_data_type_t Queue_type = {
|
|
|
26
26
|
.dsize = NULL,
|
|
27
27
|
.dcompact = Queue_compact
|
|
28
28
|
},
|
|
29
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
29
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
static VALUE Queue_allocate(VALUE klass) {
|