polyphony 0.46.0 → 0.46.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/TODO.md +22 -9
- data/bin/test +4 -0
- data/examples/performance/fiber_transfer.rb +13 -4
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +7 -18
- data/ext/polyphony/backend_common.h +11 -0
- data/ext/polyphony/backend_io_uring.c +49 -14
- data/ext/polyphony/backend_libev.c +35 -0
- data/ext/polyphony/fiber.c +1 -6
- data/ext/polyphony/polyphony.h +4 -1
- data/ext/polyphony/thread.c +1 -3
- data/lib/polyphony/core/exceptions.rb +0 -4
- data/lib/polyphony/core/global_api.rb +8 -3
- data/lib/polyphony/extensions/core.rb +9 -15
- data/lib/polyphony/extensions/openssl.rb +6 -0
- data/lib/polyphony/extensions/socket.rb +4 -0
- data/lib/polyphony/version.rb +1 -1
- data/test/helper.rb +1 -1
- data/test/stress.rb +1 -1
- data/test/test_backend.rb +11 -0
- data/test/test_global_api.rb +13 -0
- data/test/test_queue.rb +1 -1
- data/test/test_socket.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 831c85a16a22fe3877044430a4d1cc4a270d18dc73e9ceca8d4826623ab0ddc8
|
4
|
+
data.tar.gz: f0432473abb769be2805ad354dddf44465789ebe2d5220f194660e4c6521ec87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bfecbed04a8052c3a885dfde73975694313801d2a8341260041be84e4910ac459af71766f7df6fa96e5afad66a737b97e36531811bd47cab407ad43b239e073
|
7
|
+
data.tar.gz: 2caa40f7193cf1954b69adc5810844ad4e578a4472382602a6ee4204d548e8327344f913bc0aef076030e7deacb911cab1733b281f7a2e8849ffcbd009a00ebc
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## 0.46.1
|
2
|
+
|
3
|
+
* Add `TCPServer#accept_loop`, `OpenSSL::SSL::SSLSocket#accept_loop` method
|
4
|
+
* Fix compilation error on MacOS (#43)
|
5
|
+
* Fix backtrace for `Timeout.timeout`
|
6
|
+
* Add `Backend#timer_loop`
|
7
|
+
|
1
8
|
## 0.46.0
|
2
9
|
|
3
10
|
* Implement [io_uring backend](https://github.com/digital-fabric/polyphony/pull/44)
|
data/Gemfile.lock
CHANGED
data/TODO.md
CHANGED
@@ -1,16 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
-
|
4
|
-
-
|
5
|
-
-
|
6
|
-
-
|
1
|
+
## Roadmap for Polyphony 1.0
|
2
|
+
|
3
|
+
- Check why worker-thread example doesn't work.
|
4
|
+
- Add test that mimics the original design for Monocrono:
|
5
|
+
- 256 fibers each waiting for a message
|
6
|
+
- When message received do some blocking work using a `ThreadPool`
|
7
|
+
- Send messages, collect responses, check for correctness
|
7
8
|
- Improve `#supervise`. It does not work as advertised, and seems to exhibit an
|
8
9
|
inconsistent behaviour (see supervisor example).
|
9
|
-
- Fix backtrace for `Timeout.timeout` API (see timeout example).
|
10
|
-
- Check why worker-thread example doesn't work.
|
11
10
|
|
12
|
-
|
11
|
+
- io_uring
|
12
|
+
- Use playground.c to find out why we when submitting and waiting for
|
13
|
+
completion in single syscall signals seem to be blocked until the syscall
|
14
|
+
returns. Is this a bug in io_uring/liburing?
|
13
15
|
|
16
|
+
-----------------------------------------------------
|
17
|
+
|
18
|
+
- Add `Backend#splice(in, out, nbytes)` API
|
19
|
+
- Adapter for io/console (what does `IO#raw` do?)
|
20
|
+
- Adapter for Pry and IRB (Which fixes #5 and #6)
|
21
|
+
- allow backend selection at runtime
|
14
22
|
- Debugging
|
15
23
|
- Eat your own dogfood: need a good tool to check what's going on when some
|
16
24
|
test fails
|
@@ -148,6 +156,11 @@
|
|
148
156
|
- `IO.foreach`
|
149
157
|
- `Process.waitpid`
|
150
158
|
|
159
|
+
### Quic / HTTP/3
|
160
|
+
|
161
|
+
- Python impl: https://github.com/aiortc/aioquic/
|
162
|
+
- Go impl: https://github.com/lucas-clemente/quic-go
|
163
|
+
|
151
164
|
### DNS client
|
152
165
|
|
153
166
|
```ruby
|
data/bin/test
ADDED
@@ -12,6 +12,7 @@ end
|
|
12
12
|
def run(num_fibers)
|
13
13
|
count = 0
|
14
14
|
|
15
|
+
GC.start
|
15
16
|
GC.disable
|
16
17
|
|
17
18
|
first = nil
|
@@ -36,13 +37,21 @@ def run(num_fibers)
|
|
36
37
|
last.next = first
|
37
38
|
|
38
39
|
t0 = Time.now
|
40
|
+
puts "start transfer..."
|
39
41
|
first.transfer
|
40
42
|
elapsed = Time.now - t0
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
+
rss = `ps -o rss= -p #{Process.pid}`.to_i
|
45
|
+
|
46
|
+
puts "fibers: #{num_fibers} rss: #{rss} count: #{count} rate: #{count / elapsed}"
|
47
|
+
rescue Exception => e
|
48
|
+
puts "Stopped at #{count} fibers"
|
49
|
+
p e
|
44
50
|
end
|
45
51
|
|
52
|
+
puts "pid: #{Process.pid}"
|
46
53
|
run(100)
|
47
|
-
run(1000)
|
48
|
-
run(10000)
|
54
|
+
# run(1000)
|
55
|
+
# run(10000)
|
56
|
+
# run(100000)
|
57
|
+
# run(400000)
|
@@ -4,41 +4,30 @@ require 'bundler/setup'
|
|
4
4
|
require 'polyphony'
|
5
5
|
require 'http/parser'
|
6
6
|
|
7
|
-
$connection_count = 0
|
8
|
-
|
9
7
|
def handle_client(socket)
|
10
|
-
|
8
|
+
pending_requests = []
|
11
9
|
parser = Http::Parser.new
|
12
|
-
|
13
|
-
|
14
|
-
reqs << Object.new # parser
|
15
|
-
end
|
10
|
+
parser.on_message_complete = proc { pending_requests << parser }
|
11
|
+
|
16
12
|
socket.recv_loop do |data|
|
17
13
|
parser << data
|
18
|
-
|
19
|
-
handle_request(socket, req)
|
20
|
-
req = nil
|
21
|
-
end
|
14
|
+
write_response(socket) while pending_requests.shift
|
22
15
|
end
|
23
16
|
rescue IOError, SystemCallError => e
|
24
17
|
# do nothing
|
25
18
|
ensure
|
26
|
-
$connection_count -= 1
|
27
19
|
socket&.close
|
28
20
|
end
|
29
21
|
|
30
|
-
def
|
22
|
+
def write_response(socket)
|
31
23
|
status_code = "200 OK"
|
32
24
|
data = "Hello world!\n"
|
33
25
|
headers = "Content-Type: text/plain\r\nContent-Length: #{data.bytesize}\r\n"
|
34
|
-
|
26
|
+
socket.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
|
35
27
|
end
|
36
28
|
|
37
29
|
server = TCPServer.open('0.0.0.0', 1234)
|
38
30
|
puts "pid #{Process.pid}"
|
39
31
|
puts "listening on port 1234"
|
40
32
|
|
41
|
-
|
42
|
-
client = server.accept
|
43
|
-
spin { handle_client(client) }
|
44
|
-
end
|
33
|
+
server.accept_loop { |c| handle_client(c) }
|
@@ -1,3 +1,5 @@
|
|
1
|
+
#include <time.h>
|
2
|
+
|
1
3
|
#include "ruby.h"
|
2
4
|
#include "ruby/io.h"
|
3
5
|
|
@@ -107,3 +109,12 @@ inline void rectify_io_file_pos(rb_io_t *fptr) {
|
|
107
109
|
fptr->rbuf.len = 0;
|
108
110
|
}
|
109
111
|
}
|
112
|
+
|
113
|
+
inline double current_time() {
|
114
|
+
struct timespec ts;
|
115
|
+
clock_gettime(CLOCK_MONOTONIC, &ts);
|
116
|
+
long long ns = ts.tv_sec;
|
117
|
+
ns = ns * 1000000000 + ts.tv_nsec;
|
118
|
+
double t = ns;
|
119
|
+
return t / 1e9;
|
120
|
+
}
|
@@ -7,18 +7,18 @@
|
|
7
7
|
#include <fcntl.h>
|
8
8
|
#include <netinet/in.h>
|
9
9
|
#include <arpa/inet.h>
|
10
|
-
|
11
|
-
#include "polyphony.h"
|
12
|
-
#include "../liburing/liburing.h"
|
13
|
-
#include "ruby/thread.h"
|
14
|
-
#include "backend_io_uring_context.h"
|
15
|
-
|
10
|
+
#include <stdnoreturn.h>
|
16
11
|
#include <poll.h>
|
17
12
|
#include <sys/types.h>
|
18
13
|
#include <sys/eventfd.h>
|
19
14
|
#include <sys/wait.h>
|
20
15
|
#include <errno.h>
|
21
16
|
|
17
|
+
#include "polyphony.h"
|
18
|
+
#include "../liburing/liburing.h"
|
19
|
+
#include "ruby/thread.h"
|
20
|
+
#include "backend_io_uring_context.h"
|
21
|
+
|
22
22
|
#ifndef __NR_pidfd_open
|
23
23
|
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
24
24
|
#endif
|
@@ -304,6 +304,7 @@ int io_uring_backend_defer_submit_and_await(
|
|
304
304
|
|
305
305
|
if (value_ptr) (*value_ptr) = switchpoint_result;
|
306
306
|
RB_GC_GUARD(switchpoint_result);
|
307
|
+
RB_GC_GUARD(ctx->fiber);
|
307
308
|
return ctx->result;
|
308
309
|
}
|
309
310
|
|
@@ -773,29 +774,62 @@ VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
773
774
|
return self;
|
774
775
|
}
|
775
776
|
|
776
|
-
|
777
|
-
|
778
|
-
struct io_uring_sqe *sqe;
|
777
|
+
// returns true if completed, 0 otherwise
|
778
|
+
int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duration, VALUE *resume_value) {
|
779
779
|
double duration_integral;
|
780
|
-
double duration_fraction = modf(
|
780
|
+
double duration_fraction = modf(duration, &duration_integral);
|
781
781
|
struct __kernel_timespec ts;
|
782
782
|
|
783
|
-
|
784
|
-
sqe = io_uring_get_sqe(&backend->ring);
|
783
|
+
struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
|
785
784
|
ts.tv_sec = duration_integral;
|
786
785
|
ts.tv_nsec = floor(duration_fraction * 1000000000);
|
787
786
|
|
788
|
-
VALUE resume_value = Qnil;
|
789
787
|
op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_TIMEOUT);
|
790
788
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
791
789
|
|
792
|
-
io_uring_backend_defer_submit_and_await(backend, sqe, ctx,
|
790
|
+
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
793
791
|
OP_CONTEXT_RELEASE(&backend->store, ctx);
|
792
|
+
return ctx->completed;
|
793
|
+
}
|
794
|
+
|
795
|
+
VALUE Backend_sleep(VALUE self, VALUE duration) {
|
796
|
+
Backend_t *backend;
|
797
|
+
GetBackend(self, backend);
|
798
|
+
|
799
|
+
VALUE resume_value = Qnil;
|
800
|
+
io_uring_backend_submit_timeout_and_await(backend, NUM2DBL(duration), &resume_value);
|
794
801
|
RAISE_IF_EXCEPTION(resume_value);
|
795
802
|
RB_GC_GUARD(resume_value);
|
796
803
|
return resume_value;
|
797
804
|
}
|
798
805
|
|
806
|
+
VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
807
|
+
Backend_t *backend;
|
808
|
+
double interval_d = NUM2DBL(interval);
|
809
|
+
GetBackend(self, backend);
|
810
|
+
double next_time = 0.;
|
811
|
+
|
812
|
+
while (1) {
|
813
|
+
double now = current_time();
|
814
|
+
if (next_time == 0.) next_time = current_time() + interval_d;
|
815
|
+
double sleep_duration = next_time - now;
|
816
|
+
if (sleep_duration < 0) sleep_duration = 0;
|
817
|
+
|
818
|
+
VALUE resume_value = Qnil;
|
819
|
+
int completed = io_uring_backend_submit_timeout_and_await(backend, sleep_duration, &resume_value);
|
820
|
+
RAISE_IF_EXCEPTION(resume_value);
|
821
|
+
if (!completed) return resume_value;
|
822
|
+
RB_GC_GUARD(resume_value);
|
823
|
+
|
824
|
+
rb_yield(Qnil);
|
825
|
+
|
826
|
+
while (1) {
|
827
|
+
next_time += interval_d;
|
828
|
+
if (next_time > now) break;
|
829
|
+
}
|
830
|
+
}
|
831
|
+
}
|
832
|
+
|
799
833
|
VALUE Backend_waitpid(VALUE self, VALUE pid) {
|
800
834
|
Backend_t *backend;
|
801
835
|
int pid_int = NUM2INT(pid);
|
@@ -864,6 +898,7 @@ void Init_Backend() {
|
|
864
898
|
rb_define_method(cBackend, "connect", Backend_connect, 3);
|
865
899
|
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
866
900
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
901
|
+
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
867
902
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
868
903
|
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
869
904
|
|
@@ -7,6 +7,7 @@
|
|
7
7
|
#include <fcntl.h>
|
8
8
|
#include <netinet/in.h>
|
9
9
|
#include <arpa/inet.h>
|
10
|
+
#include <stdnoreturn.h>
|
10
11
|
|
11
12
|
#include "polyphony.h"
|
12
13
|
#include "../libev/ev.h"
|
@@ -688,6 +689,39 @@ VALUE Backend_sleep(VALUE self, VALUE duration) {
|
|
688
689
|
return switchpoint_result;
|
689
690
|
}
|
690
691
|
|
692
|
+
noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
693
|
+
Backend_t *backend;
|
694
|
+
struct libev_timer watcher;
|
695
|
+
double interval_d = NUM2DBL(interval);
|
696
|
+
|
697
|
+
GetBackend(self, backend);
|
698
|
+
watcher.fiber = rb_fiber_current();
|
699
|
+
|
700
|
+
double next_time = 0.;
|
701
|
+
|
702
|
+
while (1) {
|
703
|
+
double now = current_time();
|
704
|
+
if (next_time == 0.) next_time = current_time() + interval_d;
|
705
|
+
double sleep_duration = next_time - now;
|
706
|
+
if (sleep_duration < 0) sleep_duration = 0;
|
707
|
+
|
708
|
+
VALUE switchpoint_result = Qnil;
|
709
|
+
ev_timer_init(&watcher.timer, Backend_timer_callback, sleep_duration, 0.);
|
710
|
+
ev_timer_start(backend->ev_loop, &watcher.timer);
|
711
|
+
switchpoint_result = backend_await(backend);
|
712
|
+
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
713
|
+
RAISE_IF_EXCEPTION(switchpoint_result);
|
714
|
+
RB_GC_GUARD(switchpoint_result);
|
715
|
+
|
716
|
+
rb_yield(Qnil);
|
717
|
+
|
718
|
+
while (1) {
|
719
|
+
next_time += interval_d;
|
720
|
+
if (next_time > now) break;
|
721
|
+
}
|
722
|
+
}
|
723
|
+
}
|
724
|
+
|
691
725
|
struct libev_child {
|
692
726
|
struct ev_child child;
|
693
727
|
VALUE fiber;
|
@@ -777,6 +811,7 @@ void Init_Backend() {
|
|
777
811
|
rb_define_method(cBackend, "send", Backend_write, 2);
|
778
812
|
rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
|
779
813
|
rb_define_method(cBackend, "sleep", Backend_sleep, 1);
|
814
|
+
rb_define_method(cBackend, "timer_loop", Backend_timer_loop, 1);
|
780
815
|
rb_define_method(cBackend, "waitpid", Backend_waitpid, 1);
|
781
816
|
rb_define_method(cBackend, "wait_event", Backend_wait_event, 1);
|
782
817
|
|
data/ext/polyphony/fiber.c
CHANGED
@@ -21,7 +21,7 @@ VALUE SYM_fiber_terminate;
|
|
21
21
|
|
22
22
|
static VALUE Fiber_safe_transfer(int argc, VALUE *argv, VALUE self) {
|
23
23
|
VALUE arg = (argc == 0) ? Qnil : argv[0];
|
24
|
-
VALUE ret =
|
24
|
+
VALUE ret = FIBER_TRANSFER(self, arg);
|
25
25
|
|
26
26
|
RAISE_IF_EXCEPTION(ret);
|
27
27
|
RB_GC_GUARD(ret);
|
@@ -42,10 +42,6 @@ inline VALUE Fiber_auto_watcher(VALUE self) {
|
|
42
42
|
void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
43
43
|
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
44
44
|
if (thread == Qnil) {
|
45
|
-
INSPECT("Fiber with no thread", fiber);
|
46
|
-
TRACE_CALLER();
|
47
|
-
TRACE_C_STACK();
|
48
|
-
exit(-1);
|
49
45
|
rb_raise(rb_eRuntimeError, "No thread set for fiber");
|
50
46
|
// rb_warn("No thread set for fiber");
|
51
47
|
return;
|
@@ -57,7 +53,6 @@ void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
|
57
53
|
void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
|
58
54
|
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
59
55
|
if (thread == Qnil) {
|
60
|
-
INSPECT("Fiber with no thread", fiber);
|
61
56
|
rb_raise(rb_eRuntimeError, "No thread set for fiber");
|
62
57
|
// rb_warn("No thread set for fiber");
|
63
58
|
return;
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -23,12 +23,15 @@
|
|
23
23
|
#define TRACE(...) rb_funcall(rb_cObject, ID_fiber_trace, __VA_ARGS__)
|
24
24
|
#define COND_TRACE(...) if (__tracing_enabled__) { TRACE(__VA_ARGS__); }
|
25
25
|
|
26
|
+
// exceptions
|
26
27
|
#define TEST_EXCEPTION(ret) (RTEST(rb_obj_is_kind_of(ret, rb_eException)))
|
27
|
-
|
28
28
|
#define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
|
29
29
|
#define RAISE_IF_EXCEPTION(ret) if (RTEST(rb_obj_is_kind_of(ret, rb_eException))) { RAISE_EXCEPTION(ret); }
|
30
30
|
#define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
|
31
31
|
|
32
|
+
// Fiber#transfer
|
33
|
+
#define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
|
34
|
+
|
32
35
|
extern backend_interface_t backend_interface;
|
33
36
|
#define __BACKEND__ (backend_interface)
|
34
37
|
|
data/ext/polyphony/thread.c
CHANGED
@@ -4,7 +4,6 @@ ID ID_deactivate_all_watchers_post_fork;
|
|
4
4
|
ID ID_ivar_backend;
|
5
5
|
ID ID_ivar_join_wait_queue;
|
6
6
|
ID ID_ivar_main_fiber;
|
7
|
-
ID ID_ivar_result;
|
8
7
|
ID ID_ivar_terminated;
|
9
8
|
ID ID_ivar_runqueue;
|
10
9
|
ID ID_stop;
|
@@ -116,7 +115,7 @@ VALUE Thread_switch_fiber(VALUE self) {
|
|
116
115
|
RB_GC_GUARD(next.fiber);
|
117
116
|
RB_GC_GUARD(next.value);
|
118
117
|
return (next.fiber == current_fiber) ?
|
119
|
-
next.value :
|
118
|
+
next.value : FIBER_TRANSFER(next.fiber, next.value);
|
120
119
|
}
|
121
120
|
|
122
121
|
VALUE Thread_reset_fiber_scheduling(VALUE self) {
|
@@ -162,7 +161,6 @@ void Init_Thread() {
|
|
162
161
|
ID_ivar_backend = rb_intern("@backend");
|
163
162
|
ID_ivar_join_wait_queue = rb_intern("@join_wait_queue");
|
164
163
|
ID_ivar_main_fiber = rb_intern("@main_fiber");
|
165
|
-
ID_ivar_result = rb_intern("@result");
|
166
164
|
ID_ivar_terminated = rb_intern("@terminated");
|
167
165
|
ID_ivar_runqueue = rb_intern("@runqueue");
|
168
166
|
ID_stop = rb_intern("stop");
|
@@ -20,15 +20,20 @@ module Polyphony
|
|
20
20
|
canceller = spin do
|
21
21
|
sleep interval
|
22
22
|
exception = cancel_exception(with_exception)
|
23
|
+
# we don't want the cancelling fiber caller location as part of the
|
24
|
+
# exception backtrace
|
25
|
+
exception.__raising_fiber__ = nil
|
23
26
|
fiber.schedule exception
|
24
27
|
end
|
25
28
|
block ? cancel_after_wrap_block(canceller, &block) : canceller
|
26
29
|
end
|
27
30
|
|
28
31
|
def cancel_exception(exception)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
+
case exception
|
33
|
+
when Class then exception.new
|
34
|
+
when Array then exception[0].new(exception[1])
|
35
|
+
else RuntimeError.new(exception)
|
36
|
+
end
|
32
37
|
end
|
33
38
|
|
34
39
|
def cancel_after_wrap_block(canceller, &block)
|
@@ -12,7 +12,7 @@ class ::Exception
|
|
12
12
|
attr_accessor :__disable_sanitized_backtrace__
|
13
13
|
end
|
14
14
|
|
15
|
-
attr_accessor :source_fiber
|
15
|
+
attr_accessor :source_fiber, :__raising_fiber__
|
16
16
|
|
17
17
|
alias_method :orig_initialize, :initialize
|
18
18
|
def initialize(*args)
|
@@ -22,8 +22,8 @@ class ::Exception
|
|
22
22
|
|
23
23
|
alias_method :orig_backtrace, :backtrace
|
24
24
|
def backtrace
|
25
|
-
unless @
|
26
|
-
@
|
25
|
+
unless @backtrace_called
|
26
|
+
@backtrace_called = true
|
27
27
|
return orig_backtrace
|
28
28
|
end
|
29
29
|
|
@@ -31,12 +31,10 @@ class ::Exception
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def sanitized_backtrace
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
sanitize(orig_backtrace)
|
39
|
-
end
|
34
|
+
return sanitize(orig_backtrace) unless @__raising_fiber__
|
35
|
+
|
36
|
+
backtrace = orig_backtrace || []
|
37
|
+
sanitize(backtrace + @__raising_fiber__.caller)
|
40
38
|
end
|
41
39
|
|
42
40
|
POLYPHONY_DIR = File.expand_path(File.join(__dir__, '..'))
|
@@ -164,11 +162,7 @@ end
|
|
164
162
|
|
165
163
|
# Override Timeout to use cancel scope
|
166
164
|
module ::Timeout
|
167
|
-
def self.timeout(sec, klass =
|
168
|
-
cancel_after(sec, &block)
|
169
|
-
rescue Polyphony::Cancel => e
|
170
|
-
error = klass ? klass.new(message) : ::Timeout::Error.new
|
171
|
-
error.set_backtrace(e.backtrace)
|
172
|
-
raise error
|
165
|
+
def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
|
166
|
+
cancel_after(sec, with_exception: [klass, message], &block)
|
173
167
|
end
|
174
168
|
end
|
data/lib/polyphony/version.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/stress.rb
CHANGED
data/test/test_backend.rb
CHANGED
@@ -125,4 +125,15 @@ class BackendTest < MiniTest::Test
|
|
125
125
|
snooze
|
126
126
|
server&.close
|
127
127
|
end
|
128
|
+
|
129
|
+
def test_timer_loop
|
130
|
+
i = 0
|
131
|
+
f = spin do
|
132
|
+
@backend.timer_loop(0.01) { i += 1 }
|
133
|
+
end
|
134
|
+
@backend.sleep(0.05)
|
135
|
+
f.stop
|
136
|
+
f.await # TODO: check why this test sometimes segfaults if we don't a<wait fiber
|
137
|
+
assert_in_range 4..6, i
|
138
|
+
end
|
128
139
|
end
|
data/test/test_global_api.rb
CHANGED
@@ -202,6 +202,19 @@ class CancelAfterTest < MiniTest::Test
|
|
202
202
|
end
|
203
203
|
end
|
204
204
|
|
205
|
+
begin
|
206
|
+
err = nil
|
207
|
+
cancel_after(0.01, with_exception: [CustomException, 'custom message']) do
|
208
|
+
sleep 1
|
209
|
+
:foo
|
210
|
+
end
|
211
|
+
rescue Exception => err
|
212
|
+
ensure
|
213
|
+
assert_kind_of CustomException, err
|
214
|
+
assert_equal 'custom message', err.message
|
215
|
+
end
|
216
|
+
|
217
|
+
|
205
218
|
begin
|
206
219
|
e = nil
|
207
220
|
cancel_after(0.01, with_exception: 'foo') do
|
data/test/test_queue.rb
CHANGED
data/test/test_socket.rb
CHANGED
@@ -40,12 +40,12 @@ class HTTPClientTest < MiniTest::Test
|
|
40
40
|
def test_http
|
41
41
|
res = HTTParty.get('http://worldtimeapi.org/api/timezone/Europe/Paris')
|
42
42
|
response = JSON.load(res.body)
|
43
|
-
assert_equal "
|
43
|
+
assert_equal "CET", response['abbreviation']
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_https
|
47
47
|
res = HTTParty.get('https://worldtimeapi.org/api/timezone/Europe/Paris')
|
48
48
|
response = JSON.load(res.body)
|
49
|
-
assert_equal "
|
49
|
+
assert_equal "CET", response['abbreviation']
|
50
50
|
end
|
51
51
|
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.46.
|
4
|
+
version: 0.46.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: 2020-
|
11
|
+
date: 2020-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -290,6 +290,7 @@ files:
|
|
290
290
|
- TODO.md
|
291
291
|
- bin/polyphony-debug
|
292
292
|
- bin/stress.rb
|
293
|
+
- bin/test
|
293
294
|
- docs/_config.yml
|
294
295
|
- docs/_includes/head.html
|
295
296
|
- docs/_includes/title.html
|