polyphony 0.83 → 0.84

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: a1e0c71b9d91e674e4ce004da08cdf6535f56e48b063b63538685eb781654df6
4
- data.tar.gz: 58bf12edd0751ecc552ee01b6eb7042585061f7800f0dfa6fdc0990b87349982
3
+ metadata.gz: ce9742f5b50581c5569df4ad3e2232c7c32392a92e7ab23960373c8a4e3b0de4
4
+ data.tar.gz: a695f3191cc7cefb7d720565c3564b24784beb836528342e8d4fd9e8d0231dda
5
5
  SHA512:
6
- metadata.gz: c35e1c2756556db5bf11012b95c7e729d7ad43f52802c61fa5467d44a6460a2f30f840bc945347e83ed24d35e559b0ca4ac9d5657c9d0c805ffb44774765f867
7
- data.tar.gz: 37c34a7c2cc0b3443c0f33908f40156c223eae233ca08f564a606a7bec5c8c68189b973e6fa40fd1534bb3c9f2f3985b52fcdd33c7ea9069ba21e32e7ebc1760
6
+ metadata.gz: 041cb949e600ef328ed6d1c92badcaa9ef502e4776043d6a7786a811d5935de450f933b8eff4dd6100db6e55ff19878186bd9ef6bb840ac1cdcdb8c53341f51c
7
+ data.tar.gz: fc0542606c3ee5ab044cc5e8175a60fb3fa6a8466422643ff1446fb0271a6db09236b5c0dbc7a632fa47853ae0ac3a2007fa4644a85283b4225f453f6155dbce
data/.gitmodules CHANGED
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/liburing"]
2
+ path = vendor/liburing
3
+ url = https://github.com/axboe/liburing
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.84 2022-03-11
2
+
3
+ - Implement `IO.tee` (#82)
4
+ - Implement `IO#tee_from` (#81)
5
+ - Bundle liburing as git submodule
6
+
1
7
  ## 0.83 2022-03-10
2
8
 
3
9
  - Implement `Polyphony::Pipe` class, `Polyphony.pipe` method (#83)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.83)
4
+ polyphony (0.84)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/Rakefile CHANGED
@@ -24,3 +24,17 @@ task :docs do
24
24
  end
25
25
 
26
26
  CLEAN.include "**/*.o", "**/*.so", "**/*.so.*", "**/*.a", "**/*.bundle", "**/*.jar", "pkg", "tmp"
27
+
28
+ task :release do
29
+ require_relative './lib/polyphony/version'
30
+ version = Polyphony::VERSION
31
+
32
+ puts 'Building polyphony...'
33
+ `gem build polyphony.gemspec`
34
+
35
+ puts "Pushing polyphony #{version}..."
36
+ `gem push extralite-#{version}.gem`
37
+
38
+ puts "Cleaning up..."
39
+ `rm *.gem`
40
+ end
@@ -14,7 +14,7 @@
14
14
  #include <errno.h>
15
15
 
16
16
  #include "polyphony.h"
17
- #include "../liburing/liburing.h"
17
+ #include "liburing.h"
18
18
  #include "backend_io_uring_context.h"
19
19
  #include "ruby/thread.h"
20
20
  #include "ruby/io.h"
@@ -304,7 +304,7 @@ int io_uring_backend_defer_submit_and_await(
304
304
  // op was not completed (an exception was raised), so we need to cancel it
305
305
  ctx->result = -ECANCELED;
306
306
  sqe = io_uring_get_sqe(&backend->ring);
307
- io_uring_prep_cancel(sqe, ctx, 0);
307
+ io_uring_prep_cancel(sqe, (__u64)ctx, 0);
308
308
  backend->pending_sqes = 0;
309
309
  io_uring_submit(&backend->ring);
310
310
  }
@@ -971,6 +971,41 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize)
971
971
  return io_uring_backend_splice(backend, src, dest, chunksize, 1);
972
972
  }
973
973
 
974
+ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
975
+ Backend_t *backend;
976
+ GetBackend(self, backend);
977
+
978
+ int src_fd;
979
+ int dest_fd;
980
+ rb_io_t *src_fptr;
981
+ rb_io_t *dest_fptr;
982
+ VALUE resume_value = Qnil;
983
+
984
+ src_fd = fd_from_io(src, &src_fptr, 0, 0);
985
+ dest_fd = fd_from_io(dest, &dest_fptr, 1, 0);
986
+
987
+ while (1) {
988
+ op_context_t *ctx = context_store_acquire(&backend->store, OP_SPLICE);
989
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
990
+ int result;
991
+ int completed;
992
+
993
+ io_uring_prep_tee(sqe, src_fd, dest_fd, NUM2INT(maxlen), 0);
994
+
995
+ result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
996
+ completed = context_store_release(&backend->store, ctx);
997
+ RAISE_IF_EXCEPTION(resume_value);
998
+ if (!completed) return resume_value;
999
+
1000
+ if (result < 0)
1001
+ rb_syserr_fail(-result, strerror(-result));
1002
+
1003
+ return INT2NUM(result);
1004
+ }
1005
+
1006
+ RB_GC_GUARD(resume_value);
1007
+ }
1008
+
974
1009
  VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
