uringmachine 0.19.1 → 0.21.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/.github/workflows/test.yml +3 -4
- data/CHANGELOG.md +32 -1
- data/TODO.md +0 -39
- 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 +29 -29
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/bm_write.rb +4 -1
- 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 +310 -74
- data/ext/um/um.h +66 -29
- data/ext/um/um_async_op.c +1 -1
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +178 -31
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_op.c +37 -0
- 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 +28 -39
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +353 -0
- data/grant-2025/tasks.md +135 -0
- data/lib/uringmachine/fiber_scheduler.rb +316 -57
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +640 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +722 -54
- data/uringmachine.gemspec +5 -5
- 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 +51 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +458 -121
- data/vendor/liburing/src/liburing-ffi.map +16 -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/bind-listen.c +175 -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/read-write.c +4 -4
- 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/ringbuf-read.c +4 -4
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +103 -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 +37 -15
data/ext/um/um.h
CHANGED
|
@@ -4,12 +4,20 @@
|
|
|
4
4
|
#include <ruby.h>
|
|
5
5
|
#include <liburing.h>
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
// debugging
|
|
9
|
+
enum {
|
|
10
|
+
// set to 1 to enable debug logging
|
|
11
|
+
DEBUG = 0
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
#define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
|
|
9
15
|
#define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf(": %s\n", StringValueCStr(s)); }
|
|
10
16
|
#define CALLER() rb_funcall(rb_mKernel, rb_intern("caller"), 0)
|
|
11
17
|
#define TRACE_CALLER() INSPECT("caller: ", CALLER())
|
|
12
18
|
#define TRACE_FREE(ptr) //printf("Free %p %s:%d\n", ptr, __FILE__, __LINE__)
|
|
19
|
+
#define DEBUG_MARK(machine, markv, msg) \
|
|
20
|
+
if (machine->mark == markv) printf("%s\n", msg);
|
|
13
21
|
|
|
14
22
|
// branching
|
|
15
23
|
#ifndef unlikely
|
|
@@ -20,7 +28,10 @@
|
|
|
20
28
|
#define likely(cond) __builtin_expect(!!(cond), 1)
|
|
21
29
|
#endif
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
#define IO_BUFFER_P(buffer) \
|
|
32
|
+
(TYPE(buffer) == RUBY_T_DATA) && rb_obj_is_instance_of(buffer, rb_cIOBuffer)
|
|
33
|
+
|
|
34
|
+
enum um_op_kind {
|
|
24
35
|
OP_TIMEOUT,
|
|
25
36
|
OP_SCHEDULE,
|
|
26
37
|
|
|
@@ -47,7 +58,7 @@ enum op_kind {
|
|
|
47
58
|
OP_SHUTDOWN_ASYNC,
|
|
48
59
|
|
|
49
60
|
OP_POLL,
|
|
50
|
-
|
|
61
|
+
OP_WAITID,
|
|
51
62
|
|
|
52
63
|
OP_FUTEX_WAIT,
|
|
53
64
|
OP_FUTEX_WAKE,
|
|
@@ -59,12 +70,17 @@ enum op_kind {
|
|
|
59
70
|
OP_SLEEP_MULTISHOT
|
|
60
71
|
};
|
|
61
72
|
|
|
62
|
-
#define OP_F_COMPLETED (1U <<
|
|
63
|
-
#define OP_F_TRANSIENT (1U <<
|
|
64
|
-
#define OP_F_ASYNC (1U <<
|
|
65
|
-
#define
|
|
66
|
-
#define
|
|
67
|
-
#define
|
|
73
|
+
#define OP_F_COMPLETED (1U << 0) // op is completed (set on each CQE for multishot ops)
|
|
74
|
+
#define OP_F_TRANSIENT (1U << 1) // op is heap allocated
|
|
75
|
+
#define OP_F_ASYNC (1U << 2) // op belongs to an AsyncOp
|
|
76
|
+
#define OP_F_CANCELED (1U << 3) // op is cancelled
|
|
77
|
+
#define OP_F_IGNORE_CANCELED (1U << 4) // CQE with -ECANCEL should be ignored
|
|
78
|
+
#define OP_F_MULTISHOT (1U << 5) // op is multishot
|
|
79
|
+
#define OP_F_FREE_ON_COMPLETE (1U << 6) // op should be freed on receiving CQE
|
|
80
|
+
#define OP_F_RUNQUEUE_SKIP (1U << 7) // runqueue entry should be skipped
|
|
81
|
+
#define OP_F_SELECT_POLLIN (1U << 8) // select POLLIN
|
|
82
|
+
#define OP_F_SELECT_POLLOUT (1U << 9) // select POLLOUT
|
|
83
|
+
#define OP_F_SELECT_POLLPRI (1U << 10) // select POLLPRI
|
|
68
84
|
|
|
69
85
|
struct um_op_result {
|
|
70
86
|
__s32 res;
|
|
@@ -76,8 +92,8 @@ struct um_op {
|
|
|
76
92
|
struct um_op *prev;
|
|
77
93
|
struct um_op *next;
|
|
78
94
|
|
|
79
|
-
enum
|
|
80
|
-
|
|
95
|
+
enum um_op_kind kind;
|
|
96
|
+
uint flags;
|
|
81
97
|
|
|
82
98
|
VALUE fiber;
|
|
83
99
|
VALUE value;
|
|
@@ -85,7 +101,7 @@ struct um_op {
|
|
|
85
101
|
|
|
86
102
|
struct um_op_result result;
|
|
87
103
|
struct um_op_result *multishot_result_tail;
|
|
88
|
-
|
|
104
|
+
uint multishot_result_count;
|
|
89
105
|
|
|
90
106
|
struct __kernel_timespec ts; // used for timeout operation
|
|
91
107
|
};
|
|
@@ -114,12 +130,18 @@ struct um {
|
|
|
114
130
|
|
|
115
131
|
struct io_uring ring;
|
|
116
132
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
133
|
+
uint ring_initialized; // is the ring initialized successfully
|
|
134
|
+
uint mark; // used to mark instances for debugging
|
|
135
|
+
|
|
136
|
+
uint unsubmitted_count; // number of unsubmitted SQEs pending
|
|
137
|
+
uint pending_count; // number of pending operations (i.e. not yet completed)
|
|
138
|
+
uint buffer_ring_count; // number of registered buffer rings
|
|
139
|
+
ulong total_op_count; // total number of operations submitted since ring was initialized
|
|
140
|
+
|
|
141
|
+
uint entries; // number of entries in SQ
|
|
142
|
+
uint sqpoll_mode; // SQPOLL mode enabled
|
|
120
143
|
|
|
121
144
|
struct buf_ring_descriptor buffer_rings[BUFFER_RING_MAX_COUNT];
|
|
122
|
-
unsigned int buffer_ring_count;
|
|
123
145
|
|
|
124
146
|
struct um_op *transient_head;
|
|
125
147
|
struct um_op *runqueue_head;
|
|
@@ -131,6 +153,7 @@ struct um {
|
|
|
131
153
|
|
|
132
154
|
struct um_mutex {
|
|
133
155
|
uint32_t state;
|
|
156
|
+
uint32_t num_waiters;
|
|
134
157
|
};
|
|
135
158
|
|
|
136
159
|
struct um_queue_entry {
|
|
@@ -173,14 +196,17 @@ struct um_write_buffer {
|
|
|
173
196
|
};
|
|
174
197
|
|
|
175
198
|
extern VALUE cUM;
|
|
199
|
+
extern VALUE eUMError;
|
|
176
200
|
extern VALUE cMutex;
|
|
177
201
|
extern VALUE cQueue;
|
|
178
202
|
extern VALUE cAsyncOp;
|
|
203
|
+
extern VALUE eStreamRESPError;
|
|
179
204
|
|
|
180
205
|
struct um *um_get_machine(VALUE self);
|
|
181
|
-
void um_setup(VALUE self, struct um *machine);
|
|
206
|
+
void um_setup(VALUE self, struct um *machine, uint entries, uint sqpoll_timeout_msec);
|
|
182
207
|
void um_teardown(struct um *machine);
|
|
183
208
|
|
|
209
|
+
const char * um_op_kind_name(enum um_op_kind kind);
|
|
184
210
|
struct um_op *um_op_alloc(struct um *machine);
|
|
185
211
|
void um_op_free(struct um *machine, struct um_op *op);
|
|
186
212
|
void um_op_clear(struct um *machine, struct um_op *op);
|
|
@@ -204,21 +230,24 @@ double um_timestamp_to_double(__s64 tv_sec, __u32 tv_nsec);
|
|
|
204
230
|
int um_value_is_exception_p(VALUE v);
|
|
205
231
|
VALUE um_raise_exception(VALUE v);
|
|
206
232
|
|
|
207
|
-
#define RAISE_IF_EXCEPTION(v) if (um_value_is_exception_p(v)) { um_raise_exception(v); }
|
|
233
|
+
#define RAISE_IF_EXCEPTION(v) if (unlikely(um_value_is_exception_p(v))) { um_raise_exception(v); }
|
|
208
234
|
|
|
209
|
-
void um_prep_op(struct um *machine, struct um_op *op, enum
|
|
235
|
+
void um_prep_op(struct um *machine, struct um_op *op, enum um_op_kind kind, unsigned flags);
|
|
210
236
|
void um_raise_on_error_result(int result);
|
|
211
|
-
void
|
|
212
|
-
void
|
|
237
|
+
void um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size);
|
|
238
|
+
void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
|
|
239
|
+
void um_update_read_buffer(struct um *machine, VALUE buffer, ssize_t buffer_offset, __s32 result, __u32 flags);
|
|
213
240
|
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
|
|
214
241
|
VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
|
215
242
|
void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE strings);
|
|
216
243
|
|
|
217
244
|
struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op);
|
|
218
245
|
|
|
246
|
+
uint um_submit(struct um *machine);
|
|
219
247
|
VALUE um_fiber_switch(struct um *machine);
|
|
220
248
|
VALUE um_await(struct um *machine);
|
|
221
|
-
|
|
249
|
+
VALUE um_wakeup(struct um *machine);
|
|
250
|
+
void um_cancel_op(struct um *machine, struct um_op *op);
|
|
222
251
|
void um_cancel_and_wait(struct um *machine, struct um_op *op);
|
|
223
252
|
int um_check_completion(struct um *machine, struct um_op *op);
|
|
224
253
|
|
|
@@ -229,25 +258,31 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
|
|
|
229
258
|
|
|
230
259
|
VALUE um_sleep(struct um *machine, double duration);
|
|
231
260
|
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,
|
|
261
|
+
VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t buffer_offset, __u64 file_offset);
|
|
262
|
+
size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen);
|
|
234
263
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
|
235
|
-
VALUE um_write(struct um *machine, int fd, VALUE
|
|
264
|
+
VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
265
|
+
VALUE um_write_async(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
|
|
236
266
|
VALUE um_close(struct um *machine, int fd);
|
|
237
267
|
VALUE um_close_async(struct um *machine, int fd);
|
|
238
268
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode);
|
|
239
269
|
VALUE um_poll(struct um *machine, int fd, unsigned mask);
|
|
240
|
-
VALUE
|
|
270
|
+
VALUE um_select(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds);
|
|
271
|
+
VALUE um_waitid(struct um *machine, int idtype, int id, int options);
|
|
272
|
+
|
|
273
|
+
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
274
|
+
VALUE um_waitid_status(struct um *machine, int idtype, int id, int options);
|
|
275
|
+
#endif
|
|
276
|
+
|
|
241
277
|
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
278
|
|
|
244
279
|
VALUE um_accept(struct um *machine, int fd);
|
|
245
280
|
VALUE um_accept_each(struct um *machine, int fd);
|
|
246
281
|
VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint flags);
|
|
247
282
|
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,
|
|
283
|
+
VALUE um_send(struct um *machine, int fd, VALUE buffer, size_t len, int flags);
|
|
249
284
|
VALUE um_send_bundle(struct um *machine, int fd, int bgid, VALUE strings);
|
|
250
|
-
VALUE um_recv(struct um *machine, int fd, VALUE buffer,
|
|
285
|
+
VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags);
|
|
251
286
|
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags);
|
|
252
287
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen);
|
|
253
288
|
VALUE um_listen(struct um *machine, int fd, int backlog);
|
|
@@ -266,7 +301,7 @@ struct um_mutex *Mutex_data(VALUE self);
|
|
|
266
301
|
struct um_queue *Queue_data(VALUE self);
|
|
267
302
|
|
|
268
303
|
void um_mutex_init(struct um_mutex *mutex);
|
|
269
|
-
VALUE um_mutex_synchronize(struct um *machine,
|
|
304
|
+
VALUE um_mutex_synchronize(struct um *machine, struct um_mutex *mutex);
|
|
270
305
|
|
|
271
306
|
void um_queue_init(struct um_queue *queue);
|
|
272
307
|
void um_queue_free(struct um_queue *queue);
|
|
@@ -282,6 +317,8 @@ VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
|
|
|
282
317
|
VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
|
|
283
318
|
void resp_encode(struct um_write_buffer *buf, VALUE obj);
|
|
284
319
|
|
|
320
|
+
__attribute__((noreturn)) void um_raise_internal_error(const char *msg);
|
|
321
|
+
|
|
285
322
|
void write_buffer_init(struct um_write_buffer *buf, VALUE str);
|
|
286
323
|
void write_buffer_update_len(struct um_write_buffer *buf);
|
|
287
324
|
|
data/ext/um/um_async_op.c
CHANGED
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,14 +49,38 @@ 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
|
}
|
|
50
56
|
|
|
51
|
-
|
|
57
|
+
static inline uint get_sqpoll_timeout_msec(VALUE sqpoll_timeout) {
|
|
58
|
+
switch (TYPE(sqpoll_timeout)) {
|
|
59
|
+
case T_NIL:
|
|
60
|
+
case T_FALSE:
|
|
61
|
+
return 0;
|
|
62
|
+
case T_FLOAT:
|
|
63
|
+
return (uint)(NUM2DBL(sqpoll_timeout) * 1000);
|
|
64
|
+
case T_FIXNUM:
|
|
65
|
+
return NUM2UINT(sqpoll_timeout) * 1000;
|
|
66
|
+
case T_TRUE:
|
|
67
|
+
return 1000;
|
|
68
|
+
default:
|
|
69
|
+
rb_raise(eUMError, "Invalid sqpoll_timeout value");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
VALUE UM_initialize(int argc, VALUE *argv, VALUE self) {
|
|
52
74
|
struct um *machine = RTYPEDDATA_DATA(self);
|
|
53
|
-
|
|
75
|
+
VALUE entries;
|
|
76
|
+
VALUE sqpoll_timeout;
|
|
77
|
+
rb_scan_args(argc, argv, "02", &entries, &sqpoll_timeout);
|
|
78
|
+
|
|
79
|
+
uint entries_i = NIL_P(entries) ? 0 : NUM2UINT(entries);
|
|
80
|
+
uint sqpoll_timeout_msec = get_sqpoll_timeout_msec(sqpoll_timeout);
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
um_setup(self, machine, entries_i, sqpoll_timeout_msec);
|
|
54
84
|
return self;
|
|
55
85
|
}
|
|
56
86
|
|
|
@@ -60,9 +90,25 @@ VALUE UM_setup_buffer_ring(VALUE self, VALUE size, VALUE count) {
|
|
|
60
90
|
return INT2NUM(bgid);
|
|
61
91
|
}
|
|
62
92
|
|
|
93
|
+
VALUE UM_entries(VALUE self) {
|
|
94
|
+
struct um *machine = um_get_machine(self);
|
|
95
|
+
return UINT2NUM(machine->entries);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
VALUE UM_mark_m(VALUE self, VALUE mark) {
|
|
99
|
+
struct um *machine = um_get_machine(self);
|
|
100
|
+
machine->mark = NUM2UINT(mark);
|
|
101
|
+
return self;
|
|
102
|
+
}
|
|
103
|
+
|
|
63
104
|
VALUE UM_pending_count(VALUE self) {
|
|
64
105
|
struct um *machine = um_get_machine(self);
|
|
65
|
-
return
|
|
106
|
+
return UINT2NUM(machine->pending_count);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
VALUE UM_total_op_count(VALUE self) {
|
|
110
|
+
struct um *machine = um_get_machine(self);
|
|
111
|
+
return UINT2NUM(machine->total_op_count);
|
|
66
112
|
}
|
|
67
113
|
|
|
68
114
|
VALUE UM_snooze(VALUE self) {
|
|
@@ -76,6 +122,17 @@ VALUE UM_yield(VALUE self) {
|
|
|
76
122
|
return um_await(machine);
|
|
77
123
|
}
|
|
78
124
|
|
|
125
|
+
VALUE UM_wakeup(VALUE self) {
|
|
126
|
+
struct um *machine = um_get_machine(self);
|
|
127
|
+
return um_wakeup(machine);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
VALUE UM_submit(VALUE self) {
|
|
131
|
+
struct um *machine = um_get_machine(self);
|
|
132
|
+
uint ret = um_submit(machine);
|
|
133
|
+
return UINT2NUM(ret);
|
|
134
|
+
}
|
|
135
|
+
|
|
79
136
|
VALUE UM_schedule(VALUE self, VALUE fiber, VALUE value) {
|
|
80
137
|
struct um *machine = um_get_machine(self);
|
|
81
138
|
um_schedule(machine, fiber, value);
|
|
@@ -103,21 +160,19 @@ VALUE UM_read(int argc, VALUE *argv, VALUE self) {
|
|
|
103
160
|
VALUE buffer;
|
|
104
161
|
VALUE maxlen;
|
|
105
162
|
VALUE buffer_offset;
|
|
106
|
-
|
|
163
|
+
VALUE file_offset;
|
|
164
|
+
rb_scan_args(argc, argv, "23", &fd, &buffer, &maxlen, &buffer_offset, &file_offset);
|
|
107
165
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
166
|
+
ssize_t maxlen_i = NIL_P(maxlen) ? -1 : NUM2INT(maxlen);
|
|
167
|
+
ssize_t buffer_offset_i = NIL_P(buffer_offset) ? 0 : NUM2INT(buffer_offset);
|
|
168
|
+
__u64 file_offset_i = NIL_P(file_offset) ? (__u64)-1 : NUM2UINT(file_offset);
|
|
169
|
+
|
|
170
|
+
return um_read(machine, NUM2INT(fd), buffer, maxlen_i, buffer_offset_i, file_offset_i);
|
|
112
171
|
}
|
|
113
172
|
|
|
114
173
|
VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) {
|
|
115
|
-
#ifdef HAVE_IO_URING_PREP_READ_MULTISHOT
|
|
116
174
|
struct um *machine = um_get_machine(self);
|
|
117
175
|
return um_read_each(machine, NUM2INT(fd), NUM2INT(bgid));
|
|
118
|
-
#else
|
|
119
|
-
rb_raise(rb_eRuntimeError, "Not supported by kernel");
|
|
120
|
-
#endif
|
|
121
176
|
}
|
|
122
177
|
|
|
123
178
|
VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
@@ -125,15 +180,27 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
|
125
180
|
VALUE fd;
|
|
126
181
|
VALUE buffer;
|
|
127
182
|
VALUE len;
|
|
128
|
-
|
|
183
|
+
VALUE file_offset;
|
|
184
|
+
rb_scan_args(argc, argv, "22", &fd, &buffer, &len, &file_offset);
|
|
185
|
+
|
|
186
|
+
size_t len_i = NIL_P(len) ? (size_t)-1 : NUM2UINT(len);
|
|
187
|
+
__u64 file_offset_i = NIL_P(file_offset) ? (__u64)-1 : NUM2UINT(file_offset);
|
|
129
188
|
|
|
130
|
-
|
|
131
|
-
return um_write(machine, NUM2INT(fd), buffer, bytes);
|
|
189
|
+
return um_write(machine, NUM2INT(fd), buffer, len_i, file_offset_i);
|
|
132
190
|
}
|
|
133
191
|
|
|
134
|
-
VALUE UM_write_async(
|
|
192
|
+
VALUE UM_write_async(int argc, VALUE *argv, VALUE self) {
|
|
135
193
|
struct um *machine = um_get_machine(self);
|
|
136
|
-
|
|
194
|
+
VALUE fd;
|
|
195
|
+
VALUE buffer;
|
|
196
|
+
VALUE len;
|
|
197
|
+
VALUE file_offset;
|
|
198
|
+
rb_scan_args(argc, argv, "22", &fd, &buffer, &len, &file_offset);
|
|
199
|
+
|
|
200
|
+
size_t len_i = NIL_P(len) ? (size_t)-1 : NUM2UINT(len);
|
|
201
|
+
__u64 file_offset_i = NIL_P(file_offset) ? (__u64)-1 : NUM2UINT(file_offset);
|
|
202
|
+
|
|
203
|
+
return um_write_async(machine, NUM2INT(fd), buffer, len_i, file_offset_i);
|
|
137
204
|
}
|
|
138
205
|
|
|
139
206
|
VALUE UM_statx(VALUE self, VALUE dirfd, VALUE path, VALUE flags, VALUE mask) {
|
|
@@ -270,12 +337,10 @@ VALUE UM_setsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt, VALUE value) {
|
|
|
270
337
|
return um_setsockopt(machine, NUM2INT(fd), NUM2INT(level), NUM2INT(opt), numeric_value(value));
|
|
271
338
|
}
|
|
272
339
|
|
|
273
|
-
#ifdef HAVE_IO_URING_PREP_FUTEX
|
|
274
|
-
|
|
275
340
|
VALUE UM_mutex_synchronize(VALUE self, VALUE mutex) {
|
|
276
341
|
struct um *machine = um_get_machine(self);
|
|
277
342
|
struct um_mutex *mutex_data = Mutex_data(mutex);
|
|
278
|
-
return um_mutex_synchronize(machine,
|
|
343
|
+
return um_mutex_synchronize(machine, mutex_data);
|
|
279
344
|
}
|
|
280
345
|
|
|
281
346
|
VALUE UM_queue_push(VALUE self, VALUE queue, VALUE value) {
|
|
@@ -302,8 +367,6 @@ VALUE UM_queue_shift(VALUE self, VALUE queue) {
|
|
|
302
367
|
return um_queue_shift(machine, que);
|
|
303
368
|
}
|
|
304
369
|
|
|
305
|
-
#endif
|
|
306
|
-
|
|
307
370
|
struct um_open_ctx {
|
|
308
371
|
VALUE self;
|
|
309
372
|
VALUE fd;
|
|
@@ -332,10 +395,22 @@ VALUE UM_poll(VALUE self, VALUE fd, VALUE mask) {
|
|
|
332
395
|
return um_poll(machine, NUM2INT(fd), NUM2UINT(mask));
|
|
333
396
|
}
|
|
334
397
|
|
|
335
|
-
VALUE
|
|
398
|
+
VALUE UM_select(VALUE self, VALUE rfds, VALUE wfds, VALUE efds) {
|
|
399
|
+
struct um *machine = um_get_machine(self);
|
|
400
|
+
return um_select(machine, rfds, wfds, efds);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
VALUE UM_waitid(VALUE self, VALUE idtype, VALUE id, VALUE options) {
|
|
404
|
+
struct um *machine = um_get_machine(self);
|
|
405
|
+
return um_waitid(machine, NUM2INT(idtype), NUM2INT(id), NUM2INT(options));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
409
|
+
VALUE UM_waitid_status(VALUE self, VALUE idtype, VALUE id, VALUE options) {
|
|
336
410
|
struct um *machine = um_get_machine(self);
|
|
337
|
-
return
|
|
411
|
+
return um_waitid_status(machine, NUM2INT(idtype), NUM2INT(id), NUM2INT(options));
|
|
338
412
|
}
|
|
413
|
+
#endif
|
|
339
414
|
|
|
340
415
|
VALUE UM_prep_timeout(VALUE self, VALUE interval) {
|
|
341
416
|
struct um *machine = um_get_machine(self);
|
|
@@ -353,28 +428,93 @@ VALUE UM_pipe(VALUE self) {
|
|
|
353
428
|
return rb_ary_new_from_args(2, INT2NUM(fds[0]), INT2NUM(fds[1]));
|
|
354
429
|
}
|
|
355
430
|
|
|
431
|
+
VALUE UM_pidfd_open(VALUE self, VALUE pid) {
|
|
432
|
+
int fd = syscall(SYS_pidfd_open, NUM2INT(pid), 0);
|
|
433
|
+
if (fd == -1) {
|
|
434
|
+
int e = errno;
|
|
435
|
+
rb_syserr_fail(e, strerror(e));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
return INT2NUM(fd);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
VALUE UM_pidfd_send_signal(VALUE self, VALUE fd, VALUE sig) {
|
|
442
|
+
int ret = syscall(
|
|
443
|
+
SYS_pidfd_send_signal, NUM2INT(fd), NUM2INT(sig), NULL, 0
|
|
444
|
+
);
|
|
445
|
+
if (ret) {
|
|
446
|
+
int e = errno;
|
|
447
|
+
rb_syserr_fail(e, strerror(e));
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return fd;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
VALUE UM_io_nonblock_p(VALUE self, VALUE io) {
|
|
454
|
+
int fd = rb_io_descriptor(io);
|
|
455
|
+
int oflags = fcntl(fd, F_GETFL);
|
|
456
|
+
if (oflags == -1) return Qnil;
|
|
457
|
+
|
|
458
|
+
return (oflags & O_NONBLOCK) ? Qtrue : Qfalse;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
VALUE UM_io_set_nonblock(VALUE self, VALUE io, VALUE nonblock) {
|
|
462
|
+
int fd = rb_io_descriptor(io);
|
|
463
|
+
int oflags = fcntl(fd, F_GETFL);
|
|
464
|
+
if (oflags == -1) return Qnil;
|
|
465
|
+
|
|
466
|
+
if (RTEST(nonblock)) {
|
|
467
|
+
if (!(oflags & O_NONBLOCK)) {
|
|
468
|
+
oflags |= O_NONBLOCK;
|
|
469
|
+
fcntl(fd, F_SETFL, oflags);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
if (oflags & O_NONBLOCK) {
|
|
474
|
+
oflags &= ~O_NONBLOCK;
|
|
475
|
+
fcntl(fd, F_SETFL, oflags);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
return nonblock;
|
|
479
|
+
}
|
|
480
|
+
|
|
356
481
|
VALUE UM_kernel_version(VALUE self) {
|
|
357
482
|
return INT2NUM(UM_KERNEL_VERSION);
|
|
358
483
|
}
|
|
359
484
|
|
|
485
|
+
VALUE UM_debug(VALUE self, VALUE str) {
|
|
486
|
+
printf("%s\n", StringValueCStr(str));
|
|
487
|
+
return Qnil;
|
|
488
|
+
}
|
|
489
|
+
|
|
360
490
|
void Init_UM(void) {
|
|
361
491
|
rb_ext_ractor_safe(true);
|
|
362
492
|
|
|
363
493
|
cUM = rb_define_class("UringMachine", rb_cObject);
|
|
364
494
|
rb_define_alloc_func(cUM, UM_allocate);
|
|
365
495
|
|
|
366
|
-
rb_define_method(cUM, "initialize", UM_initialize,
|
|
496
|
+
rb_define_method(cUM, "initialize", UM_initialize, -1);
|
|
497
|
+
rb_define_method(cUM, "entries", UM_entries, 0);
|
|
498
|
+
rb_define_method(cUM, "mark", UM_mark_m, 1);
|
|
367
499
|
rb_define_method(cUM, "pending_count", UM_pending_count, 0);
|
|
500
|
+
rb_define_method(cUM, "total_op_count", UM_total_op_count, 0);
|
|
368
501
|
rb_define_method(cUM, "setup_buffer_ring", UM_setup_buffer_ring, 2);
|
|
369
502
|
|
|
370
503
|
rb_define_singleton_method(cUM, "pipe", UM_pipe, 0);
|
|
371
|
-
rb_define_singleton_method(cUM, "
|
|
504
|
+
rb_define_singleton_method(cUM, "pidfd_open", UM_pidfd_open, 1);
|
|
505
|
+
rb_define_singleton_method(cUM, "pidfd_send_signal", UM_pidfd_send_signal, 2);
|
|
372
506
|
|
|
507
|
+
rb_define_singleton_method(cUM, "io_nonblock?", UM_io_nonblock_p, 1);
|
|
508
|
+
rb_define_singleton_method(cUM, "io_set_nonblock", UM_io_set_nonblock, 2);
|
|
509
|
+
rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0);
|
|
510
|
+
rb_define_singleton_method(cUM, "debug", UM_debug, 1);
|
|
373
511
|
|
|
374
512
|
rb_define_method(cUM, "schedule", UM_schedule, 2);
|
|
375
513
|
rb_define_method(cUM, "snooze", UM_snooze, 0);
|
|
376
514
|
rb_define_method(cUM, "timeout", UM_timeout, 2);
|
|
377
515
|
rb_define_method(cUM, "yield", UM_yield, 0);
|
|
516
|
+
rb_define_method(cUM, "wakeup", UM_wakeup, 0);
|
|
517
|
+
rb_define_method(cUM, "submit", UM_submit, 0);
|
|
378
518
|
|
|
379
519
|
rb_define_method(cUM, "close", UM_close, 1);
|
|
380
520
|
rb_define_method(cUM, "close_async", UM_close_async, 1);
|
|
@@ -384,11 +524,16 @@ void Init_UM(void) {
|
|
|
384
524
|
rb_define_method(cUM, "sleep", UM_sleep, 1);
|
|
385
525
|
rb_define_method(cUM, "periodically", UM_periodically, 1);
|
|
386
526
|
rb_define_method(cUM, "write", UM_write, -1);
|
|
387
|
-
rb_define_method(cUM, "write_async", UM_write_async,
|
|
527
|
+
rb_define_method(cUM, "write_async", UM_write_async, -1);
|
|
388
528
|
rb_define_method(cUM, "statx", UM_statx, 4);
|
|
389
529
|
|
|
390
530
|
rb_define_method(cUM, "poll", UM_poll, 2);
|
|
391
|
-
rb_define_method(cUM, "
|
|
531
|
+
rb_define_method(cUM, "select", UM_select, 3);
|
|
532
|
+
rb_define_method(cUM, "waitid", UM_waitid, 3);
|
|
533
|
+
|
|
534
|
+
#ifdef HAVE_RB_PROCESS_STATUS_NEW
|
|
535
|
+
rb_define_method(cUM, "waitid_status", UM_waitid_status, 3);
|
|
536
|
+
#endif
|
|
392
537
|
|
|
393
538
|
rb_define_method(cUM, "accept", UM_accept, 1);
|
|
394
539
|
rb_define_method(cUM, "accept_each", UM_accept_each, 1);
|
|
@@ -407,13 +552,15 @@ void Init_UM(void) {
|
|
|
407
552
|
|
|
408
553
|
rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
|
|
409
554
|
|
|
410
|
-
#ifdef HAVE_IO_URING_PREP_FUTEX
|
|
411
555
|
rb_define_method(cUM, "pop", UM_queue_pop, 1);
|
|
412
556
|
rb_define_method(cUM, "push", UM_queue_push, 2);
|
|
413
557
|
rb_define_method(cUM, "shift", UM_queue_shift, 1);
|
|
414
558
|
rb_define_method(cUM, "synchronize", UM_mutex_synchronize, 1);
|
|
415
559
|
rb_define_method(cUM, "unshift", UM_queue_unshift, 2);
|
|
416
|
-
|
|
560
|
+
|
|
561
|
+
eUMError = rb_define_class_under(cUM, "Error", rb_eStandardError);
|
|
417
562
|
|
|
418
563
|
um_define_net_constants(cUM);
|
|
564
|
+
|
|
565
|
+
id_fileno = rb_intern_const("fileno");
|
|
419
566
|
}
|
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) {
|