uringmachine 0.4 → 0.5.1
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 +2 -1
- data/CHANGELOG.md +16 -0
- data/README.md +44 -1
- data/TODO.md +12 -3
- data/examples/bm_snooze.rb +89 -0
- data/examples/bm_sqlite.rb +89 -0
- data/examples/bm_write.rb +56 -0
- data/examples/dns_client.rb +12 -0
- data/examples/http_server.rb +42 -43
- data/examples/pg.rb +85 -0
- data/examples/server_client.rb +64 -0
- data/examples/snooze.rb +44 -0
- data/examples/stream.rb +85 -0
- data/examples/write_dev_null.rb +16 -0
- data/ext/um/extconf.rb +81 -14
- data/ext/um/um.c +468 -414
- data/ext/um/um.h +149 -40
- data/ext/um/um_async_op.c +40 -0
- data/ext/um/um_async_op_class.c +136 -0
- data/ext/um/um_buffer.c +49 -0
- data/ext/um/um_class.c +176 -44
- data/ext/um/um_const.c +174 -9
- data/ext/um/um_ext.c +8 -0
- data/ext/um/um_mutex_class.c +47 -0
- data/ext/um/um_op.c +89 -111
- data/ext/um/um_queue_class.c +58 -0
- data/ext/um/um_ssl.c +850 -0
- data/ext/um/um_ssl.h +22 -0
- data/ext/um/um_ssl_class.c +138 -0
- data/ext/um/um_sync.c +273 -0
- data/ext/um/um_utils.c +1 -1
- data/lib/uringmachine/dns_resolver.rb +84 -0
- data/lib/uringmachine/ssl/context_builder.rb +96 -0
- data/lib/uringmachine/ssl.rb +394 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +27 -3
- data/supressions/ruby.supp +71 -0
- data/test/helper.rb +6 -0
- data/test/test_async_op.rb +119 -0
- data/test/test_ssl.rb +155 -0
- data/test/test_um.rb +464 -47
- data/uringmachine.gemspec +3 -2
- data/vendor/liburing/.gitignore +5 -0
- data/vendor/liburing/CHANGELOG +1 -0
- data/vendor/liburing/configure +32 -0
- data/vendor/liburing/examples/Makefile +1 -0
- data/vendor/liburing/examples/reg-wait.c +159 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +48 -2
- data/vendor/liburing/src/include/liburing.h +28 -2
- data/vendor/liburing/src/int_flags.h +10 -3
- data/vendor/liburing/src/liburing-ffi.map +13 -2
- data/vendor/liburing/src/liburing.map +9 -0
- data/vendor/liburing/src/queue.c +25 -16
- data/vendor/liburing/src/register.c +73 -4
- data/vendor/liburing/src/setup.c +46 -18
- data/vendor/liburing/src/setup.h +6 -0
- data/vendor/liburing/test/Makefile +7 -0
- data/vendor/liburing/test/cmd-discard.c +427 -0
- data/vendor/liburing/test/fifo-nonblock-read.c +69 -0
- data/vendor/liburing/test/file-exit-unreg.c +48 -0
- data/vendor/liburing/test/io_uring_passthrough.c +2 -0
- data/vendor/liburing/test/io_uring_register.c +13 -2
- data/vendor/liburing/test/napi-test.c +1 -1
- data/vendor/liburing/test/no-mmap-inval.c +1 -1
- data/vendor/liburing/test/read-mshot-empty.c +2 -0
- data/vendor/liburing/test/read-mshot-stdin.c +121 -0
- data/vendor/liburing/test/read-mshot.c +6 -0
- data/vendor/liburing/test/recvsend_bundle.c +2 -2
- data/vendor/liburing/test/reg-fd-only.c +1 -1
- data/vendor/liburing/test/reg-wait.c +251 -0
- data/vendor/liburing/test/regbuf-clone.c +458 -0
- data/vendor/liburing/test/resize-rings.c +643 -0
- data/vendor/liburing/test/rsrc_tags.c +1 -1
- data/vendor/liburing/test/sqpoll-sleep.c +39 -8
- data/vendor/liburing/test/sqwait.c +136 -0
- data/vendor/liburing/test/sync-cancel.c +8 -1
- data/vendor/liburing/test/timeout.c +13 -8
- metadata +52 -8
- data/examples/http_server_multishot.rb +0 -57
- data/examples/http_server_simpler.rb +0 -34
data/ext/um/um.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#ifndef UM_H
|
2
2
|
#define UM_H
|
3
3
|
|
4
|
-
#include
|
4
|
+
#include <ruby.h>
|
5
5
|
#include <liburing.h>
|
6
6
|
|
7
7
|
// debugging
|
@@ -20,38 +20,66 @@
|
|
20
20
|
#define likely(cond) __builtin_expect(!!(cond), 1)
|
21
21
|
#endif
|
22
22
|
|
23
|
-
enum
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
23
|
+
enum op_kind {
|
24
|
+
OP_TIMEOUT,
|
25
|
+
OP_SCHEDULE,
|
26
|
+
|
27
|
+
OP_SLEEP,
|
28
|
+
OP_READ,
|
29
|
+
OP_WRITE,
|
30
|
+
OP_CLOSE,
|
31
|
+
OP_ACCEPT,
|
32
|
+
OP_RECV,
|
33
|
+
OP_SEND,
|
34
|
+
OP_SOCKET,
|
35
|
+
OP_CONNECT,
|
36
|
+
OP_BIND,
|
37
|
+
OP_LISTEN,
|
38
|
+
OP_GETSOCKOPT,
|
39
|
+
OP_SETSOCKOPT,
|
40
|
+
|
41
|
+
OP_FUTEX_WAIT,
|
42
|
+
OP_FUTEX_WAKE,
|
43
|
+
|
44
|
+
OP_ACCEPT_MULTISHOT,
|
45
|
+
OP_READ_MULTISHOT,
|
46
|
+
OP_RECV_MULTISHOT
|
30
47
|
};
|
31
48
|
|
32
|
-
|
33
|
-
|
49
|
+
#define OP_F_COMPLETED (1U << 0)
|
50
|
+
#define OP_F_TRANSIENT (1U << 1)
|
51
|
+
#define OP_F_ASYNC (1U << 2)
|
52
|
+
#define OP_F_IGNORE_CANCELED (1U << 3)
|
53
|
+
#define OP_F_MULTISHOT (1U << 4)
|
34
54
|
|
35
|
-
|
55
|
+
struct um_op_result {
|
56
|
+
__s32 res;
|
36
57
|
__u32 flags;
|
58
|
+
struct um_op_result *next;
|
37
59
|
};
|
38
60
|
|
39
61
|
struct um_op {
|
40
|
-
enum op_state state;
|
41
62
|
struct um_op *prev;
|
42
63
|
struct um_op *next;
|
43
64
|
|
44
|
-
|
45
|
-
|
46
|
-
struct um_result_entry *results_tail;
|
65
|
+
enum op_kind kind;
|
66
|
+
unsigned flags;
|
47
67
|
|
48
68
|
VALUE fiber;
|
49
|
-
VALUE
|
50
|
-
|
51
|
-
struct __kernel_timespec ts;
|
69
|
+
VALUE value;
|
70
|
+
VALUE async_op;
|
52
71
|
|
53
|
-
|
54
|
-
|
72
|
+
struct um_op_result result;
|
73
|
+
struct um_op_result *multishot_result_tail;
|
74
|
+
unsigned multishot_result_count;
|
75
|
+
|
76
|
+
struct __kernel_timespec ts; // used for timeout operation
|
77
|
+
};
|
78
|
+
|
79
|
+
struct um_buffer {
|
80
|
+
struct um_buffer *next;
|
81
|
+
void *ptr;
|
82
|
+
long len;
|
55
83
|
};
|
56
84
|
|
57
85
|
struct buf_ring_descriptor {
|
@@ -66,11 +94,9 @@ struct buf_ring_descriptor {
|
|
66
94
|
#define BUFFER_RING_MAX_COUNT 10
|
67
95
|
|
68
96
|
struct um {
|
69
|
-
|
70
|
-
struct um_result_entry *result_freelist;
|
97
|
+
VALUE self;
|
71
98
|
|
72
|
-
struct
|
73
|
-
struct um_op *runqueue_tail;
|
99
|
+
struct um_buffer *buffer_freelist;
|
74
100
|
|
75
101
|
struct io_uring ring;
|
76
102
|
|
@@ -80,48 +106,105 @@ struct um {
|
|
80
106
|
|
81
107
|
struct buf_ring_descriptor buffer_rings[BUFFER_RING_MAX_COUNT];
|
82
108
|
unsigned int buffer_ring_count;
|
109
|
+
|
110
|
+
struct um_op *transient_head;
|
111
|
+
struct um_op *runqueue_head;
|
112
|
+
struct um_op *runqueue_tail;
|
113
|
+
|
114
|
+
struct um_op *op_freelist;
|
115
|
+
struct um_op_result *result_freelist;
|
116
|
+
};
|
117
|
+
|
118
|
+
struct um_mutex {
|
119
|
+
VALUE self;
|
120
|
+
uint32_t state;
|
121
|
+
};
|
122
|
+
|
123
|
+
struct um_queue_entry {
|
124
|
+
struct um_queue_entry *prev;
|
125
|
+
struct um_queue_entry *next;
|
126
|
+
VALUE value;
|
127
|
+
};
|
128
|
+
|
129
|
+
struct um_queue {
|
130
|
+
VALUE self;
|
131
|
+
|
132
|
+
struct um_queue_entry *head;
|
133
|
+
struct um_queue_entry *tail;
|
134
|
+
struct um_queue_entry *free_head;
|
135
|
+
|
136
|
+
uint32_t num_waiters;
|
137
|
+
uint32_t state;
|
138
|
+
uint32_t count;
|
139
|
+
};
|
140
|
+
|
141
|
+
struct um_async_op {
|
142
|
+
VALUE self;
|
143
|
+
|
144
|
+
struct um *machine;
|
145
|
+
struct um_op *op;
|
83
146
|
};
|
84
147
|
|
85
148
|
extern VALUE cUM;
|
149
|
+
extern VALUE cMutex;
|
150
|
+
extern VALUE cQueue;
|
151
|
+
extern VALUE cAsyncOp;
|
86
152
|
|
87
|
-
|
153
|
+
struct um *um_get_machine(VALUE self);
|
154
|
+
void um_setup(VALUE self, struct um *machine);
|
88
155
|
void um_teardown(struct um *machine);
|
89
|
-
|
90
|
-
|
156
|
+
|
157
|
+
struct um_op *um_op_alloc(struct um *machine);
|
158
|
+
void um_op_free(struct um *machine, struct um_op *op);
|
159
|
+
void um_op_clear(struct um *machine, struct um_op *op);
|
160
|
+
void um_op_transient_add(struct um *machine, struct um_op *op);
|
161
|
+
void um_op_transient_remove(struct um *machine, struct um_op *op);
|
162
|
+
void um_op_list_mark(struct um *machine, struct um_op *head);
|
163
|
+
void um_op_list_compact(struct um *machine, struct um_op *head);
|
164
|
+
|
165
|
+
void um_op_multishot_results_push(struct um *machine, struct um_op *op, __s32 res, __u32 flags);
|
166
|
+
void um_op_multishot_results_clear(struct um *machine, struct um_op *op);
|
167
|
+
|
168
|
+
void um_runqueue_push(struct um *machine, struct um_op *op);
|
169
|
+
struct um_op *um_runqueue_shift(struct um *machine);
|
170
|
+
|
171
|
+
struct um_buffer *um_buffer_checkout(struct um *machine, int len);
|
172
|
+
void um_buffer_checkin(struct um *machine, struct um_buffer *buffer);
|
173
|
+
void um_free_buffer_linked_list(struct um *machine);
|
91
174
|
|
92
175
|
struct __kernel_timespec um_double_to_timespec(double value);
|
93
176
|
int um_value_is_exception_p(VALUE v);
|
94
177
|
VALUE um_raise_exception(VALUE v);
|
95
|
-
void um_raise_on_system_error(int result);
|
96
178
|
|
179
|
+
#define raise_if_exception(v) (um_value_is_exception_p(v) ? um_raise_exception(v) : v)
|
180
|
+
|
181
|
+
void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind);
|
182
|
+
void um_raise_on_error_result(int result);
|
97
183
|
void * um_prepare_read_buffer(VALUE buffer, unsigned len, int ofs);
|
98
184
|
void um_update_read_buffer(struct um *machine, VALUE buffer, int buffer_offset, __s32 result, __u32 flags);
|
99
|
-
|
100
185
|
int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
|
101
186
|
VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
|
102
187
|
|
188
|
+
struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op);
|
189
|
+
|
103
190
|
VALUE um_fiber_switch(struct um *machine);
|
104
191
|
VALUE um_await(struct um *machine);
|
192
|
+
void um_submit_cancel_op(struct um *machine, struct um_op *op);
|
193
|
+
void um_cancel_and_wait(struct um *machine, struct um_op *op);
|
194
|
+
int um_check_completion(struct um *machine, struct um_op *op);
|
105
195
|
|
106
|
-
|
107
|
-
struct um_op* um_op_checkout(struct um *machine);
|
108
|
-
void um_op_result_push(struct um *machine, struct um_op *op, __s32 result, __u32 flags);
|
109
|
-
int um_op_result_shift(struct um *machine, struct um_op *op, __s32 *result, __u32 *flags);
|
110
|
-
|
111
|
-
struct um_op *um_runqueue_find_by_fiber(struct um *machine, VALUE fiber);
|
112
|
-
void um_runqueue_push(struct um *machine, struct um_op *op);
|
113
|
-
struct um_op *um_runqueue_shift(struct um *machine);
|
114
|
-
void um_runqueue_unshift(struct um *machine, struct um_op *op);
|
196
|
+
#define um_op_completed_p(op) ((op)->flags & OP_F_COMPLETED)
|
115
197
|
|
116
198
|
void um_schedule(struct um *machine, VALUE fiber, VALUE value);
|
117
|
-
void um_interrupt(struct um *machine, VALUE fiber, VALUE value);
|
118
199
|
VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
|
119
200
|
|
120
201
|
VALUE um_sleep(struct um *machine, double duration);
|
121
202
|
VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset);
|
122
203
|
VALUE um_read_each(struct um *machine, int fd, int bgid);
|
123
|
-
VALUE um_write(struct um *machine, int fd, VALUE
|
204
|
+
VALUE um_write(struct um *machine, int fd, VALUE str, int len);
|
124
205
|
VALUE um_close(struct um *machine, int fd);
|
206
|
+
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode);
|
207
|
+
VALUE um_waitpid(struct um *machine, int pid, int options);
|
125
208
|
|
126
209
|
VALUE um_accept(struct um *machine, int fd);
|
127
210
|
VALUE um_accept_each(struct um *machine, int fd);
|
@@ -129,9 +212,35 @@ VALUE um_socket(struct um *machine, int domain, int type, int protocol, uint fla
|
|
129
212
|
VALUE um_connect(struct um *machine, int fd, const struct sockaddr *addr, socklen_t addrlen);
|
130
213
|
VALUE um_send(struct um *machine, int fd, VALUE buffer, int len, int flags);
|
131
214
|
VALUE um_recv(struct um *machine, int fd, VALUE buffer, int maxlen, int flags);
|
215
|
+
VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags);
|
132
216
|
VALUE um_bind(struct um *machine, int fd, struct sockaddr *addr, socklen_t addrlen);
|
133
217
|
VALUE um_listen(struct um *machine, int fd, int backlog);
|
218
|
+
VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
|
219
|
+
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
|
220
|
+
|
221
|
+
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
|
222
|
+
VALUE um_async_op_await(struct um_async_op *async_op);
|
223
|
+
void um_async_op_cancel(struct um_async_op *async_op);
|
224
|
+
|
225
|
+
VALUE um_prep_timeout(struct um *machine, double interval);
|
226
|
+
|
227
|
+
struct um_mutex *Mutex_data(VALUE self);
|
228
|
+
struct um_queue *Queue_data(VALUE self);
|
229
|
+
|
230
|
+
void um_mutex_init(struct um_mutex *mutex);
|
231
|
+
VALUE um_mutex_synchronize(struct um *machine, uint32_t *state);
|
232
|
+
|
233
|
+
void um_queue_init(struct um_queue *queue);
|
234
|
+
void um_queue_free(struct um_queue *queue);
|
235
|
+
void um_queue_mark(struct um_queue *queue);
|
236
|
+
void um_queue_compact(struct um_queue *queue);
|
237
|
+
VALUE um_queue_push(struct um *machine, struct um_queue *queue, VALUE value);
|
238
|
+
VALUE um_queue_pop(struct um *machine, struct um_queue *queue);
|
239
|
+
VALUE um_queue_unshift(struct um *machine, struct um_queue *queue, VALUE value);
|
240
|
+
VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
|
134
241
|
|
135
242
|
void um_define_net_constants(VALUE mod);
|
136
243
|
|
244
|
+
// void Init_micro_ssl(VALUE mod);
|
245
|
+
|
137
246
|
#endif // UM_H
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
VALUE um_prep_timeout(struct um *machine, double interval) {
|
5
|
+
static ID ID_new = 0;
|
6
|
+
if (!ID_new) ID_new = rb_intern("new");
|
7
|
+
|
8
|
+
struct um_op *op = malloc(sizeof(struct um_op));
|
9
|
+
um_prep_op(machine, op, OP_TIMEOUT);
|
10
|
+
op->ts = um_double_to_timespec(interval);
|
11
|
+
op->flags = OP_F_TRANSIENT | OP_F_ASYNC;
|
12
|
+
|
13
|
+
VALUE obj = rb_funcall(cAsyncOp, rb_intern_const("new"), 0);
|
14
|
+
um_async_op_set(obj, machine, op);
|
15
|
+
|
16
|
+
RB_OBJ_WRITE(machine->self, &op->async_op, obj);
|
17
|
+
|
18
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
19
|
+
io_uring_prep_timeout(sqe, &op->ts, 0, 0);
|
20
|
+
|
21
|
+
um_op_transient_add(machine, op);
|
22
|
+
|
23
|
+
return obj;
|
24
|
+
}
|
25
|
+
|
26
|
+
VALUE um_async_op_await(struct um_async_op *async_op) {
|
27
|
+
RB_OBJ_WRITE(async_op->machine->self, &async_op->op->fiber, rb_fiber_current());
|
28
|
+
async_op->op->flags &= ~OP_F_ASYNC;
|
29
|
+
|
30
|
+
VALUE ret = um_fiber_switch(async_op->machine);
|
31
|
+
if (!um_op_completed_p(async_op->op))
|
32
|
+
um_cancel_and_wait(async_op->machine, async_op->op);
|
33
|
+
|
34
|
+
raise_if_exception(ret);
|
35
|
+
return INT2NUM(async_op->op->result.res);
|
36
|
+
}
|
37
|
+
|
38
|
+
void um_async_op_cancel(struct um_async_op *async_op) {
|
39
|
+
um_submit_cancel_op(async_op->machine, async_op->op);
|
40
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
#include <stdlib.h>
|
3
|
+
|
4
|
+
VALUE cAsyncOp;
|
5
|
+
|
6
|
+
VALUE SYM_timeout;
|
7
|
+
|
8
|
+
static void AsyncOp_mark(void *ptr) {
|
9
|
+
struct um_async_op *async_op = ptr;
|
10
|
+
rb_gc_mark_movable(async_op->self);
|
11
|
+
rb_gc_mark_movable(async_op->machine->self);
|
12
|
+
}
|
13
|
+
|
14
|
+
static void AsyncOp_compact(void *ptr) {
|
15
|
+
struct um_async_op *async_op = ptr;
|
16
|
+
async_op->self = rb_gc_location(async_op->self);
|
17
|
+
}
|
18
|
+
|
19
|
+
static size_t AsyncOp_size(const void *ptr) {
|
20
|
+
return sizeof(struct um_async_op);
|
21
|
+
}
|
22
|
+
|
23
|
+
static void AsyncOp_free(void *ptr) {
|
24
|
+
struct um_async_op *async_op = ptr;
|
25
|
+
um_op_free(async_op->machine, async_op->op);
|
26
|
+
free(ptr);
|
27
|
+
}
|
28
|
+
|
29
|
+
static const rb_data_type_t AsyncOp_type = {
|
30
|
+
"UringMachine::AsyncOp",
|
31
|
+
{AsyncOp_mark, AsyncOp_free, AsyncOp_size, AsyncOp_compact},
|
32
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
33
|
+
};
|
34
|
+
|
35
|
+
static VALUE AsyncOp_allocate(VALUE klass) {
|
36
|
+
struct um_async_op *async_op = malloc(sizeof(struct um_async_op));
|
37
|
+
return TypedData_Wrap_Struct(klass, &AsyncOp_type, async_op);
|
38
|
+
}
|
39
|
+
|
40
|
+
inline struct um_async_op *AsyncOp_data(VALUE self) {
|
41
|
+
return RTYPEDDATA_DATA(self);
|
42
|
+
}
|
43
|
+
|
44
|
+
VALUE AsyncOp_initialize(VALUE self) {
|
45
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
46
|
+
memset(async_op, 0, sizeof(struct um_async_op));
|
47
|
+
async_op->self = self;
|
48
|
+
return self;
|
49
|
+
}
|
50
|
+
|
51
|
+
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op) {
|
52
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
53
|
+
async_op->machine = machine;
|
54
|
+
async_op->op = op;
|
55
|
+
}
|
56
|
+
|
57
|
+
inline void raise_on_missing_op(struct um_async_op *async_op) {
|
58
|
+
if (!async_op->op)
|
59
|
+
rb_raise(rb_eRuntimeError, "Missing op");
|
60
|
+
}
|
61
|
+
|
62
|
+
inline int async_op_is_done(struct um_async_op *async_op) {
|
63
|
+
return (async_op->op->flags & OP_F_COMPLETED);
|
64
|
+
}
|
65
|
+
|
66
|
+
VALUE AsyncOp_kind(VALUE self) {
|
67
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
68
|
+
raise_on_missing_op(async_op);
|
69
|
+
|
70
|
+
switch(async_op->op->kind) {
|
71
|
+
case OP_TIMEOUT:
|
72
|
+
return SYM_timeout;
|
73
|
+
default:
|
74
|
+
rb_raise(rb_eRuntimeError, "Invalid op kind");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
VALUE AsyncOp_done_p(VALUE self) {
|
79
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
80
|
+
raise_on_missing_op(async_op);
|
81
|
+
|
82
|
+
return async_op_is_done(async_op) ? Qtrue : Qfalse;
|
83
|
+
}
|
84
|
+
|
85
|
+
VALUE AsyncOp_result(VALUE self) {
|
86
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
87
|
+
raise_on_missing_op(async_op);
|
88
|
+
|
89
|
+
return async_op_is_done(async_op) ? INT2NUM(async_op->op->result.res) : Qnil;
|
90
|
+
}
|
91
|
+
|
92
|
+
VALUE AsyncOp_cancelled_p(VALUE self) {
|
93
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
94
|
+
raise_on_missing_op(async_op);
|
95
|
+
|
96
|
+
if (!async_op_is_done(async_op)) return Qnil;
|
97
|
+
|
98
|
+
return (async_op->op->result.res == -ECANCELED) ? Qtrue : Qfalse;
|
99
|
+
}
|
100
|
+
|
101
|
+
VALUE AsyncOp_await(VALUE self) {
|
102
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
103
|
+
raise_on_missing_op(async_op);
|
104
|
+
|
105
|
+
if (async_op_is_done(async_op))
|
106
|
+
return INT2NUM(async_op->op->result.res);
|
107
|
+
|
108
|
+
return um_async_op_await(async_op);
|
109
|
+
}
|
110
|
+
|
111
|
+
VALUE AsyncOp_cancel(VALUE self) {
|
112
|
+
struct um_async_op *async_op = AsyncOp_data(self);
|
113
|
+
raise_on_missing_op(async_op);
|
114
|
+
|
115
|
+
if (!async_op_is_done(async_op))
|
116
|
+
um_async_op_cancel(async_op);
|
117
|
+
|
118
|
+
return self;
|
119
|
+
}
|
120
|
+
|
121
|
+
void Init_AsyncOp(void) {
|
122
|
+
cAsyncOp = rb_define_class_under(cUM, "AsyncOp", rb_cObject);
|
123
|
+
rb_define_alloc_func(cAsyncOp, AsyncOp_allocate);
|
124
|
+
|
125
|
+
rb_define_method(cAsyncOp, "initialize", AsyncOp_initialize, 0);
|
126
|
+
rb_define_method(cAsyncOp, "kind", AsyncOp_kind, 0);
|
127
|
+
rb_define_method(cAsyncOp, "done?", AsyncOp_done_p, 0);
|
128
|
+
rb_define_method(cAsyncOp, "result", AsyncOp_result, 0);
|
129
|
+
rb_define_method(cAsyncOp, "cancelled?", AsyncOp_cancelled_p, 0);
|
130
|
+
|
131
|
+
rb_define_method(cAsyncOp, "await", AsyncOp_await, 0);
|
132
|
+
rb_define_method(cAsyncOp, "join", AsyncOp_await, 0);
|
133
|
+
rb_define_method(cAsyncOp, "cancel", AsyncOp_cancel, 0);
|
134
|
+
|
135
|
+
SYM_timeout = ID2SYM(rb_intern("timeout"));
|
136
|
+
}
|
data/ext/um/um_buffer.c
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#include "um.h"
|
2
|
+
|
3
|
+
inline long buffer_size(long len) {
|
4
|
+
len--;
|
5
|
+
len |= len >> 1;
|
6
|
+
len |= len >> 2;
|
7
|
+
len |= len >> 4;
|
8
|
+
len |= len >> 8;
|
9
|
+
len |= len >> 16;
|
10
|
+
len++;
|
11
|
+
return (len > 4096) ? len : 4096;
|
12
|
+
}
|
13
|
+
|
14
|
+
inline struct um_buffer *um_buffer_checkout(struct um *machine, int len) {
|
15
|
+
struct um_buffer *buffer = machine->buffer_freelist;
|
16
|
+
if (buffer)
|
17
|
+
machine->buffer_freelist = buffer->next;
|
18
|
+
else {
|
19
|
+
buffer = malloc(sizeof(struct um_buffer));
|
20
|
+
memset(buffer, 0, sizeof(struct um_buffer));
|
21
|
+
}
|
22
|
+
|
23
|
+
if (buffer->len < len) {
|
24
|
+
if (buffer->ptr) {
|
25
|
+
free(buffer->ptr);
|
26
|
+
buffer->ptr = NULL;
|
27
|
+
}
|
28
|
+
|
29
|
+
buffer->len = buffer_size(len);
|
30
|
+
if (posix_memalign(&buffer->ptr, 4096, buffer->len))
|
31
|
+
rb_raise(rb_eRuntimeError, "Failed to allocate buffer");
|
32
|
+
}
|
33
|
+
return buffer;
|
34
|
+
}
|
35
|
+
|
36
|
+
inline void um_buffer_checkin(struct um *machine, struct um_buffer *buffer) {
|
37
|
+
buffer->next = machine->buffer_freelist;
|
38
|
+
machine->buffer_freelist = buffer;
|
39
|
+
}
|
40
|
+
|
41
|
+
inline void um_free_buffer_linked_list(struct um *machine) {
|
42
|
+
struct um_buffer *buffer = machine->buffer_freelist;
|
43
|
+
while (buffer) {
|
44
|
+
struct um_buffer *next = buffer->next;
|
45
|
+
if (buffer->ptr) free(buffer->ptr);
|
46
|
+
free(buffer);
|
47
|
+
buffer = next;
|
48
|
+
}
|
49
|
+
}
|