polyphony 0.53.0 → 0.53.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0682736e3fdca0ada986f4210f1bb25d682c75a7b9d297451c186b90c8025e13'
4
- data.tar.gz: 5ff46620651c056983a6f73c879ca1c49acea22c0c7abcefb1a119cbe248cb77
3
+ metadata.gz: b769b5e71cbfa8679a639d369817abd8e5870efec8ea21feb60bb1e46ee7ca29
4
+ data.tar.gz: 0b2ded84eb0e120d20dd17c9973e2cab784cdf61c20bd20fcb6a13c2b6e9f58a
5
5
  SHA512:
6
- metadata.gz: cfbb8141b21cc9e56cdcd9a34fd55cd3b48573dcc3011f127ece5049b13ca2c7fa8a17c8525ba5996ab97afcbfc8e46064a3d68c79d71d44d40c274ff9051d2d
7
- data.tar.gz: f31d711c88fe354b8ffd63e37f30887b1bfb5c3709d3760412ee4ec4ea06d14c0a17e668ddd750958295dc12307b96cf64874b1be4ed46b8564d04236114ee67
6
+ metadata.gz: e6d3a3d2c130c31483ead4d8f13cc90a87149ac6c461871a43144111cdc37e6e2544c130dc447af26e39e9519b48e3abe1a10197dd4512a7292968e4939e676b
7
+ data.tar.gz: dc1b53918032fc74578ca528abb5a96e423ea8e7a070047f7936720cb6553d9f247cbb625e9d82c7b9b58795a4a3a74aae566231a7a4bb8443f5352c00d10b2a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.53.1
2
+
3
+ - Remove `splice` methods on libev backend on non-Linux OS (#43)
4
+
1
5
  ## 0.53.0
2
6
 
3
7
  - Implement `Backend#splice`, `Backend#splice_to_eof`, along with `IO#splice`, `IO#splice_to_eof`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.53.0)
4
+ polyphony (0.53.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/TODO.md CHANGED
@@ -35,8 +35,8 @@
35
35
 
36
36
  ```ruby
37
37
  Thread.current.backend.submit(
38
- [sock, :<<, chunk_header(len)],
39
- [sock, :splice, file, len]
38
+ [:send, sock, chunk_header(len)],
39
+ [:splice, file, sock, len]
40
40
  )
41
41
  ```
42
42
 
@@ -51,8 +51,8 @@
51
51
  break if len == 0
52
52
 
53
53
  backend.submit(
54
- [sock, :<<, chunk_header(len)],
55
- [sock, :splice, file, len]
54
+ [:write, sock, chunk_header(len)],
55
+ [:splice, i, sock, len]
56
56
  )
57
57
  end
58
58
  end
@@ -150,7 +150,7 @@ static inline bool cq_ring_needs_flush(struct io_uring *ring) {
150
150
  return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
151
151
  }
152
152
 
153
- void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
153
+ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
154
154
  op_context_t *ctx = io_uring_cqe_get_data(cqe);
155
155
  if (!ctx) return;
156
156
 
@@ -169,7 +169,7 @@ void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *bac
169
169
  }
170
170
 
171
171
  // adapted from io_uring_peek_batch_cqe in queue.c
172
- // this peeks at cqes and for each one
172
+ // this peeks at cqes and handles each available cqe
173
173
  void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
174
174
  struct io_uring *ring = &backend->ring;
175
175
  bool overflow_checked = false;
@@ -315,8 +315,8 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
315
315
  Backend_t *backend;
316
316
  rb_io_t *fptr;
317
317
  long dynamic_len = length == Qnil;
318
- long len = dynamic_len ? 4096 : NUM2INT(length);
319
- int shrinkable = io_setstrbuf(&str, len);
318
+ long buffer_size = dynamic_len ? 4096 : NUM2INT(length);
319
+ int shrinkable = io_setstrbuf(&str, buffer_size);
320
320
  char *buf = RSTRING_PTR(str);
321
321
  long total = 0;
322
322
  int read_to_eof = RTEST(to_eof);
@@ -334,7 +334,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
334
334
  VALUE resume_value = Qnil;
335
335
  op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_READ);