975
1010
  Backend_t *backend;
976
1011
  int fd;
@@ -1125,7 +1160,7 @@ VALUE Backend_timeout_ensure(VALUE arg) {
1125
1160
  timeout_ctx->ctx->result = -ECANCELED;
1126
1161
  // op was not completed, so we need to cancel it
1127
1162
  sqe = io_uring_get_sqe(&timeout_ctx->backend->ring);
1128
- io_uring_prep_cancel(sqe, timeout_ctx->ctx, 0);
1163
+ io_uring_prep_cancel(sqe, (__u64)timeout_ctx->ctx, 0);
1129
1164
  timeout_ctx->backend->pending_sqes = 0;
1130
1165
  io_uring_submit(&timeout_ctx->backend->ring);
1131
1166
  }
@@ -1318,7 +1353,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1318
1353
  ctx->ref_count = sqe_count;
1319
1354
  ctx->result = -ECANCELED;
1320
1355
  sqe = io_uring_get_sqe(&backend->ring);
1321
- io_uring_prep_cancel(sqe, ctx, 0);
1356
+ io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1322
1357
  backend->pending_sqes = 0;
1323
1358
  io_uring_submit(&backend->ring);
1324
1359
  }
@@ -1349,7 +1384,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
1349
1384
  // op was not completed (an exception was raised), so we need to cancel it
1350
1385
  ctx->result = -ECANCELED;
1351
1386
  sqe = io_uring_get_sqe(&backend->ring);
1352
- io_uring_prep_cancel(sqe, ctx, 0);
1387
+ io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1353
1388
  backend->pending_sqes = 0;
1354
1389
  io_uring_submit(&backend->ring);
1355
1390
  RAISE_IF_EXCEPTION(resume_value);
@@ -1416,7 +1451,7 @@ static inline void splice_chunks_cancel(Backend_t *backend, op_context_t *ctx) {
1416
1451
 
1417
1452
  ctx->result = -ECANCELED;
1418
1453
  sqe = io_uring_get_sqe(&backend->ring);
1419
- io_uring_prep_cancel(sqe, ctx, 0);
1454
+ io_uring_prep_cancel(sqe, (__u64)ctx, 0);
1420
1455
  backend->pending_sqes = 0;
1421
1456
  io_uring_submit(&backend->ring);
1422
1457
  }
@@ -1619,6 +1654,7 @@ void Init_Backend() {
1619
1654
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
1620
1655
  rb_define_method(cBackend, "splice", Backend_splice, 3);
1621
1656
  rb_define_method(cBackend, "splice_to_eof", Backend_splice_to_eof, 3);
1657
+ rb_define_method(cBackend, "tee", Backend_tee, 3);
1622
1658
  rb_define_method(cBackend, "timeout", Backend_timeout, -1);
1623
1659
  rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
1624
1660
  rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
@@ -940,7 +940,52 @@ VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
940
940
  error:
941
941
  return RAISE_EXCEPTION(switchpoint_result);
942
942
  }
