polyphony 0.53.0 → 0.53.1

Sign up to get free protection for your applications and to get access to all the features.
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