polyphony 0.87 → 0.91
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_io_uring.yml +8 -4
- data/CHANGELOG.md +18 -0
- data/Gemfile.lock +1 -1
- data/examples/pipes/echo_server.rb +17 -0
- data/examples/pipes/gunzip.rb +6 -0
- data/examples/pipes/gzip.rb +6 -0
- data/examples/pipes/gzip_http_server.rb +49 -0
- data/examples/pipes/tcp_proxy.rb +28 -0
- data/examples/pipes/tee.rb +15 -0
- data/ext/polyphony/backend_common.c +10 -10
- data/ext/polyphony/backend_io_uring.c +175 -51
- data/ext/polyphony/backend_libev.c +25 -25
- data/ext/polyphony/extconf.rb +4 -2
- data/ext/polyphony/io_extensions.c +132 -57
- data/ext/polyphony/polyphony.c +12 -9
- data/ext/polyphony/polyphony.h +7 -0
- data/ext/polyphony/queue.c +3 -3
- data/ext/polyphony/socket_extensions.c +2 -2
- data/lib/polyphony/extensions/io.rb +4 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/stress.rb +1 -1
- data/test/test_io.rb +229 -9
- data/test/test_signal.rb +6 -2
- metadata +8 -2
@@ -291,7 +291,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
291
291
|
rb_io_t *fptr;
|
292
292
|
|
293
293
|
struct io_buffer buffer = get_io_buffer(str);
|
294
|
-
long buf_pos =
|
294
|
+
long buf_pos = FIX2INT(pos);
|
295
295
|
int shrinkable_string = 0;
|
296
296
|
int expandable_buffer = 0;
|
297
297
|
long total = 0;
|
@@ -311,7 +311,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
311
311
|
|
312
312
|
if (string_cap < expected_read_length + buf_pos) {
|
313
313
|
shrinkable_string = io_setstrbuf(&str, expected_read_length + buf_pos);
|
314
|
-
buffer.ptr = RSTRING_PTR(str) + buf_pos;
|
314
|
+
buffer.ptr = (unsigned char *)RSTRING_PTR(str) + buf_pos;
|
315
315
|
buffer.len = expected_read_length;
|
316
316
|
}
|
317
317
|
else {
|
@@ -353,7 +353,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
|
|
353
353
|
rb_str_resize(str, total + buf_pos);
|
354
354
|
rb_str_modify_expand(str, rb_str_capacity(str));
|
355
355
|
shrinkable_string = 0;
|
356
|
-
buffer.ptr = RSTRING_PTR(str) + total + buf_pos;
|
356
|
+
buffer.ptr = (unsigned char *)RSTRING_PTR(str) + total + buf_pos;
|
357
357
|
buffer.len = rb_str_capacity(str) - total - buf_pos;
|
358
358
|
}
|
359
359
|
else {
|
@@ -389,7 +389,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
|
|
389
389
|
rb_io_t *fptr;
|
390
390
|
VALUE str;
|
391
391
|
long total;
|
392
|
-
long len =
|
392
|
+
long len = FIX2INT(maxlen);
|
393
393
|
int shrinkable;
|
394
394
|
char *buf;
|
395
395
|
VALUE switchpoint_result = Qnil;
|
@@ -519,7 +519,7 @@ VALUE Backend_write(VALUE self, VALUE io, VALUE str) {
|
|
519
519
|
RB_GC_GUARD(watcher.fiber);
|
520
520
|
RB_GC_GUARD(switchpoint_result);
|
521
521
|
|
522
|
-
return
|
522
|
+
return INT2FIX(buffer.len);
|
523
523
|
error:
|
524
524
|
return RAISE_EXCEPTION(switchpoint_result);
|
525
525
|
}
|
@@ -590,7 +590,7 @@ VALUE Backend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
590
590
|
RB_GC_GUARD(switchpoint_result);
|
591
591
|
|
592
592
|
free(iov);
|
593
|
-
return
|
593
|
+
return INT2FIX(total_written);
|
594
594
|
error:
|
595
595
|
free(iov);
|
596
596
|
return RAISE_EXCEPTION(switchpoint_result);
|
@@ -763,7 +763,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
763
763
|
|
764
764
|
struct io_buffer buffer = get_io_buffer(str);
|
765
765
|
long left = buffer.len;
|
766
|
-
int flags_int =
|
766
|
+
int flags_int = FIX2INT(flags);
|
767
767
|
|
768
768
|
GetBackend(self, backend);
|
769
769
|
fd = fd_from_io(io, &fptr, 1, 0);
|
@@ -795,7 +795,7 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str, VALUE flags) {
|
|
795
795
|
RB_GC_GUARD(watcher.fiber);
|
796
796
|
RB_GC_GUARD(switchpoint_result);
|
797
797
|
|
798
|
-
return
|
798
|
+
return INT2FIX(buffer.len);
|
799
799
|
error:
|
800
800
|
return RAISE_EXCEPTION(switchpoint_result);
|
801
801
|
}
|
@@ -868,7 +868,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
868
868
|
|
869
869
|
while (1) {
|
870
870
|
backend->base.op_count++;
|
871
|
-
len = splice(src_fd, 0, dest_fd, 0,
|
871
|
+
len = splice(src_fd, 0, dest_fd, 0, FIX2INT(maxlen), 0);
|
872
872
|
if (len < 0) {
|
873
873
|
int e = errno;
|
874
874
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -889,7 +889,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
889
889
|
RB_GC_GUARD(watcher.ctx.fiber);
|
890
890
|
RB_GC_GUARD(switchpoint_result);
|
891
891
|
|
892
|
-
return
|
892
|
+
return INT2FIX(len);
|
893
893
|
error:
|
894
894
|
return RAISE_EXCEPTION(switchpoint_result);
|
895
895
|
}
|
@@ -912,7 +912,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
912
912
|
|
913
913
|
while (1) {
|
914
914
|
backend->base.op_count++;
|
915
|
-
len = splice(src_fd, 0, dest_fd, 0,
|
915
|
+
len = splice(src_fd, 0, dest_fd, 0, FIX2INT(maxlen), 0);
|
916
916
|
if (len < 0) {
|
917
917
|
int e = errno;
|
918
918
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -936,7 +936,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
936
936
|
RB_GC_GUARD(watcher.ctx.fiber);
|
937
937
|
RB_GC_GUARD(switchpoint_result);
|
938
938
|
|
939
|
-
return
|
939
|
+
return INT2FIX(total);
|
940
940
|
error:
|
941
941
|
return RAISE_EXCEPTION(switchpoint_result);
|
942
942
|
}
|
@@ -958,7 +958,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
958
958
|
|
959
959
|
while (1) {
|
960
960
|
backend->base.op_count++;
|
961
|
-
len = tee(src_fd, dest_fd,
|
961
|
+
len = tee(src_fd, dest_fd, FIX2INT(maxlen), 0);
|
962
962
|
if (len < 0) {
|
963
963
|
int e = errno;
|
964
964
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
@@ -979,7 +979,7 @@ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
979
979
|
RB_GC_GUARD(watcher.ctx.fiber);
|
980
980
|
RB_GC_GUARD(switchpoint_result);
|
981
981
|
|
982
|
-
return
|
982
|
+
return INT2FIX(len);
|
983
983
|
error:
|
984
984
|
return RAISE_EXCEPTION(switchpoint_result);
|
985
985
|
}
|
@@ -994,7 +994,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
994
994
|
int dest_fd;
|
995
995
|
rb_io_t *src_fptr;
|
996
996
|
rb_io_t *dest_fptr;
|
997
|
-
int len =
|
997
|
+
int len = FIX2INT(maxlen);
|
998
998
|
VALUE str = rb_str_new(0, len);
|
999
999
|
char *buf = RSTRING_PTR(str);
|
1000
1000
|
int left = 0;
|
@@ -1047,7 +1047,7 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1047
1047
|
RB_GC_GUARD(switchpoint_result);
|
1048
1048
|
RB_GC_GUARD(str);
|
1049
1049
|
|
1050
|
-
return
|
1050
|
+
return INT2FIX(total);
|
1051
1051
|
error:
|
1052
1052
|
return RAISE_EXCEPTION(switchpoint_result);
|
1053
1053
|
}
|
@@ -1060,7 +1060,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
1060
1060
|
int dest_fd;
|
1061
1061
|
rb_io_t *src_fptr;
|
1062
1062
|
rb_io_t *dest_fptr;
|
1063
|
-
int len =
|
1063
|
+
int len = FIX2INT(maxlen);
|
1064
1064
|
VALUE str = rb_str_new(0, len);
|
1065
1065
|
char *buf = RSTRING_PTR(str);
|
1066
1066
|
int left = 0;
|
@@ -1118,7 +1118,7 @@ done:
|
|
1118
1118
|
RB_GC_GUARD(switchpoint_result);
|
1119
1119
|
RB_GC_GUARD(str);
|
1120
1120
|
|
1121
|
-
return
|
1121
|
+
return INT2FIX(total);
|
1122
1122
|
error:
|
1123
1123
|
return RAISE_EXCEPTION(switchpoint_result);
|
1124
1124
|
}
|
@@ -1263,7 +1263,7 @@ VALUE Backend_timeout(int argc,VALUE *argv, VALUE self) {
|
|
1263
1263
|
|
1264
1264
|
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
1265
1265
|
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
1266
|
-
int pid_int =
|
1266
|
+
int pid_int = FIX2INT(pid);
|
1267
1267
|
int fd = pidfd_open(pid_int, 0);
|
1268
1268
|
if (fd >= 0) {
|
1269
1269
|
Backend_t *backend;
|
@@ -1286,7 +1286,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1286
1286
|
int e = errno;
|
1287
1287
|
rb_syserr_fail(e, strerror(e));
|
1288
1288
|
}
|
1289
|
-
return rb_ary_new_from_args(2,
|
1289
|
+
return rb_ary_new_from_args(2, INT2FIX(ret), INT2FIX(WEXITSTATUS(status)));
|
1290
1290
|
}
|
1291
1291
|
#else
|
1292
1292
|
struct libev_child {
|
@@ -1299,7 +1299,7 @@ void Backend_child_callback(EV_P_ ev_child *w, int revents) {
|
|
1299
1299
|
int exit_status = WEXITSTATUS(w->rstatus);
|
1300
1300
|
VALUE status;
|
1301
1301
|
|
1302
|
-
status = rb_ary_new_from_args(2,
|
1302
|
+
status = rb_ary_new_from_args(2, INT2FIX(w->rpid), INT2FIX(exit_status));
|
1303
1303
|
Fiber_make_runnable(watcher->fiber, status);
|
1304
1304
|
}
|
1305
1305
|
|
@@ -1310,7 +1310,7 @@ VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
|
1310
1310
|
GetBackend(self, backend);
|
1311
1311
|
|
1312
1312
|
watcher.fiber = rb_fiber_current();
|
1313
|
-
ev_child_init(&watcher.child, Backend_child_callback,
|
1313
|
+
ev_child_init(&watcher.child, Backend_child_callback, FIX2INT(pid), 0);
|
1314
1314
|
ev_child_start(backend->ev_loop, &watcher.child);
|
1315
1315
|
backend->base.op_count++;
|
1316
1316
|
|
@@ -1491,7 +1491,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1491
1491
|
|
1492
1492
|
struct libev_rw_io watcher;
|
1493
1493
|
watcher.ctx.fiber = Qnil;
|
1494
|
-
int maxlen =
|
1494
|
+
int maxlen = FIX2INT(chunk_size);
|
1495
1495
|
VALUE str = Qnil;
|
1496
1496
|
VALUE chunk_len_value = Qnil;
|
1497
1497
|
|
@@ -1515,7 +1515,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1515
1515
|
if (chunk_len == 0) break;
|
1516
1516
|
|
1517
1517
|
total += chunk_len;
|
1518
|
-
chunk_len_value =
|
1518
|
+
chunk_len_value = INT2FIX(chunk_len);
|
1519
1519
|
|
1520
1520
|
if (chunk_prefix != Qnil) {
|
1521
1521
|
VALUE str = (TYPE(chunk_prefix) == T_STRING) ? chunk_prefix : rb_funcall(chunk_prefix, ID_call, 1, chunk_len_value);
|
@@ -1553,7 +1553,7 @@ VALUE Backend_splice_chunks(VALUE self, VALUE src, VALUE dest, VALUE prefix, VAL
|
|
1553
1553
|
RB_GC_GUARD(result);
|
1554
1554
|
if (pipefd[0] != -1) close(pipefd[0]);
|
1555
1555
|
if (pipefd[1] != -1) close(pipefd[1]);
|
1556
|
-
return
|
1556
|
+
return INT2FIX(total);
|
1557
1557
|
syscallerror:
|
1558
1558
|
if (pipefd[0] != -1) close(pipefd[0]);
|
1559
1559
|
if (pipefd[1] != -1) close(pipefd[1]);
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -47,6 +47,7 @@ end
|
|
47
47
|
$defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
|
48
48
|
if config[:io_uring]
|
49
49
|
$defs << "-DPOLYPHONY_BACKEND_LIBURING"
|
50
|
+
$defs << "-DPOLYPHONY_LINUX"
|
50
51
|
$defs << "-DPOLYPHONY_UNSET_NONBLOCK" if RUBY_VERSION =~ /^3/
|
51
52
|
$CFLAGS << " -Wno-pointer-arith"
|
52
53
|
else
|
@@ -70,7 +71,8 @@ $defs << '-DPOLYPHONY_PLAYGROUND' if ENV['POLYPHONY_PLAYGROUND']
|
|
70
71
|
|
71
72
|
CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
|
72
73
|
|
73
|
-
|
74
|
-
|
74
|
+
if RUBY_VERSION >= '3.1'
|
75
|
+
have_func('rb_fiber_transfer', 'ruby.h')
|
76
|
+
end
|
75
77
|
|
76
78
|
create_makefile 'polyphony_ext'
|
@@ -10,6 +10,7 @@
|
|
10
10
|
#include "polyphony.h"
|
11
11
|
#include "zlib.h"
|
12
12
|
#include "assert.h"
|
13
|
+
#include "ruby/thread.h"
|
13
14
|
|
14
15
|
ID ID_at;
|
15
16
|
ID ID_read_method;
|
@@ -29,6 +30,7 @@ VALUE SYM_orig_name;
|
|
29
30
|
VALUE SYM_readpartial;
|
30
31
|
|
31
32
|
enum read_method {
|
33
|
+
RM_STRING,
|
32
34
|
RM_BACKEND_READ,
|
33
35
|
RM_BACKEND_RECV,
|
34
36
|
RM_READPARTIAL,
|
@@ -36,13 +38,15 @@ enum read_method {
|
|
36
38
|
};
|
37
39
|
|
38
40
|
enum write_method {
|
41
|
+
WM_STRING,
|
39
42
|
WM_BACKEND_WRITE,
|
40
43
|
WM_BACKEND_SEND,
|
41
44
|
WM_WRITE,
|
42
45
|
WM_CALL
|
43
46
|
};
|
44
47
|
|
45
|
-
static enum read_method detect_read_method(VALUE io) {
|
48
|
+
static inline enum read_method detect_read_method(VALUE io) {
|
49
|
+
if (TYPE(io) == T_STRING) return RM_STRING;
|
46
50
|
if (rb_respond_to(io, ID_read_method)) {
|
47
51
|
VALUE method = rb_funcall(io, ID_read_method, 0);
|
48
52
|
if (method == SYM_readpartial) return RM_READPARTIAL;
|
@@ -58,7 +62,8 @@ static enum read_method detect_read_method(VALUE io) {
|
|
58
62
|
rb_raise(rb_eRuntimeError, "Given io instance should be a callable or respond to #__read_method__");
|
59
63
|
}
|
60
64
|
|
61
|
-
static enum write_method detect_write_method(VALUE io) {
|
65
|
+
static inline enum write_method detect_write_method(VALUE io) {
|
66
|
+
if (TYPE(io) == T_STRING) return WM_STRING;
|
62
67
|
if (rb_respond_to(io, ID_write_method)) {
|
63
68
|
VALUE method = rb_funcall(io, ID_write_method, 0);
|
64
69
|
if (method == SYM_readpartial) return WM_WRITE;
|
@@ -136,11 +141,18 @@ static inline int read_to_raw_buffer(VALUE backend, VALUE io, enum read_method m
|
|
136
141
|
RB_GC_GUARD(str);
|
137
142
|
return len;
|
138
143
|
}
|
144
|
+
default: {
|
145
|
+
rb_raise(rb_eRuntimeError, "Invalid read method");
|
146
|
+
}
|
139
147
|
}
|
140
148
|
}
|
141
149
|
|
142
150
|
static inline int write_from_raw_buffer(VALUE backend, VALUE io, enum write_method method, struct raw_buffer *buffer) {
|
143
151
|
switch (method) {
|
152
|
+
case WM_STRING: {
|
153
|
+
rb_str_buf_cat(io, (char *)buffer->ptr, buffer->len);
|
154
|
+
return buffer->len;
|
155
|
+
}
|
144
156
|
case WM_BACKEND_WRITE: {
|
145
157
|
VALUE len = Backend_write(backend, io, PTR2FIX(buffer));
|
146
158
|
return FIX2INT(len);
|
@@ -165,6 +177,9 @@ static inline int write_from_raw_buffer(VALUE backend, VALUE io, enum write_meth
|
|
165
177
|
RB_GC_GUARD(str);
|
166
178
|
return buffer->len;
|
167
179
|
}
|
180
|
+
default: {
|
181
|
+
rb_raise(rb_eRuntimeError, "Invalid write method");
|
182
|
+
}
|
168
183
|
}
|
169
184
|
}
|
170
185
|
|
@@ -228,7 +243,7 @@ static inline time_t time_from_object(VALUE o) {
|
|
228
243
|
return FIX2INT(rb_funcall(o, rb_intern("to_i"), 0));
|
229
244
|
}
|
230
245
|
|
231
|
-
int gzip_prepare_header(struct gzip_header_ctx *ctx, char *buffer, int maxlen) {
|
246
|
+
int gzip_prepare_header(struct gzip_header_ctx *ctx, unsigned char *buffer, int maxlen) {
|
232
247
|
int len = 0;
|
233
248
|
unsigned char flags = 0, extraflags = 0;
|
234
249
|
|
@@ -259,7 +274,7 @@ int gzip_prepare_header(struct gzip_header_ctx *ctx, char *buffer, int maxlen) {
|
|
259
274
|
return len;
|
260
275
|
}
|
261
276
|
|
262
|
-
int gzip_prepare_footer(unsigned long crc32, unsigned long total_in, char *buffer, int maxlen) {
|
277
|
+
static inline int gzip_prepare_footer(unsigned long crc32, unsigned long total_in, unsigned char *buffer, int maxlen) {
|
263
278
|
assert(maxlen >= GZIP_FOOTER_LEN);
|
264
279
|
|
265
280
|
gzfile_set32(crc32, buffer);
|
@@ -287,8 +302,8 @@ struct z_stream_ctx {
|
|
287
302
|
|
288
303
|
unsigned char in[CHUNK];
|
289
304
|
unsigned char out[CHUNK];
|
290
|
-
int in_pos;
|
291
|
-
int out_pos;
|
305
|
+
unsigned int in_pos;
|
306
|
+
unsigned int out_pos;
|
292
307
|
unsigned long in_total;
|
293
308
|
unsigned long out_total;
|
294
309
|
|
@@ -297,8 +312,8 @@ struct z_stream_ctx {
|
|
297
312
|
|
298
313
|
typedef int (*zlib_func)(z_streamp, int);
|
299
314
|
|
300
|
-
void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, int *in_pos, unsigned long *total_read) {
|
301
|
-
|
315
|
+
void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, unsigned int *in_pos, unsigned long *total_read) {
|
316
|
+
unsigned long null_pos;
|
302
317
|
// find null terminator
|
303
318
|
for (null_pos = *in_pos; null_pos < *total_read; null_pos++) {
|
304
319
|
if (!buffer->ptr[null_pos]) break;
|
@@ -306,28 +321,37 @@ void read_gzip_header_str(struct raw_buffer *buffer, VALUE *str, int *in_pos, un
|
|
306
321
|
if (null_pos == *total_read)
|
307
322
|
rb_raise(rb_eRuntimeError, "Invalid gzip header");
|
308
323
|
|
309
|
-
*str = rb_str_new_cstr(buffer->ptr + *in_pos);
|
324
|
+
*str = rb_str_new_cstr((char *)buffer->ptr + *in_pos);
|
310
325
|
*in_pos = null_pos + 1;
|
311
326
|
}
|
312
327
|
|
313
328
|
void gzip_read_header(struct z_stream_ctx *ctx, struct gzip_header_ctx *header_ctx) {
|
314
|
-
struct raw_buffer in_buffer
|
329
|
+
struct raw_buffer in_buffer;
|
315
330
|
int flags;
|
316
331
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
ctx->in_total
|
332
|
+
if (ctx->src_read_method == RM_STRING) {
|
333
|
+
in_buffer.ptr = (unsigned char *)RSTRING_PTR(ctx->src);
|
334
|
+
in_buffer.len = RSTRING_LEN(ctx->src);
|
335
|
+
ctx->in_total = in_buffer.len;
|
336
|
+
}
|
337
|
+
else {
|
338
|
+
in_buffer.ptr = ctx->in;
|
339
|
+
in_buffer.len = CHUNK;
|
340
|
+
while (ctx->in_total < 10) {
|
341
|
+
int read = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
|
342
|
+
if (read == 0) goto error;
|
343
|
+
ctx->in_total += read;
|
344
|
+
}
|
321
345
|
}
|
346
|
+
|
322
347
|
// PRINT_BUFFER("read gzip header", ctx->in, ctx->in_total);
|
323
|
-
if (
|
324
|
-
if (
|
325
|
-
if (
|
326
|
-
flags =
|
348
|
+
if (in_buffer.ptr[0] != GZ_MAGIC1) goto error;
|
349
|
+
if (in_buffer.ptr[1] != GZ_MAGIC2) goto error;
|
350
|
+
if (in_buffer.ptr[2] != GZ_METHOD_DEFLATE) goto error;
|
351
|
+
flags = in_buffer.ptr[3];
|
327
352
|
|
328
|
-
unsigned long mtime = gzfile_get32(
|
353
|
+
unsigned long mtime = gzfile_get32(in_buffer.ptr + 4);
|
329
354
|
header_ctx->mtime = INT2FIX(mtime);
|
330
|
-
|
331
355
|
ctx->in_pos = 10;
|
332
356
|
|
333
357
|
if (flags & GZ_FLAG_ORIG_NAME)
|
@@ -344,6 +368,26 @@ error:
|
|
344
368
|
rb_raise(rb_eRuntimeError, "Invalid gzip header");
|
345
369
|
}
|
346
370
|
|
371
|
+
struct process_z_stream_ctx {
|
372
|
+
z_stream *strm;
|
373
|
+
int flags;
|
374
|
+
zlib_func fun;
|
375
|
+
int ret;
|
376
|
+
};
|
377
|
+
|
378
|
+
void *do_process_z_stream_without_gvl(void *ptr) {
|
379
|
+
struct process_z_stream_ctx *ctx = (struct process_z_stream_ctx *)ptr;
|
380
|
+
|
381
|
+
ctx->ret = (ctx->fun)(ctx->strm, ctx->flags);
|
382
|
+
return NULL;
|
383
|
+
}
|
384
|
+
|
385
|
+
static inline int process_without_gvl(zlib_func fun, z_stream *strm, int flags) {
|
386
|
+
struct process_z_stream_ctx ctx = { strm, flags, fun, 0 };
|
387
|
+
rb_thread_call_without_gvl2(do_process_z_stream_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
|
388
|
+
return ctx.ret;
|
389
|
+
}
|
390
|
+
|
347
391
|
static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, int eof) {
|
348
392
|
int ret;
|
349
393
|
int written;
|
@@ -351,7 +395,7 @@ static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, in
|
|
351
395
|
|
352
396
|
int avail_out_pre = ctx->strm.avail_out = CHUNK - ctx->out_pos;
|
353
397
|
ctx->strm.next_out = ctx->out + ctx->out_pos;
|
354
|
-
ret = fun
|
398
|
+
ret = process_without_gvl(fun, &ctx->strm, eof ? Z_FINISH : Z_NO_FLUSH);
|
355
399
|
assert(ret != Z_STREAM_ERROR);
|
356
400
|
written = avail_out_pre - ctx->strm.avail_out;
|
357
401
|
out_buffer.ptr = ctx->out;
|
@@ -372,12 +416,13 @@ static inline int z_stream_write_out(struct z_stream_ctx *ctx, zlib_func fun, in
|
|
372
416
|
return ctx->strm.avail_out;
|
373
417
|
}
|
374
418
|
|
375
|
-
|
419
|
+
VALUE z_stream_io_loop(struct z_stream_ctx *ctx) {
|
376
420
|
zlib_func fun = (ctx->mode == SM_DEFLATE) ? deflate : inflate;
|
377
421
|
|
378
|
-
if (ctx->in_total > ctx->in_pos) {
|
422
|
+
if ((ctx->src_read_method != RM_STRING) && (ctx->in_total > ctx->in_pos)) {
|
379
423
|
// In bytes already read for parsing gzip header, so we need to process the
|
380
424
|
// rest.
|
425
|
+
|
381
426
|
ctx->strm.next_in = ctx->in + ctx->in_pos;
|
382
427
|
ctx->strm.avail_in = ctx->in_total -= ctx->in_pos;
|
383
428
|
|
@@ -389,14 +434,27 @@ void z_stream_io_loop(struct z_stream_ctx *ctx) {
|
|
389
434
|
}
|
390
435
|
|
391
436
|
while (1) {
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
ctx->
|
437
|
+
int eof;
|
438
|
+
int read_len;
|
439
|
+
if (ctx->src_read_method == RM_STRING) {
|
440
|
+
struct raw_buffer in_buffer = {
|
441
|
+
(unsigned char *)RSTRING_PTR(ctx->src) + ctx->in_pos,
|
442
|
+
RSTRING_LEN(ctx->src) - ctx->in_pos
|
443
|
+
};
|
444
|
+
ctx->strm.next_in = in_buffer.ptr;
|
445
|
+
read_len = ctx->strm.avail_in = in_buffer.len;
|
446
|
+
eof = 1;
|
447
|
+
if (ctx->mode == SM_DEFLATE) ctx->crc32 = crc32(ctx->crc32, in_buffer.ptr, read_len);
|
448
|
+
}
|
449
|
+
else {
|
450
|
+
struct raw_buffer in_buffer = {ctx->in, CHUNK};
|
451
|
+
ctx->strm.next_in = ctx->in;
|
452
|
+
read_len = ctx->strm.avail_in = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
|
453
|
+
if (!read_len) break;
|
454
|
+
eof = read_len < CHUNK;
|
455
|
+
if (ctx->mode == SM_DEFLATE) ctx->crc32 = crc32(ctx->crc32, ctx->in, read_len);
|
456
|
+
}
|
457
|
+
|
400
458
|
ctx->in_total += read_len;
|
401
459
|
|
402
460
|
// PRINT_BUFFER("read stream", ctx->in, read_len);
|
@@ -407,13 +465,15 @@ void z_stream_io_loop(struct z_stream_ctx *ctx) {
|
|
407
465
|
if (z_stream_write_out(ctx, fun, eof)) break;
|
408
466
|
}
|
409
467
|
|
410
|
-
if (eof)
|
468
|
+
if (eof) goto done;
|
411
469
|
}
|
412
470
|
|
413
471
|
//flush
|
414
472
|
ctx->strm.avail_in = 0;
|
415
473
|
ctx->strm.next_in = ctx->in;
|
416
474
|
z_stream_write_out(ctx, fun, 1);
|
475
|
+
done:
|
476
|
+
return Qnil;
|
417
477
|
}
|
418
478
|
|
419
479
|
static inline void setup_ctx(struct z_stream_ctx *ctx, enum stream_mode mode, VALUE src, VALUE dest) {
|
@@ -434,6 +494,17 @@ static inline void setup_ctx(struct z_stream_ctx *ctx, enum stream_mode mode, VA
|
|
434
494
|
ctx->crc32 = 0;
|
435
495
|
}
|
436
496
|
|
497
|
+
static inline VALUE z_stream_cleanup(struct z_stream_ctx *ctx) {
|
498
|
+
if (ctx->mode == SM_DEFLATE)
|
499
|
+
deflateEnd(&ctx->strm);
|
500
|
+
else
|
501
|
+
inflateEnd(&ctx->strm);
|
502
|
+
return Qnil;
|
503
|
+
}
|
504
|
+
|
505
|
+
#define Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx) \
|
506
|
+
rb_ensure(SAFE(z_stream_io_loop), (VALUE)&ctx, SAFE(z_stream_cleanup), (VALUE)&ctx)
|
507
|
+
|
437
508
|
VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
438
509
|
VALUE src;
|
439
510
|
VALUE dest;
|
@@ -450,18 +521,16 @@ VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
|
450
521
|
};
|
451
522
|
|
452
523
|
struct z_stream_ctx ctx;
|
453
|
-
int level = DEFAULT_LEVEL;
|
454
524
|
int ret;
|
455
525
|
|
456
526
|
setup_ctx(&ctx, SM_DEFLATE, src, dest);
|
457
527
|
ctx.f_gzip_footer = 1; // write gzip footer
|
458
|
-
ctx.out_pos = gzip_prepare_header(&header_ctx, ctx.out, sizeof(ctx.out));
|
528
|
+
ctx.out_total = ctx.out_pos = gzip_prepare_header(&header_ctx, ctx.out, sizeof(ctx.out));
|
459
529
|
|
460
|
-
ret = deflateInit2(&ctx.strm,
|
461
|
-
if (ret != Z_OK)
|
462
|
-
|
463
|
-
|
464
|
-
|
530
|
+
ret = deflateInit2(&ctx.strm, DEFAULT_LEVEL, Z_DEFLATED, -MAX_WBITS, DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
531
|
+
if (ret != Z_OK)
|
532
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
533
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
465
534
|
return INT2FIX(ctx.out_total);
|
466
535
|
}
|
467
536
|
|
@@ -482,21 +551,25 @@ VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
|
|
482
551
|
setup_ctx(&ctx, SM_INFLATE, src, dest);
|
483
552
|
gzip_read_header(&ctx, &header_ctx);
|
484
553
|
|
554
|
+
ret = inflateInit2(&ctx.strm, -MAX_WBITS);
|
555
|
+
if (ret != Z_OK)
|
556
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
557
|
+
|
558
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
559
|
+
|
560
|
+
// gzip_read_footer(&ctx, &footer_ctx);
|
561
|
+
// TODO: verify crc32
|
562
|
+
// TODO: verify total length
|
563
|
+
|
485
564
|
if (info != Qnil) {
|
486
565
|
rb_hash_aset(info, SYM_mtime, FIX2TIME(header_ctx.mtime));
|
487
566
|
rb_hash_aset(info, SYM_orig_name, header_ctx.orig_name);
|
488
567
|
rb_hash_aset(info, SYM_comment, header_ctx.comment);
|
489
568
|
}
|
569
|
+
RB_GC_GUARD(header_ctx.orig_name);
|
570
|
+
RB_GC_GUARD(header_ctx.comment);
|
490
571
|
|
491
|
-
|
492
|
-
if (ret != Z_OK) return INT2FIX(ret);
|
493
|
-
z_stream_io_loop(&ctx);
|
494
|
-
inflateEnd(&ctx.strm);
|
495
|
-
|
496
|
-
// gzip_read_footer(&ctx, &footer_ctx);
|
497
|
-
// TODO: verify crc32
|
498
|
-
// TODO: verify total length
|
499
|
-
return self;
|
572
|
+
return INT2FIX(ctx.out_total);
|
500
573
|
}
|
501
574
|
|
502
575
|
VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
@@ -506,9 +579,10 @@ VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
|
506
579
|
|
507
580
|
setup_ctx(&ctx, SM_DEFLATE, src, dest);
|
508
581
|
ret = deflateInit(&ctx.strm, level);
|
509
|
-
if (ret != Z_OK)
|
510
|
-
|
511
|
-
|
582
|
+
if (ret != Z_OK)
|
583
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
584
|
+
|
585
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
512
586
|
|
513
587
|
return INT2FIX(ctx.out_total);
|
514
588
|
}
|
@@ -519,9 +593,10 @@ VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
|
|
519
593
|
|
520
594
|
setup_ctx(&ctx, SM_INFLATE, src, dest);
|
521
595
|
ret = inflateInit(&ctx.strm);
|
522
|
-
if (ret != Z_OK)
|
523
|
-
|
524
|
-
|
596
|
+
if (ret != Z_OK)
|
597
|
+
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
598
|
+
|
599
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
525
600
|
|
526
601
|
return INT2FIX(ctx.out_total);
|
527
602
|
}
|
@@ -538,16 +613,16 @@ VALUE IO_http1_splice_chunked(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
|
|
538
613
|
if (!len) break;
|
539
614
|
|
540
615
|
// write chunk header
|
541
|
-
buffer.len += sprintf(buffer.ptr + buffer.len, "%x\r\n", len);
|
616
|
+
buffer.len += sprintf((char *)buffer.ptr + buffer.len, "%x\r\n", len);
|
542
617
|
write_from_raw_buffer(backend, dest, method, &buffer);
|
543
618
|
buffer.len = 0;
|
544
619
|
while (len) {
|
545
620
|
int spliced = FIX2INT(Backend_splice(backend, pipe, dest, INT2FIX(len)));
|
546
621
|
len -= spliced;
|
547
622
|
}
|
548
|
-
buffer.len += sprintf(buffer.ptr + buffer.len, "\r\n");
|
623
|
+
buffer.len += sprintf((char *)buffer.ptr + buffer.len, "\r\n");
|
549
624
|
}
|
550
|
-
buffer.len += sprintf(buffer.ptr + buffer.len, "0\r\n\r\n");
|
625
|
+
buffer.len += sprintf((char *)buffer.ptr + buffer.len, "0\r\n\r\n");
|
551
626
|
write_from_raw_buffer(backend, dest, method, &buffer);
|
552
627
|
|
553
628
|
Pipe_close(pipe);
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -94,6 +94,12 @@ VALUE Polyphony_backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE c
|
|
94
94
|
return Backend_splice_to_eof(BACKEND(), src, dest, chunksize);
|
95
95
|
}
|
96
96
|
|
97
|
+
#ifdef POLYPHONY_BACKEND_LIBURING
|
98
|
+
VALUE Polyphony_backend_double_splice_to_eof(VALUE self, VALUE src, VALUE dest) {
|
99
|
+
return Backend_double_splice_to_eof(BACKEND(), src, dest);
|
100
|
+
}
|
101
|
+
#endif
|
102
|
+
|
97
103
|
#ifdef POLYPHONY_LINUX
|
98
104
|
VALUE Polyphony_backend_tee(VALUE self, VALUE src, VALUE dest, VALUE chunksize) {
|
99
105
|
return Backend_tee(BACKEND(), src, dest, chunksize);
|
@@ -126,7 +132,7 @@ VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
|
|
126
132
|
|
127
133
|
VALUE Polyphony_with_raw_buffer(VALUE self, VALUE size) {
|
128
134
|
struct raw_buffer buffer;
|
129
|
-
buffer.len =
|
135
|
+
buffer.len = FIX2INT(size);
|
130
136
|
buffer.ptr = malloc(buffer.len);
|
131
137
|
if (!buffer.ptr)
|
132
138
|
rb_raise(rb_eRuntimeError, "Failed to allocate buffer");
|
@@ -145,7 +151,7 @@ VALUE Polyphony_raw_buffer_get(int argc, VALUE *argv, VALUE self) {
|
|
145
151
|
int length = (len == Qnil) ? buffer->len : FIX2INT(len);
|
146
152
|
|
147
153
|
if (length > buffer->len) length = buffer->len;
|
148
|
-
return rb_utf8_str_new(buffer->ptr, length);
|
154
|
+
return rb_utf8_str_new((char *)buffer->ptr, length);
|
149
155
|
}
|
150
156
|
|
151
157
|
VALUE Polyphony_raw_buffer_set(VALUE self, VALUE buf, VALUE str) {
|
@@ -164,12 +170,6 @@ VALUE Polyphony_raw_buffer_size(VALUE self, VALUE buf) {
|
|
164
170
|
return INT2FIX(buffer->len);
|
165
171
|
}
|
166
172
|
|
167
|
-
VALUE Polyphony_backend_test(VALUE self, VALUE io, VALUE str) {
|
168
|
-
struct raw_buffer buffer = { RSTRING_PTR(str), RSTRING_LEN(str) };
|
169
|
-
VALUE args[2] = { io, PTR2FIX(&buffer) };
|
170
|
-
return Polyphony_backend_write(2, args, self);
|
171
|
-
}
|
172
|
-
|
173
173
|
// VALUE Polyphony_backend_close(VALUE self, VALUE io) {
|
174
174
|
// return Backend_close(BACKEND(), io);
|
175
175
|
// }
|
@@ -193,6 +193,10 @@ void Init_Polyphony() {
|
|
193
193
|
rb_define_singleton_method(mPolyphony, "backend_splice", Polyphony_backend_splice, 3);
|
194
194
|
rb_define_singleton_method(mPolyphony, "backend_splice_to_eof", Polyphony_backend_splice_to_eof, 3);
|
195
195
|
|
196
|
+
#ifdef POLYPHONY_BACKEND_LIBURING
|
197
|
+
rb_define_singleton_method(mPolyphony, "backend_double_splice_to_eof", Polyphony_backend_double_splice_to_eof, 2);
|
198
|
+
#endif
|
199
|
+
|
196
200
|
#ifdef POLYPHONY_LINUX
|
197
201
|
rb_define_singleton_method(mPolyphony, "backend_tee", Polyphony_backend_tee, 3);
|
198
202
|
#endif
|
@@ -210,7 +214,6 @@ void Init_Polyphony() {
|
|
210
214
|
rb_define_singleton_method(mPolyphony, "__raw_buffer_get__", Polyphony_raw_buffer_get, -1);
|
211
215
|
rb_define_singleton_method(mPolyphony, "__raw_buffer_set__", Polyphony_raw_buffer_set, 2);
|
212
216
|
rb_define_singleton_method(mPolyphony, "__raw_buffer_size__", Polyphony_raw_buffer_size, 1);
|
213
|
-
rb_define_singleton_method(mPolyphony, "backend_test", Polyphony_backend_test, 2);
|
214
217
|
|
215
218
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
216
219
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|