polyphony 0.72 → 0.73
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -2
- data/.gitignore +3 -1
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +2 -2
- data/docs/api-reference/exception.md +5 -1
- data/examples/core/ring.rb +29 -0
- data/ext/polyphony/backend_common.c +7 -1
- data/ext/polyphony/backend_common.h +1 -1
- data/ext/polyphony/backend_io_uring.c +31 -28
- data/ext/polyphony/backend_libev.c +27 -21
- data/ext/polyphony/extconf.rb +1 -0
- data/ext/polyphony/polyphony.h +5 -1
- data/ext/polyphony/thread.c +1 -1
- data/lib/polyphony/{extensions → core}/debug.rb +0 -0
- data/lib/polyphony/core/global_api.rb +0 -3
- data/lib/polyphony/extensions/exception.rb +45 -0
- data/lib/polyphony/extensions/fiber.rb +0 -1
- data/lib/polyphony/extensions/{core.rb → kernel.rb} +0 -73
- data/lib/polyphony/extensions/process.rb +19 -0
- data/lib/polyphony/extensions/timeout.rb +10 -0
- data/lib/polyphony/extensions.rb +9 -0
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -5
- data/test/test_global_api.rb +14 -1
- data/test/test_process_supervision.rb +1 -1
- data/test/test_signal.rb +20 -1
- metadata +14 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cfcb66ef2171cc3c4216bc674c38468ef4bd23333031ec77d61d74bc17b32c33
|
4
|
+
data.tar.gz: 215cf149bd26e9d3d8c64b5c6f63eeccad86c5b6dc9ed5289bb6a1537e51ab56
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9157512378e6edb0a362ea3db4fc35ecae3b6d2b54c025184a39ddf5e0e85528ac97aac1f3b829b461aa85e58a1655f35c7ad4d2aec0e8dda97c75d130625b34
|
7
|
+
data.tar.gz: f90758ee02b5dd28f488372d260b73413e4d01afa14756b8bfc787cd335c42ef43fa1b5907060cb33065727e804296bc6a25fee91d40b94e390e21c6b98d903e
|
data/.github/workflows/test.yml
CHANGED
@@ -16,7 +16,7 @@ jobs:
|
|
16
16
|
runs-on: ${{matrix.os}}
|
17
17
|
steps:
|
18
18
|
- uses: actions/checkout@v1
|
19
|
-
- uses:
|
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 -
|
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
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -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://
|
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
|
-
|
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
|
-
|
148
|
+
bool overflow_checked = false;
|
149
149
|
struct io_uring_cqe *cqe;
|
150
|
-
|
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
|
-
|
161
|
+
if (overflow_checked) goto done;
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
1003
|
-
if (
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
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
|
-
|
1017
|
-
if (
|
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
|
-
|
1154
|
+
GetBackend(self, backend);
|
1156
1155
|
|
1157
1156
|
while (1) {
|
1158
|
-
|
1159
|
-
if (
|
1160
|
-
double sleep_duration =
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
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
|
-
|
1174
|
-
|
1175
|
-
|
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 {
|
data/ext/polyphony/extconf.rb
CHANGED
@@ -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'
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -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
|
-
#
|
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
|
|
data/ext/polyphony/thread.c
CHANGED
@@ -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
|
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
|
@@ -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,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'
|
data/lib/polyphony/version.rb
CHANGED
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'
|
data/test/test_global_api.rb
CHANGED
@@ -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.
|
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
|
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
|
-
|
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.
|
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
|
+
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
|
366
|
-
- lib/polyphony/extensions/
|
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.
|
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: []
|