336
336
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
337
- io_uring_prep_read(sqe, fptr->fd, buf, len - total, -1);
337
+ io_uring_prep_read(sqe, fptr->fd, buf, buffer_size - total, -1);
338
338
 
339
339
  int result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
340
340
  OP_CONTEXT_RELEASE(&backend->store, ctx);
@@ -350,14 +350,15 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
350
350
  total += result;
351
351
  if (!read_to_eof) break;
352
352
 
353
- if (total == len) {
353
+ if (total == buffer_size) {
354
354
  if (!dynamic_len) break;
355
355
 
356
+ // resize buffer
356
357
  rb_str_resize(str, total);
357
- rb_str_modify_expand(str, len);
358
+ rb_str_modify_expand(str, buffer_size);
358
359
  buf = RSTRING_PTR(str) + total;
359
360
  shrinkable = 0;
360
- len += len;
361
+ buffer_size += buffer_size;
361
362
  }
362
363
  else buf += result;
363
364
  }
@@ -857,8 +858,8 @@ VALUE io_uring_backend_splice(Backend_t *backend, VALUE src, VALUE dest, VALUE m
857
858
  if (result < 0)
858
859
  rb_syserr_fail(-result, strerror(-result));
859
860
 
860
- if (result == 0 || !loop) return INT2NUM(total);
861
861
  total += result;
862
+ if (result == 0 || !loop) return INT2NUM(total);
862
863
  }
863
864
 
864
865
  RB_GC_GUARD(resume_value);
@@ -58,6 +58,9 @@ thread.
58
58
  #include "ruby/io.h"
59
59
 
60
60
  VALUE SYM_libev;
61
+ VALUE SYM_send;
62
+ VALUE SYM_splice;
63
+ VALUE SYM_write;
61
64
 
62
65
  ID ID_ivar_is_nonblocking;
63
66
 
@@ -773,6 +776,7 @@ error:
773
776
  return RAISE_EXCEPTION(switchpoint_result);
774
777
  }
775
778
 
779
+ #ifndef POLYPHONY_LINUX
776
780
  VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
777
781
  Backend_t *backend;
778
782
  struct libev_io watcher;
@@ -782,10 +786,6 @@ VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
782
786
  rb_io_t *dest_fptr;
783
787
  int len;
784
788
 
785
- #ifndef POLYPHONY_LINUX
786
- rb_raise(rb_eRuntimeError, "splice not supported");
787
- #endif
788
-
789
789
  GetBackend(self, backend);
790
790
 
791
791
  underlying_io = rb_ivar_get(src, ID_ivar_io);
@@ -840,10 +840,6 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
840
840
  int len;
841
841
  int total = 0;
842
842
 
843
- #ifndef POLYPHONY_LINUX
844
- rb_raise(rb_eRuntimeError, "splice not supported");
845
- #endif
846
-
847
843
  GetBackend(self, backend);
848
844
 
849
845
  underlying_io = rb_ivar_get(src, ID_ivar_io);
@@ -890,6 +886,7 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
890
886
  error:
891
887
  return RAISE_EXCEPTION(switchpoint_result);
892
888
  }
889
+ #endif
893
890
 
894
891
  VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
895
892
  Backend_t *backend;
@@ -1103,6 +1100,31 @@ VALUE Backend_kind(VALUE self) {
1103
1100
  return SYM_libev;
1104
1101
  }
1105
1102
 
