polyphony 0.72 → 0.73

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: 2af189faeecbe2eecb367a7400005306ab74370e56c61de1d703edd40d851d92
4
- data.tar.gz: c0888b10d03b9bf29f1d10a41b0050231db655c587d06035039b4c09e1c68baa
3
+ metadata.gz: cfcb66ef2171cc3c4216bc674c38468ef4bd23333031ec77d61d74bc17b32c33
4
+ data.tar.gz: 215cf149bd26e9d3d8c64b5c6f63eeccad86c5b6dc9ed5289bb6a1537e51ab56
5
5
  SHA512:
6
- metadata.gz: b86fd5682ce52e635658a8d620031f8ae841ef5f7876d6239f74772d8f700054eb3bb7732488e246433a91e5ab4279479c6f18bb0d1a154172d90f351ab8149e
7
- data.tar.gz: 713ba61a64ef73c5c16971bd0d678d6575b7bd37062a29348f02ec8e0578821d7ec41f826f1868cd017bede9c70d47192e19a0217469b331f17ff66afac21054
6
+ metadata.gz: 9157512378e6edb0a362ea3db4fc35ecae3b6d2b54c025184a39ddf5e0e85528ac97aac1f3b829b461aa85e58a1655f35c7ad4d2aec0e8dda97c75d130625b34
7
+ data.tar.gz: f90758ee02b5dd28f488372d260b73413e4d01afa14756b8bfc787cd335c42ef43fa1b5907060cb33065727e804296bc6a25fee91d40b94e390e21c6b98d903e
@@ -16,7 +16,7 @@ jobs:
16
16
  runs-on: ${{matrix.os}}
17
17
  steps:
18
18
  - uses: actions/checkout@v1
19
- - uses: actions/setup-ruby@v1
19
+ - uses: ruby/setup-ruby@v1
20
20
  with:
21
21
  ruby-version: ${{matrix.ruby}}
22
22
  - name: Install dependencies
@@ -24,7 +24,7 @@ jobs:
24
24
  gem install bundler
25
25
  bundle install
26
26
  - name: Show Linux kernel version
27
- run: uname -r
27
+ run: uname -a
28
28
  - name: Compile C-extension
29
29
  run: POLYPHONY_USE_LIBEV=1 bundle exec rake compile
30
30
  - name: Run tests
