uringmachine 0.31.0 → 0.33.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 +9 -0
- data/README.md +36 -37
- data/TODO.md +40 -59
- 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/docs/um_api.md +4 -9
- 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.c +21 -76
- data/ext/um/um.h +22 -41
- data/ext/um/um_class.c +11 -65
- data/ext/um/um_ext.c +2 -4
- data/ext/um/{um_connection.c → um_io.c} +209 -210
- data/ext/um/{um_connection_class.c → um_io_class.c} +102 -102
- data/ext/um/um_op.c +0 -1
- data/ext/um/um_utils.c +0 -86
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +12 -12
- data/test/{test_connection.rb → test_io.rb} +63 -63
- data/test/test_um.rb +17 -95
- 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,141 @@ 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
|
-
// connection_multishot_op_start(conn);
|
|
178
|
+
um_op_release(io->machine, io->op);
|
|
179
|
+
io->op = NULL;
|
|
181
180
|
}
|
|
182
181
|
else {
|
|
183
|
-
um_op_release(
|
|
184
|
-
|
|
182
|
+
um_op_release(io->machine, io->op);
|
|
183
|
+
io->op = NULL;
|
|
185
184
|
}
|
|
186
185
|
|
|
187
186
|
if (total_bytes) return total_bytes;
|
|
188
187
|
}
|
|
189
188
|
else {
|
|
190
189
|
if (more)
|
|
191
|
-
|
|
192
|
-
if (total_bytes ||
|
|
190
|
+
io->op->flags &= ~OP_F_CQE_SEEN;
|
|
191
|
+
if (total_bytes || io->eof) return total_bytes;
|
|
193
192
|
}
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
195
|
|
|
197
|
-
int
|
|
198
|
-
if (!
|
|
199
|
-
|
|
196
|
+
int io_get_more_segments_ssl(struct um_io *io) {
|
|
197
|
+
if (!io->working_buffer)
|
|
198
|
+
io->working_buffer = bp_buffer_checkout(io->machine);
|
|
200
199
|
|
|
201
|
-
char *ptr =
|
|
202
|
-
size_t maxlen =
|
|
203
|
-
int res = um_ssl_read_raw(
|
|
200
|
+
char *ptr = io->working_buffer->buf + io->working_buffer->pos;
|
|
201
|
+
size_t maxlen = io->working_buffer->len - io->working_buffer->pos;
|
|
202
|
+
int res = um_ssl_read_raw(io->machine, io->target, ptr, maxlen);
|
|
204
203
|
if (res == 0) return 0;
|
|
205
204
|
if (res < 0) rb_raise(eUMError, "Failed to read segment");
|
|
206
205
|
|
|
207
|
-
struct um_segment *segment = bp_buffer_consume(
|
|
206
|
+
struct um_segment *segment = bp_buffer_consume(io->machine, io->working_buffer, res);
|
|
208
207
|
if ((size_t)res == maxlen) {
|
|
209
|
-
bp_buffer_checkin(
|
|
210
|
-
|
|
208
|
+
bp_buffer_checkin(io->machine, io->working_buffer);
|
|
209
|
+
io->working_buffer = NULL;
|
|
211
210
|
}
|
|
212
|
-
|
|
211
|
+
io_add_segment(io, segment);
|
|
213
212
|
return 1;
|
|
214
213
|
}
|
|
215
214
|
|
|
216
|
-
int
|
|
217
|
-
switch (
|
|
218
|
-
case
|
|
219
|
-
case
|
|
220
|
-
return
|
|
221
|
-
case
|
|
222
|
-
return
|
|
215
|
+
int io_get_more_segments(struct um_io *io) {
|
|
216
|
+
switch (io->mode) {
|
|
217
|
+
case IO_FD:
|
|
218
|
+
case IO_SOCKET:
|
|
219
|
+
return io_get_more_segments_bp(io);
|
|
220
|
+
case IO_SSL:
|
|
221
|
+
return io_get_more_segments_ssl(io);
|
|
223
222
|
default:
|
|
224
|
-
rb_raise(eUMError, "Invalid
|
|
223
|
+
rb_raise(eUMError, "Invalid IO mode");
|
|
225
224
|
}
|
|
226
225
|
}
|
|
227
226
|
|
|
228
227
|
////////////////////////////////////////////////////////////////////////////////
|
|
229
228
|
|
|
230
|
-
inline void
|
|
231
|
-
struct um_segment *consumed =
|
|
232
|
-
|
|
233
|
-
if (!
|
|
234
|
-
um_segment_checkin(
|
|
235
|
-
|
|
229
|
+
inline void io_shift_head(struct um_io *io) {
|
|
230
|
+
struct um_segment *consumed = io->head;
|
|
231
|
+
io->head = consumed->next;
|
|
232
|
+
if (!io->head) io->tail = NULL;
|
|
233
|
+
um_segment_checkin(io->machine, consumed);
|
|
234
|
+
io->pos = 0;
|
|
236
235
|
}
|
|
237
236
|
|
|
238
237
|
inline VALUE make_segment_io_buffer(struct um_segment *segment, size_t pos) {
|
|
@@ -242,32 +241,32 @@ inline VALUE make_segment_io_buffer(struct um_segment *segment, size_t pos) {
|
|
|
242
241
|
);
|
|
243
242
|
}
|
|
244
243
|
|
|
245
|
-
inline void
|
|
246
|
-
if (unlikely(
|
|
247
|
-
if (safe_inc && !
|
|
244
|
+
inline void io_skip(struct um_io *io, size_t inc, int safe_inc) {
|
|
245
|
+
if (unlikely(io->eof && !io->head)) return;
|
|
246
|
+
if (safe_inc && !io->tail && !io_get_more_segments(io)) return;
|
|
248
247
|
|
|
249
248
|
while (inc) {
|
|
250
|
-
size_t segment_len =
|
|
249
|
+
size_t segment_len = io->head->len - io->pos;
|
|
251
250
|
size_t inc_len = (segment_len <= inc) ? segment_len : inc;
|
|
252
251
|
inc -= inc_len;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
|
|
258
|
-
if (inc && safe_inc && !
|
|
259
|
-
if (!
|
|
252
|
+
io->pos += inc_len;
|
|
253
|
+
io->consumed_bytes += inc_len;
|
|
254
|
+
io->pending_bytes -= inc_len;
|
|
255
|
+
if (io->pos == io->head->len) {
|
|
256
|
+
io_shift_head(io);
|
|
257
|
+
if (inc && safe_inc && !io->head) {
|
|
258
|
+
if (!io_get_more_segments(io)) break;
|
|
260
259
|
}
|
|
261
260
|
}
|
|
262
261
|
}
|
|
263
262
|
}
|
|
264
263
|
|
|
265
|
-
inline void
|
|
266
|
-
if (unlikely(
|
|
267
|
-
if (!
|
|
264
|
+
inline void io_read_each(struct um_io *io) {
|
|
265
|
+
if (unlikely(io->eof && !io->head)) return;
|
|
266
|
+
if (!io->tail && !io_get_more_segments(io)) return;
|
|
268
267
|
|
|
269
|
-
struct um_segment *current =
|
|
270
|
-
size_t pos =
|
|
268
|
+
struct um_segment *current = io->head;
|
|
269
|
+
size_t pos = io->pos;
|
|
271
270
|
|
|
272
271
|
VALUE buffer = Qnil;
|
|
273
272
|
while (true) {
|
|
@@ -275,34 +274,34 @@ inline void connection_read_each(struct um_connection *conn) {
|
|
|
275
274
|
buffer = make_segment_io_buffer(current, pos);
|
|
276
275
|
rb_yield(buffer);
|
|
277
276
|
rb_io_buffer_free_locked(buffer);
|
|
278
|
-
|
|
277
|
+
io_shift_head(io);
|
|
279
278
|
|
|
280
279
|
if (!next) {
|
|
281
|
-
if (!
|
|
280
|
+
if (!io_get_more_segments(io)) return;
|
|
282
281
|
}
|
|
283
|
-
current =
|
|
282
|
+
current = io->head;
|
|
284
283
|
pos = 0;
|
|
285
284
|
}
|
|
286
285
|
RB_GC_GUARD(buffer);
|
|
287
286
|
}
|
|
288
287
|
|
|
289
|
-
inline void
|
|
288
|
+
inline void io_copy(struct um_io *io, char *dest, size_t len) {
|
|
290
289
|
while (len) {
|
|
291
|
-
char *segment_ptr =
|
|
292
|
-
size_t segment_len =
|
|
290
|
+
char *segment_ptr = io->head->ptr + io->pos;
|
|
291
|
+
size_t segment_len = io->head->len - io->pos;
|
|
293
292
|
size_t cpy_len = (segment_len <= len) ? segment_len : len;
|
|
294
293
|
memcpy(dest, segment_ptr, cpy_len);
|
|
295
294
|
|
|
296
295
|
len -= cpy_len;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
296
|
+
io->pos += cpy_len;
|
|
297
|
+
io->consumed_bytes += cpy_len;
|
|
298
|
+
io->pending_bytes -= cpy_len;
|
|
300
299
|
dest += cpy_len;
|
|
301
|
-
if (
|
|
300
|
+
if (io->pos == io->head->len) io_shift_head(io);
|
|
302
301
|
}
|
|
303
302
|
}
|
|
304
303
|
|
|
305
|
-
VALUE
|
|
304
|
+
VALUE io_consume_string(struct um_io *io, VALUE out_buffer, size_t len, size_t inc, int safe_inc) {
|
|
306
305
|
VALUE str = Qnil;
|
|
307
306
|
if (!NIL_P(out_buffer)) {
|
|
308
307
|
str = out_buffer;
|
|
@@ -316,8 +315,8 @@ VALUE connection_consume_string(struct um_connection *conn, VALUE out_buffer, si
|
|
|
316
315
|
str = rb_str_new(NULL, len);
|
|
317
316
|
char *dest = RSTRING_PTR(str);
|
|
318
317
|
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
io_copy(io, dest, len);
|
|
319
|
+
io_skip(io, inc, safe_inc);
|
|
321
320
|
return str;
|
|
322
321
|
RB_GC_GUARD(str);
|
|
323
322
|
}
|
|
@@ -326,16 +325,16 @@ inline int trailing_cr_p(char *ptr, size_t len) {
|
|
|
326
325
|
return ptr[len - 1] == '\r';
|
|
327
326
|
}
|
|
328
327
|
|
|
329
|
-
VALUE
|
|
330
|
-
if (unlikely(
|
|
331
|
-
if (!
|
|
328
|
+
VALUE io_read_line(struct um_io *io, VALUE out_buffer, size_t maxlen) {
|
|
329
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
330
|
+
if (!io->tail && !io_get_more_segments(io)) return Qnil;
|
|
332
331
|
|
|
333
332
|
struct um_segment *last = NULL;
|
|
334
|
-
struct um_segment *current =
|
|
333
|
+
struct um_segment *current = io->head;
|
|
335
334
|
size_t remaining_len = maxlen;
|
|
336
335
|
size_t total_len = 0;
|
|
337
336
|
size_t inc = 1;
|
|
338
|
-
size_t pos =
|
|
337
|
+
size_t pos = io->pos;
|
|
339
338
|
|
|
340
339
|
while (true) {
|
|
341
340
|
size_t segment_len = current->len - pos;
|
|
@@ -359,7 +358,7 @@ VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t
|
|
|
359
358
|
}
|
|
360
359
|
}
|
|
361
360
|
|
|
362
|
-
return
|
|
361
|
+
return io_consume_string(io, out_buffer, total_len, inc, false);
|
|
363
362
|
}
|
|
364
363
|
else {
|
|
365
364
|
// not found, early return if segment len exceeds maxlen
|
|
@@ -370,7 +369,7 @@ VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t
|
|
|
370
369
|
}
|
|
371
370
|
|
|
372
371
|
if (!current->next) {
|
|
373
|
-
if (!
|
|
372
|
+
if (!io_get_more_segments(io)) {
|
|
374
373
|
return Qnil;
|
|
375
374
|
}
|
|
376
375
|
}
|
|
@@ -381,15 +380,15 @@ VALUE connection_read_line(struct um_connection *conn, VALUE out_buffer, size_t
|
|
|
381
380
|
}
|
|
382
381
|
}
|
|
383
382
|
|
|
384
|
-
VALUE
|
|
385
|
-
if (unlikely(
|
|
386
|
-
if (!
|
|
383
|
+
VALUE io_read(struct um_io *io, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc) {
|
|
384
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
385
|
+
if (!io->tail && !io_get_more_segments(io)) return Qnil;
|
|
387
386
|
|
|
388
|
-
struct um_segment *current =
|
|
387
|
+
struct um_segment *current = io->head;
|
|
389
388
|
size_t abs_len = labs(len);
|
|
390
389
|
size_t remaining_len = abs_len;
|
|
391
390
|
size_t total_len = 0;
|
|
392
|
-
size_t pos =
|
|
391
|
+
size_t pos = io->pos;
|
|
393
392
|
|
|
394
393
|
while (true) {
|
|
395
394
|
size_t segment_len = current->len - pos;
|
|
@@ -400,14 +399,14 @@ VALUE connection_read(struct um_connection *conn, VALUE out_buffer, ssize_t len,
|
|
|
400
399
|
if (abs_len) {
|
|
401
400
|
remaining_len -= segment_len;
|
|
402
401
|
if (!remaining_len)
|
|
403
|
-
return
|
|
402
|
+
return io_consume_string(io, out_buffer, total_len, inc, safe_inc);
|
|
404
403
|
}
|
|
405
404
|
|
|
406
405
|
if (!current->next) {
|
|
407
406
|
if (len <= 0)
|
|
408
|
-
return
|
|
407
|
+
return io_consume_string(io, out_buffer, total_len, inc, safe_inc);
|
|
409
408
|
|
|
410
|
-
if (!
|
|
409
|
+
if (!io_get_more_segments(io))
|
|
411
410
|
return Qnil;
|
|
412
411
|
}
|
|
413
412
|
current = current->next;
|
|
@@ -425,17 +424,17 @@ static inline char delim_to_char(VALUE delim) {
|
|
|
425
424
|
return *RSTRING_PTR(delim);
|
|
426
425
|
}
|
|
427
426
|
|
|
428
|
-
VALUE
|
|
427
|
+
VALUE io_read_to_delim(struct um_io *io, VALUE out_buffer, VALUE delim, ssize_t maxlen) {
|
|
429
428
|
char delim_char = delim_to_char(delim);
|
|
430
429
|
|
|
431
|
-
if (unlikely(
|
|
432
|
-
if (unlikely(!
|
|
430
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
431
|
+
if (unlikely(!io->tail) && !io_get_more_segments(io)) return Qnil;
|
|
433
432
|
|
|
434
|
-
struct um_segment *current =
|
|
433
|
+
struct um_segment *current = io->head;
|
|
435
434
|
size_t abs_maxlen = labs(maxlen);
|
|
436
435
|
size_t remaining_len = abs_maxlen;
|
|
437
436
|
size_t total_len = 0;
|
|
438
|
-
size_t pos =
|
|
437
|
+
size_t pos = io->pos;
|
|
439
438
|
|
|
440
439
|
while (true) {
|
|
441
440
|
size_t segment_len = current->len - pos;
|
|
@@ -447,7 +446,7 @@ VALUE connection_read_to_delim(struct um_connection *conn, VALUE out_buffer, VAL
|
|
|
447
446
|
if (delim_ptr) {
|
|
448
447
|
size_t len = delim_ptr - start;
|
|
449
448
|
total_len += len;
|
|
450
|
-
return
|
|
449
|
+
return io_consume_string(io, out_buffer, total_len, 1, false);
|
|
451
450
|
}
|
|
452
451
|
else {
|
|
453
452
|
// delimiter not found
|
|
@@ -455,51 +454,51 @@ VALUE connection_read_to_delim(struct um_connection *conn, VALUE out_buffer, VAL
|
|
|
455
454
|
remaining_len -= search_len;
|
|
456
455
|
|
|
457
456
|
if (abs_maxlen && total_len >= abs_maxlen)
|
|
458
|
-
return (maxlen > 0) ? Qnil :
|
|
457
|
+
return (maxlen > 0) ? Qnil : io_consume_string(io, out_buffer, abs_maxlen, 1, false);
|
|
459
458
|
}
|
|
460
459
|
|
|
461
|
-
if (!current->next && !
|
|
460
|
+
if (!current->next && !io_get_more_segments(io)) return Qnil;
|
|
462
461
|
|
|
463
462
|
current = current->next;
|
|
464
463
|
pos = 0;
|
|
465
464
|
}
|
|
466
465
|
}
|
|
467
466
|
|
|
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(
|
|
467
|
+
size_t io_write_raw(struct um_io *io, const char *buffer, size_t len) {
|
|
468
|
+
switch (io->mode) {
|
|
469
|
+
case IO_FD:
|
|
470
|
+
return um_write_raw(io->machine, io->fd, buffer, len);
|
|
471
|
+
case IO_SOCKET:
|
|
472
|
+
return um_send_raw(io->machine, io->fd, buffer, len, 0);
|
|
473
|
+
case IO_SSL:
|
|
474
|
+
return um_ssl_write_raw(io->machine, io->target, buffer, len);
|
|
476
475
|
default:
|
|
477
|
-
rb_raise(eUMError, "Invalid
|
|
476
|
+
rb_raise(eUMError, "Invalid IO mode");
|
|
478
477
|
}
|
|
479
478
|
}
|
|
480
479
|
|
|
481
|
-
VALUE
|
|
482
|
-
switch (
|
|
483
|
-
case
|
|
484
|
-
return um_writev(
|
|
485
|
-
case
|
|
486
|
-
return um_sendv(
|
|
487
|
-
case
|
|
488
|
-
return ULONG2NUM(um_ssl_writev(
|
|
480
|
+
VALUE io_writev(struct um_io *io, int argc, VALUE *argv) {
|
|
481
|
+
switch (io->mode) {
|
|
482
|
+
case IO_FD:
|
|
483
|
+
return um_writev(io->machine, io->fd, argc, argv);
|
|
484
|
+
case IO_SOCKET:
|
|
485
|
+
return um_sendv(io->machine, io->fd, argc, argv);
|
|
486
|
+
case IO_SSL:
|
|
487
|
+
return ULONG2NUM(um_ssl_writev(io->machine, io->target, argc, argv));
|
|
489
488
|
default:
|
|
490
|
-
rb_raise(eUMError, "Invalid
|
|
489
|
+
rb_raise(eUMError, "Invalid IO mode");
|
|
491
490
|
}
|
|
492
491
|
}
|
|
493
492
|
|
|
494
493
|
////////////////////////////////////////////////////////////////////////////////
|
|
495
494
|
|
|
496
|
-
VALUE resp_read_line(struct
|
|
497
|
-
if (unlikely(
|
|
498
|
-
if (!
|
|
495
|
+
VALUE resp_read_line(struct um_io *io, VALUE out_buffer) {
|
|
496
|
+
if (unlikely(io->eof && !io->head)) return Qnil;
|
|
497
|
+
if (!io->tail && !io_get_more_segments(io)) return Qnil;
|
|
499
498
|
|
|
500
|
-
struct um_segment *current =
|
|
499
|
+
struct um_segment *current = io->head;
|
|
501
500
|
size_t total_len = 0;
|
|
502
|
-
size_t pos =
|
|
501
|
+
size_t pos = io->pos;
|
|
503
502
|
|
|
504
503
|
while (true) {
|
|
505
504
|
size_t segment_len = current->len - pos;
|
|
@@ -508,20 +507,20 @@ VALUE resp_read_line(struct um_connection *conn, VALUE out_buffer) {
|
|
|
508
507
|
if (lf_ptr) {
|
|
509
508
|
size_t len = lf_ptr - start;
|
|
510
509
|
total_len += len;
|
|
511
|
-
return
|
|
510
|
+
return io_consume_string(io, out_buffer, total_len, 2, true);
|
|
512
511
|
}
|
|
513
512
|
else
|
|
514
513
|
total_len += segment_len;
|
|
515
514
|
|
|
516
515
|
if (!current->next)
|
|
517
|
-
if (!
|
|
516
|
+
if (!io_get_more_segments(io)) return Qnil;
|
|
518
517
|
|
|
519
518
|
current = current->next;
|
|
520
519
|
}
|
|
521
520
|
}
|
|
522
521
|
|
|
523
|
-
inline VALUE resp_read_string(struct
|
|
524
|
-
return
|
|
522
|
+
inline VALUE resp_read_string(struct um_io *io, ulong len, VALUE out_buffer) {
|
|
523
|
+
return io_read(io, out_buffer, len, 2, true);
|
|
525
524
|
}
|
|
526
525
|
|
|
527
526
|
inline ulong resp_parse_length_field(const char *ptr, int len) {
|
|
@@ -531,12 +530,12 @@ inline ulong resp_parse_length_field(const char *ptr, int len) {
|
|
|
531
530
|
return acc;
|
|
532
531
|
}
|
|
533
532
|
|
|
534
|
-
VALUE resp_decode_hash(struct
|
|
533
|
+
VALUE resp_decode_hash(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
535
534
|
VALUE hash = rb_hash_new();
|
|
536
535
|
|
|
537
536
|
for (ulong i = 0; i < len; i++) {
|
|
538
|
-
VALUE key = resp_read(
|
|
539
|
-
VALUE value = resp_read(
|
|
537
|
+
VALUE key = resp_read(io, out_buffer);
|
|
538
|
+
VALUE value = resp_read(io, out_buffer);
|
|
540
539
|
rb_hash_aset(hash, key, value);
|
|
541
540
|
RB_GC_GUARD(key);
|
|
542
541
|
RB_GC_GUARD(value);
|
|
@@ -546,11 +545,11 @@ VALUE resp_decode_hash(struct um_connection *conn, VALUE out_buffer, ulong len)
|
|
|
546
545
|
return hash;
|
|
547
546
|
}
|
|
548
547
|
|
|
549
|
-
VALUE resp_decode_array(struct
|
|
548
|
+
VALUE resp_decode_array(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
550
549
|
VALUE array = rb_ary_new2(len);
|
|
551
550
|
|
|
552
551
|
for (ulong i = 0; i < len; i++) {
|
|
553
|
-
VALUE value = resp_read(
|
|
552
|
+
VALUE value = resp_read(io, out_buffer);
|
|
554
553
|
rb_ary_push(array, value);
|
|
555
554
|
RB_GC_GUARD(value);
|
|
556
555
|
}
|
|
@@ -563,12 +562,12 @@ static inline VALUE resp_decode_simple_string(char *ptr, ulong len) {
|
|
|
563
562
|
return rb_str_new(ptr + 1, len - 1);
|
|
564
563
|
}
|
|
565
564
|
|
|
566
|
-
static inline VALUE resp_decode_string(struct
|
|
567
|
-
return resp_read_string(
|
|
565
|
+
static inline VALUE resp_decode_string(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
566
|
+
return resp_read_string(io, len, out_buffer);
|
|
568
567
|
}
|
|
569
568
|
|
|
570
|
-
static inline VALUE resp_decode_string_with_encoding(struct
|
|
571
|
-
VALUE with_enc = resp_read_string(
|
|
569
|
+
static inline VALUE resp_decode_string_with_encoding(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
570
|
+
VALUE with_enc = resp_read_string(io, len, out_buffer);
|
|
572
571
|
char *ptr = RSTRING_PTR(with_enc);
|
|
573
572
|
len = RSTRING_LEN(with_enc);
|
|
574
573
|
if ((len < 4) || (ptr[3] != ':')) return Qnil;
|
|
@@ -591,23 +590,23 @@ static inline VALUE resp_decode_simple_error(char *ptr, ulong len) {
|
|
|
591
590
|
if (!ID_new) ID_new = rb_intern("new");
|
|
592
591
|
|
|
593
592
|
VALUE msg = rb_str_new(ptr + 1, len - 1);
|
|
594
|
-
VALUE err = rb_funcall(
|
|
593
|
+
VALUE err = rb_funcall(eIORESPError, ID_new, 1, msg);
|
|
595
594
|
RB_GC_GUARD(msg);
|
|
596
595
|
return err;
|
|
597
596
|
}
|
|
598
597
|
|
|
599
|
-
static inline VALUE resp_decode_error(struct
|
|
598
|
+
static inline VALUE resp_decode_error(struct um_io *io, VALUE out_buffer, ulong len) {
|
|
600
599
|
static ID ID_new = 0;
|
|
601
600
|
if (!ID_new) ID_new = rb_intern("new");
|
|
602
601
|
|
|
603
|
-
VALUE msg = resp_decode_string(
|
|
604
|
-
VALUE err = rb_funcall(
|
|
602
|
+
VALUE msg = resp_decode_string(io, out_buffer, len);
|
|
603
|
+
VALUE err = rb_funcall(eIORESPError, ID_new, 1, msg);
|
|
605
604
|
RB_GC_GUARD(msg);
|
|
606
605
|
return err;
|
|
607
606
|
}
|
|
608
607
|
|
|
609
|
-
VALUE resp_read(struct
|
|
610
|
-
VALUE msg = resp_read_line(
|
|
608
|
+
VALUE resp_read(struct um_io *io, VALUE out_buffer) {
|
|
609
|
+
VALUE msg = resp_read_line(io, out_buffer);
|
|
611
610
|
if (msg == Qnil) return Qnil;
|
|
612
611
|
|
|
613
612
|
char *ptr = RSTRING_PTR(msg);
|
|
@@ -619,22 +618,22 @@ VALUE resp_read(struct um_connection *conn, VALUE out_buffer) {
|
|
|
619
618
|
case '%': // hash
|
|
620
619
|
case '|': // attributes hash
|
|
621
620
|
data_len = resp_parse_length_field(ptr, len);
|
|
622
|
-
return resp_decode_hash(
|
|
621
|
+
return resp_decode_hash(io, out_buffer, data_len);
|
|
623
622
|
|
|
624
623
|
case '*': // array
|
|
625
624
|
case '~': // set
|
|
626
625
|
case '>': // pub/sub push
|
|
627
626
|
data_len = resp_parse_length_field(ptr, len);
|
|
628
|
-
return resp_decode_array(
|
|
627
|
+
return resp_decode_array(io, out_buffer, data_len);
|
|
629
628
|
|
|
630
629
|
case '+': // simple string
|
|
631
630
|
return resp_decode_simple_string(ptr, len);
|
|
632
631
|
case '$': // string
|
|
633
632
|
data_len = resp_parse_length_field(ptr, len);
|
|
634
|
-
return resp_decode_string(
|
|
633
|
+
return resp_decode_string(io, out_buffer, data_len);
|
|
635
634
|
case '=': // string with encoding
|
|
636
635
|
data_len = resp_parse_length_field(ptr, len);
|
|
637
|
-
return resp_decode_string_with_encoding(
|
|
636
|
+
return resp_decode_string_with_encoding(io, out_buffer, data_len);
|
|
638
637
|
|
|
639
638
|
case '_': // null
|
|
640
639
|
return Qnil;
|
|
@@ -652,7 +651,7 @@ VALUE resp_read(struct um_connection *conn, VALUE out_buffer) {
|
|
|
652
651
|
return resp_decode_simple_error(ptr, len);
|
|
653
652
|
case '!': // error
|
|
654
653
|
data_len = resp_parse_length_field(ptr, len);
|
|
655
|
-
return resp_decode_error(
|
|
654
|
+
return resp_decode_error(io, out_buffer, data_len);
|
|
656
655
|
default:
|
|
657
656
|
um_raise_internal_error("Invalid character encountered");
|
|
658
657
|
}
|