polyphony 0.72 → 0.73

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: 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: []