data/.gitignore CHANGED
@@ -58,4 +58,6 @@ lib/*.so
58
58
  _site
59
59
  .sass-cache
60
60
 
61
- log
61
+ log
62
+
63
+ .ruby-version
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.73 2021-12-16
2
+
3
+ - Refactor core extensions into separate files for each class
4
+ - Improve compatibility with Ruby 3.1
5
+ - Improve accuracy of `timer_loop`
6
+
1
7
  ## 0.72 2021-11-22
2
8
 
3
9
  - Add support for supervising added child fibers
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.72)
4
+ polyphony (0.73)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -75,4 +75,4 @@ DEPENDENCIES
75
75
  simplecov (= 0.17.1)
76
76
 
77
77
  BUNDLED WITH
78
- 2.2.26
78
+ 2.3.0.dev
@@ -3,15 +3,19 @@ layout: page
3
3
  title: ::Exception
4
4
  parent: API Reference
5
5
  permalink: /api-reference/exception/
6
+ source_url: https://github.com/digital-fabric/polyphony/blob/master/lib/polyphony/extensions/core.rb
7
+ ruby_docs_url: https://rubyapi.org/3.0/o/exception
6
8
  ---
7
9
  # ::Exception
8
10
 
9
- [Ruby core Exception documentation](https://ruby-doc.org/core-2.7.0/Exception.html)
11
+ [Ruby core Exception documentation](https://rubyapi.org/3.0/o/exception)
10
12
 
11
13
  The core `Exception` class is enhanced to provide a better backtrace that takes
12
14
  into account the fiber hierarchy. In addition, a `source_fiber` attribute allows
13
15
  tracking the fiber from which an uncaught exception was propagated.
14
16
 
17
+
18
+
15
19
  ## Class Methods
16
20
 
17
21
  ## Instance methods
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ M = 100
7
+ N = 10000
8
+
9
+ GC.disable
10
+
11
+ def monotonic_clock
12
+ ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
13
+ end
14
+
15
+ def spin_proc(next_fiber)
16
+ spin_loop { next_fiber << receive }
17
+ end
18
+
19
+ last = Fiber.current
20
+ N.times { last = spin_proc(last) }
21
+
22
+ snooze
23
+ t0 = monotonic_clock
24
+ M.times do
25
+ last << 'hello'
26
+ receive
27
+ end
28
+ elapsed = monotonic_clock - t0
29
+ puts "M=#{M} N=#{N} elapsed: #{elapsed}"
@@ -202,7 +202,6 @@ inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
202
202
  }
203
203
 
204
204
  inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
205
- OBJ_TAINT(str);
206
205
  rb_enc_associate(str, io_read_encoding(fptr));
207
206
  return str;
208
207
  }
@@ -246,6 +245,13 @@ inline double current_time() {
246
245
  return t / 1e9;
247
246
  }
248
247
 
248
+ inline uint64_t current_time_ns() {
249
+ struct timespec ts;
250
+ clock_gettime(CLOCK_MONOTONIC, &ts);
251
+ uint64_t ns = ts.tv_sec;
252
+ return ns * 1e9 + ts.tv_nsec;
253
+ }
254
+
249
255
  inline VALUE backend_timeout_exception(VALUE exception) {
250
256
  if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
251
257
  return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
@@ -82,7 +82,6 @@ VALUE backend_snooze();
82
82
  shrinkable = io_setstrbuf(&str, len); \
83
83
  buf = RSTRING_PTR(str); \
84
84
  total = 0; \
85
- OBJ_TAINT(str); \
86
85
  }
87
86
 
88
87
  #define READ_LOOP_YIELD_STR() { \
@@ -101,6 +100,7 @@ VALUE backend_snooze();
101
100
 
102
101
  void rectify_io_file_pos(rb_io_t *fptr);
103
102
  double current_time();
103
+ uint64_t current_time_ns();
104
104
  VALUE backend_timeout_exception(VALUE exception);
105
105
  VALUE Backend_timeout_ensure_safe(VALUE arg);
106
106
  VALUE Backend_timeout_ensure_safe(VALUE arg);
@@ -127,7 +127,7 @@ void *io_uring_backend_poll_without_gvl(void *ptr) {
127
127
 
128
128
  // copied from queue.c
129
129
  static inline bool cq_ring_needs_flush(struct io_uring *ring) {
130
- return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
130
+ return IO_URING_READ_ONCE(*ring->sq.kflags) & IORING_SQ_CQ_OVERFLOW;
131
131
  }
132
132
 
133
133
  static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
@@ -145,9 +145,9 @@ static inline void io_uring_backend_handle_completion(struct io_uring_cqe *cqe,
145
145
  // this peeks at cqes and handles each available cqe
146
146
  void io_uring_backend_handle_ready_cqes(Backend_t *backend) {
147
147
  struct io_uring *ring = &backend->ring;
148
- bool overflow_checked = false;
148
+ bool overflow_checked = false;
149
149
  struct io_uring_cqe *cqe;
150
- unsigned head;
150
+ unsigned head;
151
151
  unsigned cqe_count;
152
152
 
153
153
  again:
@@ -158,16 +158,16 @@ again:
158
158
  }
159
159
  io_uring_cq_advance(ring, cqe_count);
160
160
 
161
- if (overflow_checked) goto done;
161
+ if (overflow_checked) goto done;
162
162
 
163
- if (cq_ring_needs_flush(ring)) {
164
- __sys_io_uring_enter(ring->ring_fd, 0, 0, IORING_ENTER_GETEVENTS, NULL);
165
- overflow_checked = true;
166
- goto again;
167
- }
163
+ if (cq_ring_needs_flush(ring)) {
164
+ __sys_io_uring_enter(ring->ring_fd, 0, 0, IORING_ENTER_GETEVENTS, NULL);
165
+ overflow_checked = true;
166
+ goto again;
167
+ }
168
168
 
169
169
  done:
170
- return;
170
+ return;
171
171
  }
172
172
 
173
173
  void io_uring_backend_poll(Backend_t *backend) {
@@ -333,7 +333,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
333
333
  rb_io_check_byte_readable(fptr);
334
334
  io_unset_nonblock(fptr, io);
335
335
  rectify_io_file_pos(fptr);
336
- OBJ_TAINT(str);
337
336
 
338
337
  while (1) {
339
338
  VALUE resume_value = Qnil;
@@ -621,7 +620,6 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos) {
621
620
  rb_io_check_byte_readable(fptr);
622
621
  io_unset_nonblock(fptr, io);
623
622
  rectify_io_file_pos(fptr);
624
- OBJ_TAINT(str);
625
623
 
626
624
  while (1) {
627
625
  VALUE resume_value = Qnil;
@@ -831,7 +829,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE soc
831
829
  rb_io_synchronized(fp);
832
830
 
833
831
  // if (rsock_do_not_reverse_lookup) {
834
- // fp->mode |= FMODE_NOREVLOOKUP;
832
+ // fp->mode |= FMODE_NOREVLOOKUP;
835
833
  // }
836
834
  if (loop) {
837
835
  rb_yield(socket);
@@ -962,7 +960,7 @@ inline struct __kernel_timespec double_to_timespec(double duration) {
962
960
  double duration_fraction = modf(duration, &duration_integral);
963
961
  struct __kernel_timespec ts;
964
962
  ts.tv_sec = duration_integral;
965
- ts.tv_nsec = floor(duration_fraction * 1000000000);
963
+ ts.tv_nsec = floor(duration_fraction * 1000000000);
966
964
  return ts;
967
965
  }
968
966
 
@@ -994,29 +992,34 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
994
992
 
995
993
  VALUE Backend_timer_loop(VALUE self, VALUE interval) {
996
994
  Backend_t *backend;
997
- double interval_d = NUM2DBL(interval);
995
+ uint64_t interval_ns = NUM2DBL(interval) * 1e9;
996
+ uint64_t next_time_ns = 0;
997
+ VALUE resume_value = Qnil;
998
+
998
999
  GetBackend(self, backend);
999
- double next_time = 0.;
1000
1000
 
1001
1001
  while (1) {
1002
- double now = current_time();
1003
- if (next_time == 0.) next_time = current_time() + interval_d;
1004
- double sleep_duration = next_time - now;
1005
- if (sleep_duration < 0) sleep_duration = 0;
1006
-
1007
- VALUE resume_value = Qnil;
1008
- int completed = io_uring_backend_submit_timeout_and_await(backend, sleep_duration, &resume_value);
1009
- RAISE_IF_EXCEPTION(resume_value);
1010
- if (!completed) return resume_value;
1011
- RB_GC_GUARD(resume_value);
1002
+ double now_ns = current_time_ns();
1003
+ if (next_time_ns == 0) next_time_ns = now_ns + interval_ns;
1004
+ if (next_time_ns > now_ns) {
1005
+ double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
1006
+ int completed = io_uring_backend_submit_timeout_and_await(backend, sleep_duration, &resume_value);
1007
+ RAISE_IF_EXCEPTION(resume_value);
1008
+ if (!completed) return resume_value;
1009
+ }
1010
+ else {
1011
+ resume_value = backend_snooze();
1012
+ RAISE_IF_EXCEPTION(resume_value);
1013
+ }
1012
1014
 
1013
1015
  rb_yield(Qnil);
1014
1016
 
1015
1017
  while (1) {
1016
- next_time += interval_d;
1017
- if (next_time > now) break;
1018
+ next_time_ns += interval_ns;
1019
+ if (next_time_ns > now_ns) break;
1018
1020
  }
1019
1021
  }
1022
+ RB_GC_GUARD(resume_value);
1020
1023
  }
1021
1024
 
1022
1025
  struct Backend_timeout_ctx {
@@ -287,7 +287,6 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof,
287
287
  io_verify_blocking_mode(fptr, io, Qfalse);
288
288
  rectify_io_file_pos(fptr);
289
289
  watcher.fiber = Qnil;
290
- OBJ_TAINT(str);
291
290
 
292
291
  while (1) {
293
292
  backend->base.op_count++;
@@ -1147,33 +1146,40 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
1147
1146
  noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
1148
1147
  Backend_t *backend;
1149
1148
  struct libev_timer watcher;
1150
- double interval_d = NUM2DBL(interval);
1151
-
1152
- GetBackend(self, backend);
1153
1149
  watcher.fiber = rb_fiber_current();
1150
+ uint64_t interval_ns = NUM2DBL(interval) * 1e9;
1151
+ uint64_t next_time_ns = 0;
1152
+ VALUE resume_value = Qnil;
1154
1153
 
1155
- double next_time = 0.;
1154
+ GetBackend(self, backend);
1156
1155
 
1157
1156
  while (1) {
1158
- double now = current_time();
1159
- if (next_time == 0.) next_time = current_time() + interval_d;
1160
- double sleep_duration = next_time - now;
1161
- if (sleep_duration < 0) sleep_duration = 0;
1162
-
1163
- VALUE switchpoint_result = Qnil;
1164
- ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
1165
- ev_timer_start(backend->ev_loop, &watcher.timer);
1166
- backend->base.op_count++;
1167
- switchpoint_result = backend_await((struct Backend_base *)backend);
1168
- ev_timer_stop(backend->ev_loop, &watcher.timer);
1169
- RAISE_IF_EXCEPTION(switchpoint_result);
1170
- RB_GC_GUARD(switchpoint_result);
1157
+ uint64_t now_ns = current_time_ns();
1158
+ if (next_time_ns == 0) next_time_ns = now_ns + interval_ns;
1159
+ double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
1160
+
1161
+ if (next_time_ns > now_ns) {
1162
+ double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
1163
+ ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
1164
+ ev_timer_start(backend->ev_loop, &watcher.timer);
1165
+ backend->base.op_count++;
1166
+ resume_value = backend_await((struct Backend_base *)backend);
1167
+ ev_timer_stop(backend->ev_loop, &watcher.timer);
1168
+ RAISE_IF_EXCEPTION(resume_value);
1169
+ }
1170
+ else {
1171
+ resume_value = backend_snooze();
1172
+ RAISE_IF_EXCEPTION(resume_value);
1173
+ }
1171
1174
 
1172
1175
  rb_yield(Qnil);
1173
- do {
1174
- next_time += interval_d;
1175
- } while (next_time <= now);
1176
+
1177
+ while (1) {
1178
+ next_time_ns += interval_ns;
1179
+ if (next_time_ns > now_ns) break;
1180
+ }
1176
1181
  }
1182
+ RB_GC_GUARD(resume_value);
1177
1183
  }
1178
1184
 
1179
1185
  struct libev_timeout {
@@ -51,6 +51,7 @@ $defs << '-DPOLYPHONY_PLAYGROUND' if ENV['POLYPHONY_PLAYGROUND']
51
51
 
52
52
  CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
53
53
 
54
+ have_func('rb_fiber_transfer', 'ruby.h')
54
55
 
55
56
  dir_config 'polyphony_ext'
56
57
  create_makefile 'polyphony_ext'
@@ -26,7 +26,11 @@
26
26
  #define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
27
27
 
28
28
  // Fiber#transfer
29
- #define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
29
+ #if HAVE_RB_FIBER_TRANSFER
30
+ #define FIBER_TRANSFER(fiber, value) rb_fiber_transfer(fiber, 1, &value)
31
+ #else
32
+ #define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
33
+ #endif
30
34
 
31
35
  #define BACKEND() (rb_ivar_get(rb_thread_current(), ID_ivar_backend))
32
36
 
@@ -40,7 +40,7 @@ VALUE Thread_fiber_schedule_and_wakeup(VALUE self, VALUE fiber, VALUE resume_obj
40
40
  }
41
41
 
42
42
  if (Backend_wakeup(rb_ivar_get(self, ID_ivar_backend)) == Qnil) {
43
- // we're not inside the ev_loop, so we just do a switchpoint
43
+ // we're not inside Backend_poll, so we just do a switchpoint
44
44
  Thread_switch_fiber(self);
45
45
  }
46
46
 
File without changes
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../extensions/core'
4
- require_relative '../extensions/fiber'
5
- require_relative './exceptions'
6
3
  require_relative './throttler'
7
4
 
8
5
  module Polyphony
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Exeption overrides
4
+ class ::Exception
5
+ class << self
6
+ attr_accessor :__disable_sanitized_backtrace__
7
+ end
8
+
9
+ attr_accessor :source_fiber, :raising_fiber
10
+
11
+ alias_method :orig_initialize, :initialize
12
+ def initialize(*args)
13
+ @raising_fiber = Fiber.current
14
+ orig_initialize(*args)
15
+ end
16
+
17
+ alias_method :orig_backtrace, :backtrace
18
+ def backtrace
19
+ unless @backtrace_called
20
+ @backtrace_called = true
21
+ return orig_backtrace
22
+ end
23
+
24
+ sanitized_backtrace
25
+ end
26
+
27
+ def sanitized_backtrace
28
+ return sanitize(orig_backtrace) unless @raising_fiber
29
+
30
+ backtrace = orig_backtrace || []
31
+ sanitize(backtrace + @raising_fiber.caller)
32
+ end
33
+
34
+ POLYPHONY_DIR = File.expand_path(File.join(__dir__, '..'))
35
+
36
+ def sanitize(backtrace)
37
+ return backtrace if ::Exception.__disable_sanitized_backtrace__
38
+
39
+ backtrace.reject { |l| l[POLYPHONY_DIR] }
40
+ end
41
+
42
+ def invoke
43
+ Kernel.raise(self)
44
+ end
45
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fiber'
4
3
  require_relative '../core/exceptions'
5
4
 
6
5
  module Polyphony
@@ -1,73 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fiber'
4
- require 'timeout'
5
3
  require 'open3'
6
4
 
7
- require_relative '../core/exceptions'
8
-
9
- # Exeption overrides
10
- class ::Exception
11
- class << self
12
- attr_accessor :__disable_sanitized_backtrace__
13
- end
14
-
15
- attr_accessor :source_fiber, :raising_fiber
16
-
17
- alias_method :orig_initialize, :initialize
18
- def initialize(*args)
19
- @raising_fiber = Fiber.current
20
- orig_initialize(*args)
21
- end
22
-
23
- alias_method :orig_backtrace, :backtrace
24
- def backtrace
25
- unless @backtrace_called
26
- @backtrace_called = true
27
- return orig_backtrace
28
- end
29
-
30
- sanitized_backtrace
31
- end
32
-
33
- def sanitized_backtrace
34
- return sanitize(orig_backtrace) unless @raising_fiber
35
-
36
- backtrace = orig_backtrace || []
37
- sanitize(backtrace + @raising_fiber.caller)
38
- end
39
-
40
- POLYPHONY_DIR = File.expand_path(File.join(__dir__, '..'))
41
-
42
- def sanitize(backtrace)
43
- return backtrace if ::Exception.__disable_sanitized_backtrace__
44
-
45
- backtrace.reject { |l| l[POLYPHONY_DIR] }
46
- end
47
-
48
- def invoke
49
- Kernel.raise(self)
50
- end
51
- end
52
-
53
- # Overrides for Process
54
- module ::Process
55
- class << self
56
- alias_method :orig_detach, :detach
57
- def detach(pid)
58
- fiber = spin { Polyphony.backend_waitpid(pid) }
59
- fiber.define_singleton_method(:pid) { pid }
60
- fiber
61
- end
62
-
63
- alias_method :orig_daemon, :daemon
64
- def daemon(*args)
65
- orig_daemon(*args)
66
- Polyphony.original_pid = Process.pid
67
- end
68
- end
69
- end
70
-
71
5
  # Kernel extensions (methods available to all objects / call sites)
72
6
  module ::Kernel
73
7
  alias_method :orig_sleep, :sleep
@@ -159,10 +93,3 @@ module ::Kernel
159
93
  end
160
94
  end
161
95
  end
162
-
163
- # Override Timeout to use cancel scope
164
- module ::Timeout
165
- def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
166
- cancel_after(sec, with_exception: [klass, message], &block)
167
- end
168
- end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Overrides for Process
4
+ module ::Process
5
+ class << self
6
+ alias_method :orig_detach, :detach
7
+ def detach(pid)
8
+ fiber = spin { Polyphony.backend_waitpid(pid) }
9
+ fiber.define_singleton_method(:pid) { pid }
10
+ fiber
11
+ end
12
+
13
+ alias_method :orig_daemon, :daemon
14
+ def daemon(*args)
15
+ orig_daemon(*args)
16
+ Polyphony.original_pid = Process.pid
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'timeout'
4
+
5
+ # Override Timeout to use cancel scope
6
+ module ::Timeout
7
+ def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
8
+ cancel_after(sec, with_exception: [klass, message], &block)
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './extensions/exception'
4
+ require_relative './extensions/fiber'
5
+ require_relative './extensions/io'
6
+ require_relative './extensions/kernel'
7
+ require_relative './extensions/process'
8
+ require_relative './extensions/thread'
9
+ require_relative './extensions/timeout'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.72'
4
+ VERSION = '0.73'
5
5
  end
data/lib/polyphony.rb CHANGED
@@ -2,15 +2,12 @@
2
2
 
3
3
  require 'fiber'
4
4
  require_relative './polyphony_ext'
5
-
6
- require_relative './polyphony/extensions/core'
7
- require_relative './polyphony/extensions/thread'
8
- require_relative './polyphony/extensions/fiber'
9
- require_relative './polyphony/extensions/io'
5
+ require_relative './polyphony/extensions'
10
6
 
11
7
  Thread.current.setup_fiber_scheduling
12
8
  Thread.current.backend = Polyphony::Backend.new
13
9
 
10
+ require_relative './polyphony/core/exceptions'
14
11
  require_relative './polyphony/core/global_api'
15
12
  require_relative './polyphony/core/resource_pool'
16
13
  require_relative './polyphony/core/sync'
@@ -412,7 +412,7 @@ class GlobalAPIEtcTest < MiniTest::Test
412
412
  f = after(0.001) { buffer << 2 }
413
413
  snooze
414
414
  assert_equal [], buffer
415
- sleep 0.001
415
+ sleep 0.0015
416
416
  assert_equal [2], buffer
417
417
  end
418
418
 
@@ -429,6 +429,19 @@ class GlobalAPIEtcTest < MiniTest::Test
429
429
  assert_in_range 4..6, buffer.size
430
430
  end
431
431
 
432
+ def test_every_with_slow_op
433
+ skip unless IS_LINUX
434
+
435
+ buffer = []
436
+ t0 = Time.now
437
+ f = spin do
438
+ every(0.01) { sleep 0.05; buffer << 1 }
439
+ end
440
+ sleep 0.15
441
+ f.stop
442
+ assert_in_range 2..3, buffer.size
443
+ end
444
+
432
445
  def test_sleep
433
446
  t0 = Time.now
434
447
  sleep 0.1
@@ -65,7 +65,7 @@ class ProcessSupervisionTest < MiniTest::Test
65
65
 
66
66
  supervisor = spin { supervise(watcher) }
67
67
 
68
- sleep 0.05
68
+ sleep 0.1
69
69
  supervisor.terminate
70
70
  supervisor.await
71
71
 
data/test/test_signal.rb CHANGED
@@ -93,4 +93,23 @@ class SignalTrapTest < Minitest::Test
93
93
  buffer = i.read
94
94
  assert_equal "INT\n", buffer
95
95
  end
96
- end
96
+
97
+ def test_busy_signal_handling
98
+ i, o = IO.pipe
99
+ pid = Polyphony.fork do
100
+ main = Fiber.current
101
+ trap('INT') { o.puts 'INT'; o.close; main.stop }
102
+ i.close
103
+ f1 = spin_loop { snooze }
104
+ f2 = spin_loop { snooze }
105
+ f1.await
106
+ end
107
+
108
+ o.close
109
+ sleep 0.1
110
+ Process.kill('INT', pid)
111
+ Thread.current.backend.waitpid(pid)
112
+ buffer = i.read
113
+ assert_equal "INT\n", buffer
114
+ end
115
+ 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.72'
4
+ version: '0.73'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-22 00:00:00.000000000 Z
11
+ date: 2021-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -136,7 +136,7 @@ dependencies:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: 1.1.4
139
- description:
139
+ description:
140
140
  email: sharon@noteflakes.com
141
141
  executables: []
142
142
  extensions:
@@ -233,6 +233,7 @@ files:
233
233
  - examples/core/queue.rb
234
234
  - examples/core/recurrent-timer.rb
235
235
  - examples/core/resource_delegate.rb
236
+ - examples/core/ring.rb
236
237
  - examples/core/spin.rb
237
238
  - examples/core/spin_error_backtrace.rb
238
239
  - examples/core/supervise-process.rb
@@ -354,6 +355,7 @@ files:
354
355
  - lib/polyphony/adapters/redis.rb
355
356
  - lib/polyphony/adapters/sequel.rb
356
357
  - lib/polyphony/core/channel.rb
358
+ - lib/polyphony/core/debug.rb
357
359
  - lib/polyphony/core/exceptions.rb
358
360
  - lib/polyphony/core/global_api.rb
359
361
  - lib/polyphony/core/resource_pool.rb
@@ -362,13 +364,16 @@ files:
362
364
  - lib/polyphony/core/throttler.rb
363
365
  - lib/polyphony/core/timer.rb
364
366
  - lib/polyphony/debugger.rb
365
- - lib/polyphony/extensions/core.rb
366
- - lib/polyphony/extensions/debug.rb
367
+ - lib/polyphony/extensions.rb
368
+ - lib/polyphony/extensions/exception.rb
367
369
  - lib/polyphony/extensions/fiber.rb
368
370
  - lib/polyphony/extensions/io.rb
371
+ - lib/polyphony/extensions/kernel.rb
369
372
  - lib/polyphony/extensions/openssl.rb
373
+ - lib/polyphony/extensions/process.rb
370
374
  - lib/polyphony/extensions/socket.rb
371
375
  - lib/polyphony/extensions/thread.rb
376
+ - lib/polyphony/extensions/timeout.rb
372
377
  - lib/polyphony/net.rb
373
378
  - lib/polyphony/version.rb
374
379
  - polyphony.gemspec
@@ -406,7 +411,7 @@ metadata:
406
411
  documentation_uri: https://digital-fabric.github.io/polyphony/
407
412
  homepage_uri: https://digital-fabric.github.io/polyphony/
408
413
  changelog_uri: https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md
409
- post_install_message:
414
+ post_install_message:
410
415
  rdoc_options:
411
416
  - "--title"
412
417
  - polyphony
@@ -425,8 +430,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
425
430
  - !ruby/object:Gem::Version
426
431
  version: '0'
427
432
  requirements: []
428
- rubygems_version: 3.1.2
429
- signing_key:
433
+ rubygems_version: 3.3.0.dev
434
+ signing_key:
430
435
  specification_version: 4
431
436
  summary: Fine grained concurrency for Ruby
432
437
  test_files: []