943
+
944
+ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
945
+ Backend_t *backend;
946
+ struct libev_rw_io watcher;
947
+ VALUE switchpoint_result = Qnil;
948
+ int src_fd;
949
+ int dest_fd;
950
+ rb_io_t *src_fptr;
951
+ rb_io_t *dest_fptr;
952
+ int len;
953
+
954
+ GetBackend(self, backend);
955
+ src_fd = fd_from_io(src, &src_fptr, 0, 0);
956
+ dest_fd = fd_from_io(dest, &dest_fptr, 1, 0);
957
+ watcher.ctx.fiber = Qnil;
958
+
959
+ while (1) {
960
+ backend->base.op_count++;
961
+ len = tee(src_fd, dest_fd, NUM2INT(maxlen), 0);
962
+ if (len < 0) {
963
+ int e = errno;
964
+ if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
965
+
966
+ switchpoint_result = libev_wait_rw_fd_with_watcher(backend, src_fd, dest_fd, &watcher);
967
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
968
+ }
969
+ else {
970
+ break;
971
+ }
972
+ }
973
+
974
+ if (watcher.ctx.fiber == Qnil) {
975
+ switchpoint_result = backend_snooze(&backend->base);
976
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
977
+ }
978
+
979
+ RB_GC_GUARD(watcher.ctx.fiber);
980
+ RB_GC_GUARD(switchpoint_result);
981
+
982
+ return INT2NUM(len);
983
+ error:
984
+ return RAISE_EXCEPTION(switchpoint_result);
985
+ }
986
+
943
987
  #else
988
+
944
989
  VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
945
990
  Backend_t *backend;
946
991
  struct libev_io watcher;
@@ -28,6 +28,22 @@ puts "Building Polyphony... (#{config.inspect})"
28
28
 
29
29
  require_relative 'zlib_conf'
30
30
 
31
+ if config[:io_uring]
32
+ liburing_path = File.expand_path('../../vendor/liburing', __dir__)
33
+ FileUtils.cd liburing_path do
34
+ system('./configure', exception: true)
35
+ FileUtils.cd File.join(liburing_path, 'src') do
36
+ system('make', 'liburing.a', exception: true)
37
+ end
38
+ end
39
+
40
+ if !find_header 'liburing.h', File.expand_path('../../vendor/liburing/src/include', __dir__)
41
+ raise "Couldn't find liburing.h"
42
+ end
43
+
44
+ $LDFLAGS << " -L#{File.expand_path('../../vendor/liburing/src', __dir__)} -l uring"
45
+ end
46
+
31
47
  $defs << '-DPOLYPHONY_USE_PIDFD_OPEN' if config[:pidfd_open]
32
48
  if config[:io_uring]
33
49
  $defs << "-DPOLYPHONY_BACKEND_LIBURING"
@@ -56,4 +72,5 @@ CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
56
72
 
57
73
  have_func('rb_fiber_transfer', 'ruby.h')
58
74
 
75
+
59
76
  create_makefile 'polyphony_ext'
@@ -94,6 +94,10 @@ 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
+ VALUE Polyphony_backend_tee(VALUE self, VALUE src, VALUE dest, VALUE chunksize) {
98
+ return Backend_tee(BACKEND(), src, dest, chunksize);
99
+ }
100
+
97
101
  VALUE Polyphony_backend_timeout(int argc,VALUE *argv, VALUE self) {
98
102
  return Backend_timeout(argc, argv, BACKEND());
99
103
  }
@@ -186,6 +190,7 @@ void Init_Polyphony() {
186
190
  rb_define_singleton_method(mPolyphony, "backend_sleep", Polyphony_backend_sleep, 1);
187
191
  rb_define_singleton_method(mPolyphony, "backend_splice", Polyphony_backend_splice, 3);
188
192
  rb_define_singleton_method(mPolyphony, "backend_splice_to_eof", Polyphony_backend_splice_to_eof, 3);
193
+ rb_define_singleton_method(mPolyphony, "backend_tee", Polyphony_backend_tee, 3);
189
194
  rb_define_singleton_method(mPolyphony, "backend_timeout", Polyphony_backend_timeout, -1);
190
195
  rb_define_singleton_method(mPolyphony, "backend_timer_loop", Polyphony_backend_timer_loop, 1);
191
196
  rb_define_singleton_method(mPolyphony, "backend_wait_event", Polyphony_backend_wait_event, 1);
@@ -112,6 +112,7 @@ VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags);
112
112
  VALUE Backend_sleep(VALUE self, VALUE duration);
113
113
  VALUE Backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen);
114
114
  VALUE Backend_splice_to_eof(VALUE self, VALUE src, VALUE dest, VALUE chunksize);
115
+ VALUE Backend_tee(VALUE self, VALUE src, VALUE dest, VALUE maxlen);
115
116
  VALUE Backend_timeout(int argc,VALUE *argv, VALUE self);
116
117
  VALUE Backend_timer_loop(VALUE self, VALUE interval);
117
118
  VALUE Backend_wait_event(VALUE self, VALUE raise);
@@ -81,6 +81,12 @@ class ::IO
81
81
  def splice_to_eof(src, dest, chunk_size = 8192)
82
82
  Polyphony.backend_splice_to_eof(src, dest, chunk_size)
83
83
  end
84
+
85
+ if RUBY_PLATFORM =~ /linux/
86
+ def tee(src, dest, maxlen)
87
+ Polyphony.backend_tee(src, dest, maxlen)
88
+ end
89
+ end
84
90
  end
85
91
  end
86
92
 
@@ -272,4 +278,8 @@ class ::IO
272
278
  def splice_to_eof_from(src, chunksize = 8192)
273
279
  Polyphony.backend_splice_to_eof(src, self, chunksize)
274
280
  end
281
+
282
+ def tee_from(src, maxlen)
283
+ Polyphony.backend_tee(src, self, maxlen)
284
+ end
275
285
  end
@@ -164,4 +164,8 @@ class Polyphony::Pipe
164
164
  def splice_to_eof_from(src, chunksize = 8192)
165
165
  Polyphony.backend_splice_to_eof(src, self, chunksize)
166
166
  end
167
+
168
+ def tee_from(src, maxlen)
169
+ Polyphony.backend_tee(src, self, maxlen)
170
+ end
167
171
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.83'
4
+ VERSION = '0.84'
5
5
  end
data/test/test_io.rb CHANGED
@@ -367,6 +367,65 @@ class IOTest < MiniTest::Test
367
367
  f.await
368
368
  end
369
369
  end
370
+
371
+ def test_tee_from
372
+ skip "tested only on Linux" unless RUBY_PLATFORM =~ /linux/
373
+
374
+ src = Polyphony.pipe
375
+ dest1 = Polyphony.pipe
376
+ dest2 = Polyphony.pipe
377
+
378
+ len1 = len2 = nil
379
+
380
+ spin {
381
+ len1 = dest1.tee_from(src, 1000)
382
+ dest1.close
383
+ len2 = IO.splice(src, dest2, 1000)
384
+ dest2.close
385
+ }
386
+
387
+ src << 'foobar'
388
+ src.close
389
+ result1 = dest1.read
390
+ result2 = dest2.read
391
+
392
+ assert_equal 'foobar', result1
393
+ assert_equal 6, len1
394
+
395
+ assert_equal 'foobar', result2
396
+ assert_equal 6, len2
397
+ end
398
+
399
+ def test_tee_class_method
400
+ skip "tested only on Linux" unless RUBY_PLATFORM =~ /linux/
401
+
402
+ src = Polyphony.pipe
403
+ dest1 = Polyphony.pipe
404
+ dest2 = Polyphony.pipe
405
+
406
+ len1 = len2 = nil
407
+
408
+ spin {
409
+ len1 = IO.tee(src, dest1, 1000)
410
+ dest1.close
411
+ len2 = IO.splice(src, dest2, 1000)
412
+ dest2.close
413
+ }
414
+
415
+ src << 'foobar'
416
+ src.close
417
+ result1 = dest1.read
418
+ result2 = dest2.read
419
+
420
+ assert_equal 'foobar', result1
421
+ assert_equal 6, len1
422
+
423
+ assert_equal 'foobar', result2
424
+ assert_equal 6, len2
425
+ end
426
+
427
+
428
+
370
429
  end
371
430
 
372
431
  class IOWithRawBufferTest < MiniTest::Test
@@ -643,7 +702,7 @@ class IOExtensionsTest < MiniTest::Test
643
702
  gz = Zlib::GzipReader.new(dest)
644
703
  data = gz.read
645
704
  assert_equal IO.read(__FILE__), data
646
- assert_in_range (now-1)..(now+1), gz.mtime
705
+ assert_in_range (now-2)..(now+1), gz.mtime
647
706
  assert_nil gz.orig_name
648
707
  assert_nil gz.comment
649
708
  end
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.83'
4
+ version: '0.84'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-10 00:00:00.000000000 Z
11
+ date: 2022-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -315,16 +315,6 @@ files:
315
315
  - ext/libev/ev_win32.c
316
316
  - ext/libev/ev_wrap.h
317
317
  - ext/libev/test_libev_win32.c
318
- - ext/liburing/liburing.h
319
- - ext/liburing/liburing/README.md
320
- - ext/liburing/liburing/barrier.h
321
- - ext/liburing/liburing/compat.h
322
- - ext/liburing/liburing/io_uring.h
323
- - ext/liburing/queue.c
324
- - ext/liburing/register.c
325
- - ext/liburing/setup.c
326
- - ext/liburing/syscall.c
327
- - ext/liburing/syscall.h
328
318
  - ext/polyphony/backend_common.c