1103
+ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1104
+ VALUE result = Qnil;
1105
+ if (argc == 0) return result;
1106
+
1107
+ for (int i = 0; i < argc; i++) {
1108
+ VALUE op = argv[i];
1109
+ VALUE op_type = RARRAY_AREF(op, 0);
1110
+ VALUE op_len = RARRAY_LEN(op);
1111
+
1112
+ if (op_type == SYM_write && op_len == 3)
1113
+ result = Backend_write(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2));
1114
+ else if (op_type == SYM_send && op_len == 4)
1115
+ result = Backend_send(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
1116
+ #ifndef POLYPHONY_LINUX
1117
+ else if (op_type == SYM_splice && op_len == 4)
1118
+ result = Backend_splice(self, RARRAY_AREF(op, 1), RARRAY_AREF(op, 2), RARRAY_AREF(op, 3));
1119
+ #endif
1120
+ else
1121
+ rb_raise(rb_eRuntimeError, "Invalid op specified or bad op arity");
1122
+ }
1123
+
1124
+ RB_GC_GUARD(result);
1125
+ return result;
1126
+ }
1127
+
1106
1128
  void Init_Backend() {
1107
1129
  ev_set_allocator(xrealloc);
1108
1130
 
@@ -1116,6 +1138,7 @@ void Init_Backend() {
1116
1138
  rb_define_method(cBackend, "poll", Backend_poll, 3);
1117
1139
  rb_define_method(cBackend, "break", Backend_wakeup, 0);
1118
1140
  rb_define_method(cBackend, "kind", Backend_kind, 0);
1141
+ rb_define_method(cBackend, "chain", Backend_chain, -1);
1119
1142
 
1120
1143
  rb_define_method(cBackend, "accept", Backend_accept, 2);
1121
1144
  rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
@@ -1129,6 +1152,12 @@ void Init_Backend() {
1129
1152
  rb_define_method(cBackend, "send", Backend_send, 3);
1130
1153
  rb_define_method(cBackend, "sendv", Backend_sendv, 3);
1131
1154
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
1155
+
1156
+ #ifndef POLYPHONY_LINUX
1157
+ rb_define_method(cBackend, "splice", Backend_splice, 3);
1158
+ rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
1159
+ #endif
1160
+
1132
1161
  rb_define_method(cBackend, "timeout", Backend_timeout, -1);
1133
1162
  rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
1134
1163
  rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
@@ -1138,6 +1167,10 @@ void Init_Backend() {
1138
1167
 
1139
1168
  ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
1140
1169
  SYM_libev = ID2SYM(rb_intern("libev"));
1170
+
1171
+ SYM_send = ID2SYM(rb_intern("send"));
1172
+ SYM_splice = ID2SYM(rb_intern("splice"));
1173
+ SYM_write = ID2SYM(rb_intern("write"));
1141
1174
  }
1142
1175
 
1143
1176
  #endif // POLYPHONY_BACKEND_LIBEV
@@ -21,7 +21,7 @@ static VALUE SYM_scheduled_fibers;
21
21
  static VALUE SYM_pending_watchers;
22
22
 
23
23
  static VALUE Thread_fiber_scheduling_stats(VALUE self) {
24
- VALUE backend = rb_ivar_get(self,ID_ivar_backend);
24
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
25
25
  VALUE stats = rb_hash_new();
26
26
  VALUE runqueue = rb_ivar_get(self, ID_ivar_runqueue);
27
27
  long pending_count;
@@ -53,7 +53,7 @@ void schedule_fiber(VALUE self, VALUE fiber, VALUE value, int prioritize) {
53
53
  // event selector. Otherwise it's gonna be stuck waiting for an event to
54
54
  // happen, not knowing that it there's already a fiber ready to run in its
55
55
  // run queue.
56
- VALUE backend = rb_ivar_get(self,ID_ivar_backend);
56
+ VALUE backend = rb_ivar_get(self, ID_ivar_backend);
57
57
  Backend_wakeup(backend);
58
58
  }
59
59
  }
@@ -138,6 +138,10 @@ VALUE Thread_debug(VALUE self) {
138
138
  return self;
139
139
  }
140
140
 
141
+ VALUE Thread_class_backend(VALUE _self) {
142
+ return rb_ivar_get(rb_thread_current(), ID_ivar_backend);
143
+ }
144
+
141
145
  void Init_Thread() {
142
146
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
143
147
  rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
@@ -150,6 +154,8 @@ void Init_Thread() {
150
154
  rb_define_method(rb_cThread, "fiber_scheduling_index", Thread_fiber_scheduling_index, 1);
151
155
  rb_define_method(rb_cThread, "fiber_unschedule", Thread_fiber_unschedule, 1);
152
156
 
157
+ rb_define_singleton_method(rb_cThread, "backend", Thread_class_backend, 0);
158
+
153
159
  rb_define_method(rb_cThread, "debug!", Thread_debug, 0);
154
160
 
155
161
  ID_deactivate_all_watchers_post_fork = rb_intern("deactivate_all_watchers_post_fork");
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.53.0'
4
+ VERSION = '0.53.1'
5
5
  end
data/test/test_backend.rb CHANGED
@@ -241,9 +241,10 @@ class BackendTest < MiniTest::Test
241
241
  def test_splice
242
242
  i1, o1 = IO.pipe
243
243
  i2, o2 = IO.pipe
244
+ len = nil
244
245
 
245
246
  spin {
246
- o2.splice(i1, 1000)
247
+ len = o2.splice(i1, 1000)
247
248
  o2.close
248
249
  }
249
250
 
@@ -251,14 +252,16 @@ class BackendTest < MiniTest::Test
251
252
  result = i2.read
252
253
 
253
254
  assert_equal 'foobar', result
255
+ assert_equal 6, len
254
256
  end
255
257
 
256
258
  def test_splice_to_eof
257
259
  i1, o1 = IO.pipe
258
260
  i2, o2 = IO.pipe
261
+ len = nil
259
262
 
260
263
  f = spin {
261
- o2.splice_to_eof(i1, 1000)
264
+ len = o2.splice_to_eof(i1, 1000)
262
265
  o2.close
263
266
  }
264
267
 
@@ -269,8 +272,88 @@ class BackendTest < MiniTest::Test
269
272
  o1.write('bar')
270
273
  result = i2.readpartial(1000)
271
274
  assert_equal 'bar', result
272
- ensure
273
- f.interrupt
275
+ o1.close
274
276
  f.await
277
+ assert_equal 6, len
278
+ ensure
279
+ if f.alive?
280
+ f.interrupt
281
+ f.await
282
+ end
283
+ end
284
+ end
285
+
286
+ class BackendChainTest < MiniTest::Test
287
+ def setup
288
+ super
289
+ @prev_backend = Thread.current.backend
290
+ @backend = Polyphony::Backend.new
291
+ Thread.current.backend = @backend
292
+ end
293
+
294
+ def teardown
295
+ @backend.finalize
296
+ Thread.current.backend = @prev_backend
297
+ end
298
+
299
+ def test_simple_write_chain
300
+ i, o = IO.pipe
301
+
302
+ result = Thread.backend.chain(
303
+ [:write, o, 'hello'],
304
+ [:write, o, ' world']
305
+ )
306
+
307
+ assert_equal 6, result
308
+ o.close
309
+ assert_equal 'hello world', i.read
310
+ end
311
+
312
+ def chunk_header(len)
313
+ "Content-Length: #{len}\r\n\r\n"
314
+ end
315
+
316
+ def serve_io(from, to)
317
+ i, o = IO.pipe
318
+ backend = Thread.current.backend
319
+ while true
320
+ len = o.splice(from, 8192)
321
+ break if len == 0
322
+
323
+ backend.chain(
324
+ [:write, to, chunk_header(len)],
325
+ [:splice, i, to, len]
326
+ )
327
+ end
328
+ to.close
329
+ end
330
+
331
+ def test_chain_with_splice
332
+ from_r, from_w = IO.pipe
333
+ to_r, to_w = IO.pipe
334
+
335
+ result = nil
336
+ f = spin { serve_io(from_r, to_w) }
337
+
338
+ from_w << 'Hello world!'
339
+ from_w.close
340
+
341
+ assert_equal "Content-Length: 12\r\n\r\nHello world!", to_r.read
342
+ end
343
+
344
+ def test_invalid_op
345
+ i, o = IO.pipe
346
+
347
+ assert_raises(RuntimeError) {
348
+ Thread.backend.chain(
349
+ [:read, o]
350
+ )
351
+ }
352
+
353
+ assert_raises(TypeError) {
354
+ Thread.backend.chain(
355
+ [:write, o]
356
+ )
357
+ }
275
358
  end
276
359
  end
data/test/test_thread.rb CHANGED
@@ -124,6 +124,10 @@ class ThreadTest < MiniTest::Test
124
124
  t&.join
125
125
  end
126
126
 
127
+ def test_backend_class_method
128
+ assert_equal Thread.current.backend, Thread.backend
129
+ end
130
+
127
131
  def test_that_suspend_returns_immediately_if_no_watchers
128
132
  records = []
129
133
  t = Polyphony::Trace.new(:fiber_all) do |r|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.53.0
4
+ version: 0.53.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-23 00:00:00.000000000 Z
11
+ date: 2021-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler