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.
@@ -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 = NUM2INT(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 = NUM2INT(maxlen);
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 INT2NUM(buffer.len);
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 INT2NUM(total_written);
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 = NUM2INT(flags);
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 INT2NUM(buffer.len);
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, NUM2INT(maxlen), 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 INT2NUM(len);
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, NUM2INT(maxlen), 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 INT2NUM(total);
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, NUM2INT(maxlen), 0);
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 INT2NUM(len);
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 = NUM2INT(maxlen);
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 INT2NUM(total);
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 = NUM2INT(maxlen);
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 INT2NUM(total);
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 = NUM2INT(pid);
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, INT2NUM(ret), INT2NUM(WEXITSTATUS(status)));
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, INT2NUM(w->rpid), INT2NUM(exit_status));
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, NUM2INT(pid), 0);
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 = NUM2INT(chunk_size);
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 = INT2NUM(chunk_len);
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 INT2NUM(total);
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]);
@@ -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
- have_func('rb_fiber_transfer', 'ruby.h')
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
- int null_pos;
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 = { ctx->in, CHUNK };
329
+ struct raw_buffer in_buffer;
315
330
  int flags;
316
331
 
317
- while (ctx->in_total < 10) {
318
- int read = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
319
- if (read == 0) goto error;
320
- ctx->in_total += read;
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 (ctx->in[0] != GZ_MAGIC1) goto error;
324
- if (ctx->in[1] != GZ_MAGIC2) goto error;
325
- if (ctx->in[2] != GZ_METHOD_DEFLATE) goto error;
326
- flags = ctx->in[3];
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(ctx->in + 4);
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(&ctx->strm, eof ? Z_FINISH : Z_NO_FLUSH);
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
- void z_stream_io_loop(struct z_stream_ctx *ctx) {
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
- struct raw_buffer in_buffer = {ctx->in, CHUNK};
393
- ctx->strm.next_in = ctx->in;
394
- int read_len = ctx->strm.avail_in = read_to_raw_buffer(ctx->backend, ctx->src, ctx->src_read_method, &in_buffer);
395
- if (!read_len) break;
396
- int eof = read_len < CHUNK;
397
-
398
- if (ctx->mode == SM_DEFLATE)
399
- ctx->crc32 = crc32(ctx->crc32, ctx->in, read_len);
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) return;
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, level, Z_DEFLATED, -MAX_WBITS, DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
461
- if (ret != Z_OK) return INT2FIX(ret);
462
- z_stream_io_loop(&ctx);
463
- deflateEnd(&ctx.strm);
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
- ret = inflateInit2(&ctx.strm, -MAX_WBITS);
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) return INT2FIX(ret);
510
- z_stream_io_loop(&ctx);
511
- deflateEnd(&ctx.strm);
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) return INT2FIX(ret);
523
- z_stream_io_loop(&ctx);
524
- inflateEnd(&ctx.strm);
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);
@@ -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 = NUM2INT(size);
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);