329
319
  - ext/polyphony/backend_common.h
330
320
  - ext/polyphony/backend_io_uring.c
@@ -337,7 +327,6 @@ files:
337
327
  - ext/polyphony/io_extensions.c
338
328
  - ext/polyphony/libev.c
339
329
  - ext/polyphony/libev.h
340
- - ext/polyphony/liburing.c
341
330
  - ext/polyphony/pipe.c
342
331
  - ext/polyphony/playground.c
343
332
  - ext/polyphony/polyphony.c
@@ -1,4 +0,0 @@
1
- ## Updating the liburing source code
2
-
3
- - copy liburing/src/**/* into ext/liburing
4
- - move ext/liburing/include/**/* to ext/liburing/
@@ -1,73 +0,0 @@
1
- /* SPDX-License-Identifier: MIT */
2
- #ifndef LIBURING_BARRIER_H
3
- #define LIBURING_BARRIER_H
4
-
5
- /*
6
- From the kernel documentation file refcount-vs-atomic.rst:
7
-
8
- A RELEASE memory ordering guarantees that all prior loads and
9
- stores (all po-earlier instructions) on the same CPU are completed
10
- before the operation. It also guarantees that all po-earlier
11
- stores on the same CPU and all propagated stores from other CPUs
12
- must propagate to all other CPUs before the release operation
13
- (A-cumulative property). This is implemented using
14
- :c:func:`smp_store_release`.
15
-
16
- An ACQUIRE memory ordering guarantees that all post loads and
17
- stores (all po-later instructions) on the same CPU are
18
- completed after the acquire operation. It also guarantees that all
19
- po-later stores on the same CPU must propagate to all other CPUs
20
- after the acquire operation executes. This is implemented using
21
- :c:func:`smp_acquire__after_ctrl_dep`.
22
- */
23
-
24
- #ifdef __cplusplus
25
- #include <atomic>
26
-
27
- template <typename T>
28
- static inline void IO_URING_WRITE_ONCE(T &var, T val)
29
- {
30
- std::atomic_store_explicit(reinterpret_cast<std::atomic<T> *>(&var),
31
- val, std::memory_order_relaxed);
32
- }
33
- template <typename T>
34
- static inline T IO_URING_READ_ONCE(const T &var)
35
- {
36
- return std::atomic_load_explicit(
37
- reinterpret_cast<const std::atomic<T> *>(&var),
38
- std::memory_order_relaxed);
39
- }
40
-
41
- template <typename T>
42
- static inline void io_uring_smp_store_release(T *p, T v)
43
- {
44
- std::atomic_store_explicit(reinterpret_cast<std::atomic<T> *>(p), v,
45
- std::memory_order_release);
46
- }
47
-
48
- template <typename T>
49
- static inline T io_uring_smp_load_acquire(const T *p)
50
- {
51
- return std::atomic_load_explicit(
52
- reinterpret_cast<const std::atomic<T> *>(p),
53
- std::memory_order_acquire);
54
- }
55
- #else
56
- #include <stdatomic.h>
57
-
58
- #define IO_URING_WRITE_ONCE(var, val) \
59
- atomic_store_explicit((_Atomic typeof(var) *)&(var), \
60
- (val), memory_order_relaxed)
61
- #define IO_URING_READ_ONCE(var) \
62
- atomic_load_explicit((_Atomic typeof(var) *)&(var), \
63
- memory_order_relaxed)
64
-
65
- #define io_uring_smp_store_release(p, v) \
66
- atomic_store_explicit((_Atomic typeof(*(p)) *)(p), (v), \
67
- memory_order_release)
68
- #define io_uring_smp_load_acquire(p) \
69
- atomic_load_explicit((_Atomic typeof(*(p)) *)(p), \
70
- memory_order_acquire)
71
- #endif
72
-
73
- #endif /* defined(LIBURING_BARRIER_H) */
@@ -1,15 +0,0 @@
1
- /* SPDX-License-Identifier: MIT */
2
- #ifndef LIBURING_COMPAT_H
3
- #define LIBURING_COMPAT_H
4
-
5
- #include <linux/time_types.h>
6
-
7
- #include <inttypes.h>
8
-
9
- struct open_how {
10
- uint64_t flags;
11
- uint64_t mode;
12
- uint64_t resolve;
13
- };
14
-
15
- #endif