uringmachine 0.31.0 → 0.32.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 +4 -0
- data/README.md +36 -37
- data/TODO.md +18 -55
- data/benchmark/bm_io_pipe.rb +2 -2
- data/benchmark/common.rb +16 -16
- data/benchmark/gets.rb +7 -7
- data/benchmark/gets_concurrent.rb +12 -12
- data/benchmark/http_parse.rb +11 -11
- data/benchmark/http_server_accept_queue.rb +7 -7
- data/benchmark/http_server_multi_accept.rb +7 -7
- data/benchmark/http_server_multi_ractor.rb +7 -7
- data/benchmark/http_server_single_thread.rb +8 -8
- data/benchmark/openssl.rb +4 -4
- data/examples/fiber_concurrency_io.rb +1 -1
- data/examples/fiber_concurrency_um.rb +16 -0
- data/examples/io_uring_simple.c +13 -4
- data/examples/pg.rb +2 -2
- data/examples/um_cancellation.rb +20 -0
- data/examples/um_fiber_scheduler.rb +10 -0
- data/examples/um_io.rb +19 -0
- data/examples/um_mo.c +32 -0
- data/examples/um_multishot.rb +15 -0
- data/examples/um_ssl.rb +11 -0
- data/ext/um/um.h +19 -19
- data/ext/um/um_ext.c +2 -4
- data/ext/um/{um_connection.c → um_io.c} +210 -210
- data/ext/um/{um_connection_class.c → um_io_class.c} +102 -102
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +12 -12
- data/test/{test_connection.rb → test_io.rb} +29 -29
- data/test/test_um.rb +7 -7
- metadata +13 -6
|
@@ -2,88 +2,88 @@
|
|
|
2
2
|
#include <ruby/io/buffer.h>
|
|
3
3
|
#include "um.h"
|
|
4
4
|
|
|
5
|
-
inline void
|
|
5
|
+
inline void io_add_segment(struct um_io *io, struct um_segment *segment) {
|
|
6
6
|
segment->next = NULL;
|
|
7
|
-
if (
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
if (io->tail) {
|
|
8
|
+
io->tail->next = segment;
|
|
9
|
+
io->tail = segment;
|
|
10
10
|
}
|
|
11
11
|
else
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
io->head = io->tail = segment;
|
|
13
|
+
io->pending_bytes += segment->len;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
inline int
|
|
16
|
+
inline int io_process_op_result(struct um_io *io, struct um_op_result *result) {
|
|
17
17
|
if (likely(result->res > 0)) {
|
|
18
18
|
if (likely(result->segment)) {
|
|
19
|
-
|
|
19
|
+
io_add_segment(io, result->segment);
|
|
20
20
|
result->segment = NULL;
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
else
|
|
24
|
-
|
|
24
|
+
io->eof = 1;
|
|
25
25
|
|
|
26
26
|
return result->res;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
#define
|
|
29
|
+
#define IO_OP_FLAGS (OP_F_MULTISHOT | OP_F_BUFFER_POOL)
|
|
30
30
|
|
|
31
|
-
void
|
|
32
|
-
if (!
|
|
33
|
-
|
|
31
|
+
void io_multishot_op_start(struct um_io *io) {
|
|
32
|
+
if (!io->op)
|
|
33
|
+
io->op = um_op_acquire(io->machine);
|
|
34
34
|
struct io_uring_sqe *sqe;
|
|
35
35
|
|
|
36
|
-
bp_ensure_commit_level(
|
|
36
|
+
bp_ensure_commit_level(io->machine);
|
|
37
37
|
|
|
38
|
-
switch (
|
|
39
|
-
case
|
|
40
|
-
um_prep_op(
|
|
41
|
-
sqe = um_get_sqe(
|
|
42
|
-
io_uring_prep_read_multishot(sqe,
|
|
38
|
+
switch (io->mode) {
|
|
39
|
+
case IO_FD:
|
|
40
|
+
um_prep_op(io->machine, io->op, OP_READ_MULTISHOT, 2, IO_OP_FLAGS);
|
|
41
|
+
sqe = um_get_sqe(io->machine, io->op);
|
|
42
|
+
io_uring_prep_read_multishot(sqe, io->fd, 0, -1, BP_BGID);
|
|
43
43
|
break;
|
|
44
|
-
case
|
|
45
|
-
um_prep_op(
|
|
46
|
-
sqe = um_get_sqe(
|
|
47
|
-
io_uring_prep_recv_multishot(sqe,
|
|
44
|
+
case IO_SOCKET:
|
|
45
|
+
um_prep_op(io->machine, io->op, OP_RECV_MULTISHOT, 2, IO_OP_FLAGS);
|
|
46
|
+
sqe = um_get_sqe(io->machine, io->op);
|
|
47
|
+
io_uring_prep_recv_multishot(sqe, io->fd, NULL, 0, 0);
|
|
48
48
|
sqe->buf_group = BP_BGID;
|
|
49
49
|
sqe->flags |= IOSQE_BUFFER_SELECT;
|
|
50
50
|
break;
|
|
51
51
|
default:
|
|
52
52
|
um_raise_internal_error("Invalid multishot op");
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
io->op->bp_commit_level = io->machine->bp_commit_level;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
void
|
|
58
|
-
assert(!
|
|
57
|
+
void io_multishot_op_stop(struct um_io *io) {
|
|
58
|
+
assert(!io->op);
|
|
59
59
|
|
|
60
|
-
if (!(
|
|
61
|
-
|
|
62
|
-
um_cancel_op(
|
|
60
|
+
if (!(io->op->flags & OP_F_CQE_DONE)) {
|
|
61
|
+
io->op->flags |= OP_F_ASYNC;
|
|
62
|
+
um_cancel_op(io->machine, io->op);
|
|
63
63
|
}
|
|
64
64
|
else
|
|
65
|
-
um_op_release(
|
|
66
|
-
|
|
65
|
+
um_op_release(io->machine, io->op);
|
|
66
|
+
io->op = NULL;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
void
|
|
70
|
-
if (
|
|
69
|
+
void um_io_cleanup(struct um_io *io) {
|
|
70
|
+
if (io->op) io_multishot_op_stop(io);
|
|
71
71
|
|
|
72
|
-
while (
|
|
73
|
-
struct um_segment *next =
|
|
74
|
-
um_segment_checkin(
|
|
75
|
-
|
|
72
|
+
while (io->head) {
|
|
73
|
+
struct um_segment *next = io->head->next;
|
|
74
|
+
um_segment_checkin(io->machine, io->head);
|
|
75
|
+
io->head = next;
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
io->pending_bytes = 0;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// returns true if case of ENOBUFS error, sets more to true if more data forthcoming
|
|
81
|
-
inline int
|
|
82
|
-
struct
|
|
81
|
+
inline int io_process_segments(
|
|
82
|
+
struct um_io *io, size_t *total_bytes, int *more) {
|
|
83
83
|
|
|
84
84
|
*more = 0;
|
|
85
|
-
struct um_op_result *result = &
|
|
86
|
-
|
|
85
|
+
struct um_op_result *result = &io->op->result;
|
|
86
|
+
io->op->flags &= ~OP_F_CQE_SEEN;
|
|
87
87
|
while (result) {
|
|
88
88
|
if (unlikely(result->res == -ENOBUFS)) {
|
|
89
89
|
*more = 0;
|
|
@@ -97,142 +97,142 @@ inline int connection_process_segments(
|
|
|
97
97
|
|
|
98
98
|
*more = (result->flags & IORING_CQE_F_MORE);
|
|
99
99
|
*total_bytes += result->res;
|
|
100
|
-
|
|
100
|
+
io_process_op_result(io, result);
|
|
101
101
|
result = result->next;
|
|
102
102
|
}
|
|
103
103
|
return false;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
void
|
|
107
|
-
if (
|
|
108
|
-
if (OP_CQE_SEEN_P(
|
|
106
|
+
void io_clear(struct um_io *io) {
|
|
107
|
+
if (io->op && io->machine->ring_initialized) {
|
|
108
|
+
if (OP_CQE_SEEN_P(io->op)) {
|
|
109
109
|
size_t total_bytes = 0;
|
|
110
110
|
int more = false;
|
|
111
|
-
|
|
112
|
-
um_op_multishot_results_clear(
|
|
111
|
+
io_process_segments(io, &total_bytes, &more);
|
|
112
|
+
um_op_multishot_results_clear(io->machine, io->op);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
if (OP_CQE_DONE_P(
|
|
116
|
-
um_op_release(
|
|
115
|
+
if (OP_CQE_DONE_P(io->op))
|
|
116
|
+
um_op_release(io->machine, io->op);
|
|
117
117
|
else
|
|
118
|
-
um_cancel_op_and_discard_cqe(
|
|
118
|
+
um_cancel_op_and_discard_cqe(io->machine, io->op);
|
|
119
119
|
|
|
120
|
-
|
|
120
|
+
io->op = NULL;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
while (
|
|
124
|
-
struct um_segment *next =
|
|
125
|
-
um_segment_checkin(
|
|
126
|
-
|
|
123
|
+
while (io->head) {
|
|
124
|
+
struct um_segment *next = io->head->next;
|
|
125
|
+
um_segment_checkin(io->machine, io->head);
|
|
126
|
+
io->head = next;
|
|
127
127
|
}
|
|
128
|
-
|
|
128
|
+
io->pending_bytes = 0;
|
|
129
129
|
|
|
130
|
-
if (
|
|
131
|
-
bp_buffer_checkin(
|
|
132
|
-
|
|
130
|
+
if (io->working_buffer) {
|
|
131
|
+
bp_buffer_checkin(io->machine, io->working_buffer);
|
|
132
|
+
io->working_buffer = NULL;
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
inline void
|
|
137
|
-
if (unlikely(!
|
|
136
|
+
inline void io_await_segments(struct um_io *io) {
|
|
137
|
+
if (unlikely(!io->op)) io_multishot_op_start(io);
|
|
138
138
|
|
|
139
|
-
if (!OP_CQE_SEEN_P(
|
|
140
|
-
|
|
141
|
-
VALUE ret = um_yield(
|
|
142
|
-
|
|
143
|
-
if (!OP_CQE_SEEN_P(
|
|
139
|
+
if (!OP_CQE_SEEN_P(io->op)) {
|
|
140
|
+
io->op->flags &= ~OP_F_ASYNC;
|
|
141
|
+
VALUE ret = um_yield(io->machine);
|
|
142
|
+
io->op->flags |= OP_F_ASYNC;
|
|
143
|
+
if (!OP_CQE_SEEN_P(io->op)) RAISE_IF_EXCEPTION(ret);
|
|
144
144
|
RB_GC_GUARD(ret);
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
int
|
|
148
|
+
int io_get_more_segments_bp(struct um_io *io) {
|
|
149
149
|
size_t total_bytes = 0;
|
|
150
150
|
int more = false;
|
|
151
151
|
int enobufs = false;
|
|
152
152
|
|
|
153
153
|
while (1) {
|
|
154
|
-
if (unlikely(
|
|
154
|
+
if (unlikely(io->eof)) return 0;
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
enobufs =
|
|
158
|
-
um_op_multishot_results_clear(
|
|
156
|
+
io_await_segments(io);
|
|
157
|
+
enobufs = io_process_segments(io, &total_bytes, &more);
|
|
158
|
+
um_op_multishot_results_clear(io->machine, io->op);
|
|
159
159
|
if (unlikely(enobufs)) {
|
|
160
|
-
int should_restart =
|
|
161
|
-
// int same_threshold =
|
|
160
|
+
int should_restart = io->pending_bytes < (io->machine->bp_buffer_size * 4);
|
|
161
|
+
// int same_threshold = io->op->bp_commit_level == io->machine->bp_commit_level;
|
|
162
162
|
|
|
163
163
|
// fprintf(stderr, "%p enobufs total: %ld pending: %ld threshold: %ld bc: %d (same: %d, restart: %d)\n",
|
|
164
|
-
//
|
|
165
|
-
// total_bytes,
|
|
166
|
-
//
|
|
164
|
+
// io,
|
|
165
|
+
// total_bytes, io->pending_bytes, io->machine->bp_commit_level,
|
|
166
|
+
// io->machine->bp_buffer_count,
|
|
167
167
|
// same_threshold, should_restart
|
|
168
168
|
// );
|
|
169
169
|
|
|
170
|
-
// If multiple
|
|
170
|
+
// If multiple IO ops are happening at the same time, they'll all
|
|
171
171
|
// get ENOBUFS! We track the commit threshold in the op in order to
|
|
172
172
|
// prevent running bp_handle_enobufs() more than once.
|
|
173
173
|
|
|
174
174
|
if (should_restart) {
|
|
175
|
-
if (
|
|
176
|
-
bp_handle_enobufs(
|
|
175
|
+
if (io->op->bp_commit_level == io->machine->bp_commit_level)
|
|
176
|
+
bp_handle_enobufs(io->machine);
|
|
177
177
|
|
|
178
|
-
um_op_release(
|
|
179
|
-
|
|
180
|
-
//
|
|
178
|
+
um_op_release(io->machine, io->op);
|
|
179
|
+
io->op = NULL;
|
|
180
|
+
// io_multishot_op_start(io);
|
|
181
181
|
}
|
|
182
182
|
else {
|
|
183
|
-
um_op_release(
|
|
184
|
-
|
|
183
|
+
um_op_release(io->machine, io->op);
|
|
184
|
+
io->op = NULL;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
if (total_bytes) return total_bytes;
|
|
188
188
|
}
|
|
189
189
|
else {
|
|
190
190
|
if (more)
|
|
191
|
-
|
|
192
|
-
if (total_bytes ||
|
|
191
|
+
io->op->flags &= ~OP_F_CQE_SEEN;
|
|
192
|
+
if (total_bytes || io->eof) return total_bytes;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
int
|
|
198
|
-
if (!
|
|
199
|
-
|
|
197
|
+
int io_get_more_segments_ssl(struct um_io *io) {
|
|
198
|
+
if (!io->working_buffer)
|
|
199
|
+
io->working_buffer = bp_buffer_checkout(io->machine);
|
|
200
200
|
|
|
201
|
-
char *ptr =
|
|
202
|
-
size_t maxlen =
|
|
203
|
-
int res = um_ssl_read_raw(
|
|
201
|
+
char *ptr = io->working_buffer->buf + io->working_buffer->pos;
|
|
202
|
+
size_t maxlen = io->working_buffer->len - io->working_buffer->pos;
|
|
203
|
+
int res = um_ssl_read_raw(io->machine, io->target, ptr, maxlen);
|
|
204
204
|
if (res == 0) return 0;
|
|
205
205
|
if (res < 0) rb_raise(eUMError, "Failed to read segment");
|
|
206
206
|
|
|
207
|
-
struct um_segment *segment = bp_buffer_consume(
|
|
207
|
+
struct um_segment *segment = bp_buffer_consume(io->machine, io->working_buffer, res);
|
|
208
208
|
if ((size_t)res == maxlen) {
|
|
209
|
-
bp_buffer_checkin(
|
|
210
|
-
|
|
209
|
+
bp_buffer_checkin(io->machine, io->working_buffer);
|
|
210
|
+
io->working_buffer = NULL;
|
|
211
211
|
}
|
|
212
|
-
|
|
212
|
+
io_add_segment(io, segment);
|
|
213
213
|
return 1;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
int
|
|
217
|
-
switch (
|
|
218
|
-
case
|
|
219
|
-
case
|
|
220
|
-
return
|
|
221
|
-
case
|
|
222
|
-
return
|
|
216
|
+
int io_get_more_segments(struct um_io *io) {
|
|
217
|
+
switch (io->mode) {
|
|
218
|
+
case IO_FD:
|
|
219
|
+
case IO_SOCKET:
|
|
220
|
+
return io_get_more_segments_bp(io);
|
|
221
|
+
case IO_SSL:
|
|
222
|
+
return io_get_more_segments_ssl(io);
|
|
223
223
|
default:
|
|
224
|
-
rb_raise(eUMError, "Invalid
|
|
224
|
+
rb_raise(eUMError, "Invalid IO mode");
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
////////////////////////////////////////////////////////////////////////////////
|
|
229
229
|
|
|
230
|
-
inline void
|
|
231
|
-
struct um_segment *consumed =
|
|
232
|
-
|
|
233
|
-
if (!
|
|
234
|
-
um_segment_checkin(
|
|
235
|
-
|
|
230
|
+
inline void io_shift_head(struct um_io *io) {
|
|
231
|
+
struct um_segment *consumed = io->head;
|
|
232
|
+
io->head = consumed->next;
|
|
233
|
+
if (!io->head) io->tail = NULL;
|
|
234
|
+
um_segment_checkin(io->machine, consumed);
|
|
235
|
+
io->pos = 0;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
inline VALUE make_segment_io_buffer(struct um_segment *segment, size_t pos) {
|
|
@@ -242,32 +242,32 @@ inline VALUE make_segment_io_buffer(struct um_segment *segment, size_t pos) {
|
|
|
242
242
|
);
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
inline void
|
|
246
|
-
if (unlikely(
|
|
247
|
-
if (safe_inc && !
|
|
245
|
+
inline void io_skip(struct um_io *io, size_t inc, int safe_inc) {
|
|
246
|
+
if (unlikely(io->eof && !io->head)) return;
|
|
247
|
+
if (safe_inc && !io->tail && !io_get_more_segments(io)) return;
|
|
248
248
|
|
|
249
249
|
while (inc) {
|
|
250
|
-
size_t segment_len =
|
|
250
|
+
size_t segment_len = io->head->len - io->pos;
|
|
251
251
|
size_t inc_len = (segment_len <= inc) ? segment_len : inc;
|
|
252
252
|
inc -= inc_len;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
if (inc && safe_inc && !
|
|
259
|
-
if (!
|
|
253
|
+
io->pos += inc_len;
|
|
254
|
+
io->consumed_bytes += inc_len;
|
|
255
|
+
io->pending_bytes -= inc_len;
|
|
256
|
+
if (io->pos == io->head->len) {
|
|
257
|
+
io_shift_head(io);
|
|
258
|
+
if (inc && safe_inc && !io->head) {
|
|
259
|
+
if (!io_get_more_segments(io)) break;
|
|
260
260
|
}
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
inline void
|
|
266
|
-
if (unlikely(
|
|
267
|
-
if (!
|
|
265
|
+
inline void io_read_each(struct um_io *io) {
|
|
266
|
+
if (unlikely(io->eof && !io->head)) return;
|
|
267
|
+
if (!io->tail && !io_get_more_segments(io)) return;
|
|
268
268
|
|
|
269
|
-
struct um_segment *current =
|
|
270
|
-
size_t pos =
|
|
269
|
+
struct um_segment *current = io->head;
|
|
270
|
+
size_t pos = io->pos;
|
|
271
271
|
|
|
272
272
|
VALUE buffer = Qnil;
|
|
273
273
|
while (true) {
|
|
@@ -275,34 +275,34 @@ inline void connection_read_each(struct um_connection *conn) {
|
|
|
275
275
|
buffer = make_segment_io_buffer(current, pos);
|
|
276
276
|
rb_yield(buffer);
|
|
277
277
|
rb_io_buffer_free_locked(buffer);
|
|
278
|
-
|
|
278
|
+
io_shift_head(io);
|
|
279
279
|
|
|
280
280
|
if (!next) {
|
|
281
|
-
if (!
|
|
281
|
+
if (!io_get_more_segments(io)) return;
|
|
282
282
|
}
|
|
283
|
-
current =
|
|
283
|
+
current = io->head;
|
|
284
284
|
pos = 0;
|
|
285
285
|
}
|
|
286
286
|
RB_GC_GUARD(buffer);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
inline void
|
|
289
|
+
inline void io_copy(struct um_io *io, char *dest, size_t len) {
|
|
290
290
|
while (len) {
|
|
291
|
-
char *segment_ptr =
|
|
292
|
-
size_t segment_len =
|
|
291
|
+
char *segment_ptr = io->head->ptr + io->pos;
|
|
292
|
+
size_t segment_len = io->head->len - io->pos;
|
|
293
293
|
size_t cpy_len = (segment_len <= len) ? segment_len : len;
|
|
294
294
|
memcpy(dest, segment_ptr, cpy_len);
|
|
295
295
|
|
|
296
296
|
len -= cpy_len;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
io->pos += cpy_len;
|
|
298
|
+
io->consumed_bytes += cpy_len;
|
|
299
|
+
io->pending_bytes -= cpy_len;
|
|
300
300
|
dest += cpy_len;
|
|
301
|
-
if (
|
|
301
|
+
if (io->pos == io->head->len) io_shift_head(io);
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
|
|
305
|
-
VALUE
|
|
305
|
+
VALUE io_consume_string(struct um_io *io, VALUE out_buffer, size_t len, size_t inc, int safe_inc) {
|
|
306
306
|
VALUE str = Qnil;
|
|
307
307
|
if (!NIL_P(out_buffer)) {
|
|
308
308
|
str = out_buffer;
|
|
@@ -316,8 +316,8 @@ VALUE connection_consume_string(struct um_connection *conn, VALUE out_buffer, si
|
|
|
316
316
|
str = rb_str_new(NULL, len);
|
|
317
317
|
char *dest = RSTRING_PTR(str);
|
|
318
318
|
|
|
319
|
-
|
|
320
|
-
|
|
319
|
+
io_copy(io, dest, len);
|
|
320
|
+
io_skip(io, inc, safe_inc);
|
|
321
321
|
return str;
|
|
322
322
|
RB_GC_GUARD(str);
|
|
323
323
|
}
|
|
@@ -326,16 +326,16 @@ inline int trailing_cr_p(char *ptr, size_t len) {
|
|
|
326
326
|
return ptr[len - 1] == '\r';
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
VALUE
|
|
330
|
-
if (unlikely(
|
|
331
|
-
if (!
|
|
329
|
+
VALUE io_read_line(struct um_io *io, VALUE out_buffer, size_t maxlen) {
|
|
330
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
331
|
+
if (!io->tail && !io_get_more_segments(io)) return Qnil;
|
|
332
332
|
|
|
333
333
|
struct um_segment *last = NULL;
|
|
334
|
-
struct um_segment *current =
|
|
334
|
+
struct um_segment *current = io->head;
|
|
335
335
|
size_t remaining_len = maxlen;
|
|
336
336
|
size_t total_len = 0;
|
|
337
337
|
size_t inc = 1;
|
|
338
|
-
size_t pos =
|
|
338
|
+
size_t pos = io->pos;
|
|
339
339
|
|
|
340
340
|
while (true) {
|
|
341
341
|
size_t segment_len = current->len - pos;
|
|
@@ -359,7 +359,7 @@ VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t
|
|
|
359
359
|
}
|
|
360
360
|
}
|
|
361
361
|
|
|
362
|
-
return
|
|
362
|
+
return io_consume_string(io, out_buffer, total_len, inc, false);
|
|
363
363
|
}
|
|
364
364
|
else {
|
|
365
365
|
// not found, early return if segment len exceeds maxlen
|
|
@@ -370,7 +370,7 @@ VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t
|
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
if (!current->next) {
|
|
373
|
-
if (!
|
|
373
|
+
if (!io_get_more_segments(io)) {
|
|
374
374
|
return Qnil;
|
|
375
375
|
}
|
|
376
376
|
}
|
|
@@ -381,15 +381,15 @@ VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
VALUE
|
|
385
|
-
if (unlikely(
|
|
386
|
-
if (!
|
|
384
|
+
VALUE io_read(struct um_io *io, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc) {
|
|
385
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
386
|
+
if (!io->tail && !io_get_more_segments(io)) return Qnil;
|
|
387
387
|
|
|
388
|
-
struct um_segment *current =
|
|
388
|
+
struct um_segment *current = io->head;
|
|
389
389
|
size_t abs_len = labs(len);
|
|
390
390
|
size_t remaining_len = abs_len;
|
|
391
391
|
size_t total_len = 0;
|
|
392
|
-
size_t pos =
|
|
392
|
+
size_t pos = io->pos;
|
|
393
393
|
|
|
394
394
|
while (true) {
|
|
395
395
|
size_t segment_len = current->len - pos;
|
|
@@ -400,14 +400,14 @@ VALUE connection_read(struct um_connection *conn, VALUE out_buffer, ssize_t len,
|
|
|
400
400
|
if (abs_len) {
|
|
401
401
|
remaining_len -= segment_len;
|
|
402
402
|
if (!remaining_len)
|
|
403
|
-
return
|
|
403
|
+
return io_consume_string(io, out_buffer, total_len, inc, safe_inc);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
if (!current->next) {
|
|
407
407
|
if (len <= 0)
|
|
408
|
-
return
|
|
408
|
+
return io_consume_string(io, out_buffer, total_len, inc, safe_inc);
|
|
409
409
|
|
|
410
|
-
if (!
|
|
410
|
+
if (!io_get_more_segments(io))
|
|
411
411
|
return Qnil;
|
|
412
412
|
}
|
|
413
413
|
current = current->next;
|
|
@@ -425,17 +425,17 @@ static inline char delim_to_char(VALUE delim) {
|
|
|
425
425
|
return *RSTRING_PTR(delim);
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
-
VALUE
|
|
428
|
+
VALUE io_read_to_delim(struct um_io *io, VALUE out_buffer, VALUE delim, ssize_t maxlen) {
|
|
429
429
|
char delim_char = delim_to_char(delim);
|
|
430
430
|
|
|
431
|
-
if (unlikely(
|
|
432
|
-
if (unlikely(!
|
|
431
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
432
|
+
if (unlikely(!io->tail) && !io_get_more_segments(io)) return Qnil;
|
|
433
433
|
|
|
434
|
-
struct um_segment *current =
|
|
434
|
+
struct um_segment *current = io->head;
|
|
435
435
|
size_t abs_maxlen = labs(maxlen);
|
|
436
436
|
size_t remaining_len = abs_maxlen;
|
|
437
437
|
size_t total_len = 0;
|
|
438
|
-
size_t pos =
|
|
438
|
+
size_t pos = io->pos;
|
|
439
439
|
|
|
440
440
|
while (true) {
|
|
441
441
|
size_t segment_len = current->len - pos;
|
|
@@ -447,7 +447,7 @@ VALUE connection_read_to_delim(struct um_connection *conn, VALUE out_buffer, VAL
|
|
|
447
447
|
if (delim_ptr) {
|
|
448
448
|
size_t len = delim_ptr - start;
|
|
449
449
|
total_len += len;
|
|
450
|
-
return
|
|
450
|
+
return io_consume_string(io, out_buffer, total_len, 1, false);
|
|
451
451
|
}
|
|
452
452
|
else {
|
|
453
453
|
// delimiter not found
|
|
@@ -455,51 +455,51 @@ VALUE connection_read_to_delim(struct um_connection *conn, VALUE out_buffer, VAL
|
|
|
455
455
|
remaining_len -= search_len;
|
|
456
456
|
|
|
457
457
|
if (abs_maxlen && total_len >= abs_maxlen)
|
|
458
|
-
return (maxlen > 0) ? Qnil :
|
|
458
|
+
return (maxlen > 0) ? Qnil : io_consume_string(io, out_buffer, abs_maxlen, 1, false);
|
|
459
459
|
}
|
|
460
460
|
|
|
461
|
-
if (!current->next && !
|
|
461
|
+
if (!current->next && !io_get_more_segments(io)) return Qnil;
|
|
462
462
|
|
|
463
463
|
current = current->next;
|
|
464
464
|
pos = 0;
|
|
465
465
|
}
|
|
466
466
|
}
|
|
467
467
|
|
|
468
|
-
size_t
|
|
469
|
-
switch (
|
|
470
|
-
case
|
|
471
|
-
return um_write_raw(
|
|
472
|
-
case
|
|
473
|
-
return um_send_raw(
|
|
474
|
-
case
|
|
475
|
-
return um_ssl_write_raw(
|
|
468
|
+
size_t io_write_raw(struct um_io *io, const char *buffer, size_t len) {
|
|
469
|
+
switch (io->mode) {
|
|
470
|
+
case IO_FD:
|
|
471
|
+
return um_write_raw(io->machine, io->fd, buffer, len);
|
|
472
|
+
case IO_SOCKET:
|
|
473
|
+
return um_send_raw(io->machine, io->fd, buffer, len, 0);
|
|
474
|
+
case IO_SSL:
|
|
475
|
+
return um_ssl_write_raw(io->machine, io->target, buffer, len);
|
|
476
476
|
default:
|
|
477
|
-
rb_raise(eUMError, "Invalid
|
|
477
|
+
rb_raise(eUMError, "Invalid IO mode");
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
480
|
|
|
481
|
-
VALUE
|
|
482
|
-
switch (
|
|
483
|
-
case
|
|
484
|
-
return um_writev(
|
|
485
|
-
case
|
|
486
|
-
return um_sendv(
|
|
487
|
-
case
|
|
488
|
-
return ULONG2NUM(um_ssl_writev(
|
|
481
|
+
VALUE io_writev(struct um_io *io, int argc, VALUE *argv) {
|
|
482
|
+
switch (io->mode) {
|
|
483
|
+
case IO_FD:
|
|
484
|
+
return um_writev(io->machine, io->fd, argc, argv);
|
|
485
|
+
case IO_SOCKET:
|
|
486
|
+
return um_sendv(io->machine, io->fd, argc, argv);
|
|
487
|
+
case IO_SSL:
|
|
488
|
+
return ULONG2NUM(um_ssl_writev(io->machine, io->target, argc, argv));
|
|
489
489
|
default:
|
|
490
|
-
rb_raise(eUMError, "Invalid
|
|
490
|
+
rb_raise(eUMError, "Invalid IO mode");
|
|
491
491
|
}
|
|
492
492
|
}
|
|
493
493
|
|
|
494
494
|
////////////////////////////////////////////////////////////////////////////////
|
|
495
495
|
|
|
496
|
-
VALUE resp_read_line(struct
|
|
497
|
-
if (unlikely(
|
|
498
|
-
if (!
|
|
496
|
+
VALUE resp_read_line(struct um_io *io, VALUE out_buffer) {
|
|
497
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
498
|
+
if (!io->tail && !io_get_more_segments(io)) return Qnil;
|
|
499
499
|
|
|
500
|
-
struct um_segment *current =
|
|
500
|
+
struct um_segment *current = io->head;
|
|
501
501
|
size_t total_len = 0;
|
|
502
|
-
size_t pos =
|
|
502
|
+
size_t pos = io->pos;
|
|
503
503
|
|
|
504
504
|
while (true) {
|
|
505
505
|
size_t segment_len = current->len - pos;
|
|
@@ -508,20 +508,20 @@ VALUE resp_read_line(struct um_connection *conn, VALUE out_buffer) {
|
|
|
508
508
|
if (lf_ptr) {
|
|
509
509
|
size_t len = lf_ptr - start;
|
|
510
510
|
total_len += len;
|
|
511
|
-
return
|
|
511
|
+
return io_consume_string(io, out_buffer, total_len, 2, true);
|
|
512
512
|
}
|
|
513
513
|
else
|
|
514
514
|
total_len += segment_len;
|
|
515
515
|
|
|
516
516
|
if (!current->next)
|
|
517
|
-
if (!
|
|
517
|
+
if (!io_get_more_segments(io)) return Qnil;
|
|
518
518
|
|
|
519
519
|
current = current->next;
|
|
520
520
|
}
|
|
521
521
|
}
|
|
522
522
|
|
|
523
|
-
inline VALUE resp_read_string(struct
|
|
524
|
-
return
|
|
523
|
+
inline VALUE resp_read_string(struct um_io *io, ulong len, VALUE out_buffer) {
|
|
524
|
+
return io_read(io, out_buffer, len, 2, true);
|
|
525
525
|
}
|
|
526
526
|
|
|
527
527
|
inline ulong resp_parse_length_field(const char *ptr, int len) {
|
|
@@ -531,12 +531,12 @@ inline ulong resp_parse_length_field(const char *ptr, int len) {
|
|
|
531
531
|
return acc;
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
-
VALUE resp_decode_hash(struct
|
|
534
|
+
VALUE resp_decode_hash(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
535
535
|
VALUE hash = rb_hash_new();
|
|
536
536
|
|
|
537
537
|
for (ulong i = 0; i < len; i++) {
|
|
538
|
-
VALUE key = resp_read(
|
|
539
|
-
VALUE value = resp_read(
|
|
538
|
+
VALUE key = resp_read(io, out_buffer);
|
|
539
|
+
VALUE value = resp_read(io, out_buffer);
|
|
540
540
|
rb_hash_aset(hash, key, value);
|
|
541
541
|
RB_GC_GUARD(key);
|
|
542
542
|
RB_GC_GUARD(value);
|
|
@@ -546,11 +546,11 @@ VALUE resp_decode_hash(struct um_connection *conn, VALUE out_buffer, ulong len)
|
|
|
546
546
|
return hash;
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
-
VALUE resp_decode_array(struct
|
|
549
|
+
VALUE resp_decode_array(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
550
550
|
VALUE array = rb_ary_new2(len);
|
|
551
551
|
|
|
552
552
|
for (ulong i = 0; i < len; i++) {
|
|
553
|
-
VALUE value = resp_read(
|
|
553
|
+
VALUE value = resp_read(io, out_buffer);
|
|
554
554
|
rb_ary_push(array, value);
|
|
555
555
|
RB_GC_GUARD(value);
|
|
556
556
|
}
|
|
@@ -563,12 +563,12 @@ static inline VALUE resp_decode_simple_string(char *ptr, ulong len) {
|
|
|
563
563
|
return rb_str_new(ptr + 1, len - 1);
|
|
564
564
|
}
|
|
565
565
|
|
|
566
|
-
static inline VALUE resp_decode_string(struct
|
|
567
|
-
return resp_read_string(
|
|
566
|
+
static inline VALUE resp_decode_string(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
567
|
+
return resp_read_string(io, len, out_buffer);
|
|
568
568
|
}
|
|
569
569
|
|
|
570
|
-
static inline VALUE resp_decode_string_with_encoding(struct
|
|
571
|
-
VALUE with_enc = resp_read_string(
|
|
570
|
+
static inline VALUE resp_decode_string_with_encoding(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
571
|
+
VALUE with_enc = resp_read_string(io, len, out_buffer);
|
|
572
572
|
char *ptr = RSTRING_PTR(with_enc);
|
|
573
573
|
len = RSTRING_LEN(with_enc);
|
|
574
574
|
if ((len < 4) || (ptr[3] != ':')) return Qnil;
|
|
@@ -591,23 +591,23 @@ static inline VALUE resp_decode_simple_error(char *ptr, ulong len) {
|
|
|
591
591
|
if (!ID_new) ID_new = rb_intern("new");
|
|
592
592
|
|
|
593
593
|
VALUE msg = rb_str_new(ptr + 1, len - 1);
|
|
594
|
-
VALUE err = rb_funcall(
|
|
594
|
+
VALUE err = rb_funcall(eIORESPError, ID_new, 1, msg);
|
|
595
595
|
RB_GC_GUARD(msg);
|
|
596
596
|
return err;
|
|
597
597
|
}
|
|
598
598
|
|
|
599
|
-
static inline VALUE resp_decode_error(struct
|
|
599
|
+
static inline VALUE resp_decode_error(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
600
600
|
static ID ID_new = 0;
|
|
601
601
|
if (!ID_new) ID_new = rb_intern("new");
|
|
602
602
|
|
|
603
|
-
VALUE msg = resp_decode_string(
|
|
604
|
-
VALUE err = rb_funcall(
|
|
603
|
+
VALUE msg = resp_decode_string(io, out_buffer, len);
|
|
604
|
+
VALUE err = rb_funcall(eIORESPError, ID_new, 1, msg);
|
|
605
605
|
RB_GC_GUARD(msg);
|
|
606
606
|
return err;
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
-
VALUE resp_read(struct
|
|
610
|
-
VALUE msg = resp_read_line(
|
|
609
|
+
VALUE resp_read(struct um_io *io, VALUE out_buffer) {
|
|
610
|
+
VALUE msg = resp_read_line(io, out_buffer);
|
|
611
611
|
if (msg == Qnil) return Qnil;
|
|
612
612
|
|
|
613
613
|
char *ptr = RSTRING_PTR(msg);
|
|
@@ -619,22 +619,22 @@ VALUE resp_read(struct um_connection *conn, VALUE out_buffer) {
|
|
|
619
619
|
case '%': // hash
|
|
620
620
|
case '|': // attributes hash
|
|
621
621
|
data_len = resp_parse_length_field(ptr, len);
|
|
622
|
-
return resp_decode_hash(
|
|
622
|
+
return resp_decode_hash(io, out_buffer, data_len);
|
|
623
623
|
|
|
624
624
|
case '*': // array
|
|
625
625
|
case '~': // set
|
|
626
626
|
case '>': // pub/sub push
|
|
627
627
|
data_len = resp_parse_length_field(ptr, len);
|
|
628
|
-
return resp_decode_array(
|
|
628
|
+
return resp_decode_array(io, out_buffer, data_len);
|
|
629
629
|
|
|
630
630
|
case '+': // simple string
|
|
631
631
|
return resp_decode_simple_string(ptr, len);
|
|
632
632
|
case '$': // string
|
|
633
633
|
data_len = resp_parse_length_field(ptr, len);
|
|
634
|
-
return resp_decode_string(
|
|
634
|
+
return resp_decode_string(io, out_buffer, data_len);
|
|
635
635
|
case '=': // string with encoding
|
|
636
636
|
data_len = resp_parse_length_field(ptr, len);
|
|
637
|
-
return resp_decode_string_with_encoding(
|
|
637
|
+
return resp_decode_string_with_encoding(io, out_buffer, data_len);
|
|
638
638
|
|
|
639
639
|
case '_': // null
|
|
640
640
|
return Qnil;
|
|
@@ -652,7 +652,7 @@ VALUE resp_read(struct um_connection *conn, VALUE out_buffer) {
|
|
|
652
652
|
return resp_decode_simple_error(ptr, len);
|
|
653
653
|
case '!': // error
|
|
654
654
|
data_len = resp_parse_length_field(ptr, len);
|
|
655
|
-
return resp_decode_error(
|
|
655
|
+
return resp_decode_error(io, out_buffer, data_len);
|
|
656
656
|
default:
|
|
657
657
|
um_raise_internal_error("Invalid character encountered");
|
|
658
658
|
}
|