polyphony 0.73.1 → 0.74
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 +13 -10
- data/.github/workflows/test_io_uring.yml +32 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +10 -7
- data/bin/pdbg +0 -0
- data/bin/polyphony-debug +0 -0
- data/bin/stress.rb +0 -0
- data/bin/test +0 -0
- data/ext/polyphony/backend_common.c +75 -11
- data/ext/polyphony/backend_common.h +7 -0
- data/ext/polyphony/backend_io_uring.c +226 -106
- data/ext/polyphony/backend_io_uring_context.c +1 -0
- data/ext/polyphony/backend_io_uring_context.h +2 -1
- data/ext/polyphony/backend_libev.c +7 -9
- data/ext/polyphony/event.c +5 -2
- data/ext/polyphony/polyphony.c +10 -1
- data/ext/polyphony/polyphony.h +2 -0
- data/ext/polyphony/queue.c +10 -5
- data/ext/polyphony/runqueue_ring_buffer.c +3 -1
- data/ext/polyphony/socket_extensions.c +5 -2
- data/lib/polyphony/extensions/fiber.rb +58 -0
- data/lib/polyphony/extensions/socket.rb +17 -5
- data/lib/polyphony/extensions/thread.rb +9 -3
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -1
- data/test/test_backend.rb +3 -5
- data/test/test_global_api.rb +10 -14
- data/test/test_io.rb +2 -2
- data/test/test_kernel.rb +2 -2
- data/test/test_socket.rb +35 -2
- data/test/test_thread_pool.rb +1 -1
- data/test/test_throttler.rb +3 -3
- data/test/test_timer.rb +1 -1
- metadata +8 -7
@@ -697,10 +697,13 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
697
697
|
Backend_t *backend;
|
698
698
|
struct libev_io watcher;
|
699
699
|
rb_io_t *fptr;
|
700
|
-
struct
|
701
|
-
|
700
|
+
struct sockaddr *ai_addr;
|
701
|
+
int ai_addrlen;
|
702
702
|
VALUE switchpoint_result = Qnil;
|
703
703
|
VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
|
704
|
+
|
705
|
+
ai_addrlen = backend_getaddrinfo(host, port, &ai_addr);
|
706
|
+
|
704
707
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
705
708
|
|
706
709
|
GetBackend(self, backend);
|
@@ -708,12 +711,8 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
708
711
|
io_verify_blocking_mode(fptr, sock, Qfalse);
|
709
712
|
watcher.fiber = Qnil;
|
710
713
|
|
711
|
-
addr.sin_family = AF_INET;
|
712
|
-
addr.sin_addr.s_addr = inet_addr(host_buf);
|
713
|
-
addr.sin_port = htons(NUM2INT(port));
|
714
|
-
|
715
714
|
backend->base.op_count++;
|
716
|
-
int result = connect(fptr->fd,
|
715
|
+
int result = connect(fptr->fd, ai_addr, ai_addrlen);
|
717
716
|
if (result < 0) {
|
718
717
|
int e = errno;
|
719
718
|
if (e != EINPROGRESS) rb_syserr_fail(e, strerror(e));
|
@@ -1156,7 +1155,6 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
|
|
1156
1155
|
while (1) {
|
1157
1156
|
uint64_t now_ns = current_time_ns();
|
1158
1157
|
if (next_time_ns == 0) next_time_ns = now_ns + interval_ns;
|
1159
|
-
double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
|
1160
1158
|
|
1161
1159
|
if (next_time_ns > now_ns) {
|
1162
1160
|
double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
|
@@ -1370,7 +1368,7 @@ inline VALUE Backend_run_idle_tasks(VALUE self) {
|
|
1370
1368
|
return self;
|
1371
1369
|
}
|
1372
1370
|
|
1373
|
-
inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct libev_rw_io *watcher, VALUE *result) {
|
1371
|
+
static inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct libev_rw_io *watcher, VALUE *result) {
|
1374
1372
|
char *buf = RSTRING_PTR(str);
|
1375
1373
|
int len = RSTRING_LEN(str);
|
1376
1374
|
int left = len;
|
data/ext/polyphony/event.c
CHANGED
@@ -59,14 +59,17 @@ VALUE Event_signal(int argc, VALUE *argv, VALUE self) {
|
|
59
59
|
|
60
60
|
VALUE Event_await(VALUE self) {
|
61
61
|
Event_t *event;
|
62
|
+
VALUE switchpoint_result;
|
63
|
+
VALUE backend;
|
64
|
+
|
62
65
|
GetEvent(self, event);
|
63
66
|
|
64
67
|
if (event->waiting_fiber != Qnil)
|
65
68
|
rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
|
66
69
|
|
67
|
-
|
70
|
+
backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
68
71
|
event->waiting_fiber = rb_fiber_current();
|
69
|
-
|
72
|
+
switchpoint_result = Backend_wait_event(backend, Qnil);
|
70
73
|
event->waiting_fiber = Qnil;
|
71
74
|
|
72
75
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
data/ext/polyphony/polyphony.c
CHANGED
@@ -9,16 +9,18 @@ ID ID_clear;
|
|
9
9
|
ID ID_each;
|
10
10
|
ID ID_inspect;
|
11
11
|
ID ID_invoke;
|
12
|
-
ID ID_new;
|
13
12
|
ID ID_ivar_blocking_mode;
|
14
13
|
ID ID_ivar_io;
|
15
14
|
ID ID_ivar_parked;
|
16
15
|
ID ID_ivar_runnable;
|
17
16
|
ID ID_ivar_running;
|
18
17
|
ID ID_ivar_thread;
|
18
|
+
ID ID_new;
|
19
|
+
ID ID_raise;
|
19
20
|
ID ID_size;
|
20
21
|
ID ID_signal;
|
21
22
|
ID ID_switch_fiber;
|
23
|
+
ID ID_to_s;
|
22
24
|
ID ID_transfer;
|
23
25
|
ID ID_R;
|
24
26
|
ID ID_W;
|
@@ -123,6 +125,10 @@ VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
|
|
123
125
|
return Backend_write_m(argc, argv, BACKEND());
|
124
126
|
}
|
125
127
|
|
128
|
+
VALUE Polyphony_backend_close(VALUE self, VALUE io) {
|
129
|
+
return Backend_close(BACKEND(), io);
|
130
|
+
}
|
131
|
+
|
126
132
|
void Init_Polyphony() {
|
127
133
|
mPolyphony = rb_define_module("Polyphony");
|
128
134
|
|
@@ -147,6 +153,7 @@ void Init_Polyphony() {
|
|
147
153
|
rb_define_singleton_method(mPolyphony, "backend_wait_io", Polyphony_backend_wait_io, 2);
|
148
154
|
rb_define_singleton_method(mPolyphony, "backend_waitpid", Polyphony_backend_waitpid, 1);
|
149
155
|
rb_define_singleton_method(mPolyphony, "backend_write", Polyphony_backend_write, -1);
|
156
|
+
rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
|
150
157
|
|
151
158
|
rb_define_global_function("snooze", Polyphony_snooze, 0);
|
152
159
|
rb_define_global_function("suspend", Polyphony_suspend, 0);
|
@@ -166,8 +173,10 @@ void Init_Polyphony() {
|
|
166
173
|
ID_ivar_running = rb_intern("@running");
|
167
174
|
ID_ivar_thread = rb_intern("@thread");
|
168
175
|
ID_new = rb_intern("new");
|
176
|
+
ID_raise = rb_intern("raise");
|
169
177
|
ID_signal = rb_intern("signal");
|
170
178
|
ID_size = rb_intern("size");
|
171
179
|
ID_switch_fiber = rb_intern("switch_fiber");
|
180
|
+
ID_to_s = rb_intern("to_s");
|
172
181
|
ID_transfer = rb_intern("transfer");
|
173
182
|
}
|
data/ext/polyphony/polyphony.h
CHANGED
@@ -57,6 +57,7 @@ extern ID ID_raise;
|
|
57
57
|
extern ID ID_signal;
|
58
58
|
extern ID ID_size;
|
59
59
|
extern ID ID_switch_fiber;
|
60
|
+
extern ID ID_to_s;
|
60
61
|
extern ID ID_transfer;
|
61
62
|
|
62
63
|
extern VALUE SYM_fiber_create;
|
@@ -112,6 +113,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise);
|
|
112
113
|
VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write);
|
113
114
|
VALUE Backend_waitpid(VALUE self, VALUE pid);
|
114
115
|
VALUE Backend_write_m(int argc, VALUE *argv, VALUE self);
|
116
|
+
VALUE Backend_close(VALUE self, VALUE io);
|
115
117
|
|
116
118
|
VALUE Backend_poll(VALUE self, VALUE blocking);
|
117
119
|
VALUE Backend_wait_event(VALUE self, VALUE raise_on_exception);
|
data/ext/polyphony/queue.c
CHANGED
@@ -121,24 +121,27 @@ VALUE Queue_unshift(VALUE self, VALUE value) {
|
|
121
121
|
|
122
122
|
VALUE Queue_shift(VALUE self) {
|
123
123
|
Queue_t *queue;
|
124
|
-
GetQueue(self, queue);
|
125
|
-
|
126
124
|
VALUE fiber = rb_fiber_current();
|
127
125
|
VALUE thread = rb_thread_current();
|
128
126
|
VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
|
127
|
+
VALUE value;
|
128
|
+
|
129
|
+
GetQueue(self, queue);
|
129
130
|
|
130
131
|
while (1) {
|
132
|
+
VALUE switchpoint_result;
|
133
|
+
|
131
134
|
if (queue->values.count) Fiber_make_runnable(fiber, Qnil);
|
132
135
|
|
133
136
|
ring_buffer_push(&queue->shift_queue, fiber);
|
134
|
-
|
137
|
+
switchpoint_result = Backend_wait_event(backend, Qnil);
|
135
138
|
ring_buffer_delete(&queue->shift_queue, fiber);
|
136
139
|
|
137
140
|
RAISE_IF_EXCEPTION(switchpoint_result);
|
138
141
|
RB_GC_GUARD(switchpoint_result);
|
139
142
|
if (queue->values.count) break;
|
140
143
|
}
|
141
|
-
|
144
|
+
value = ring_buffer_shift(&queue->values);
|
142
145
|
if ((queue->capacity) && (queue->capacity > queue->values.count))
|
143
146
|
queue_schedule_first_blocked_fiber(&queue->push_queue);
|
144
147
|
RB_GC_GUARD(value);
|
@@ -206,9 +209,11 @@ VALUE Queue_shift_each(VALUE self) {
|
|
206
209
|
|
207
210
|
VALUE Queue_shift_all(VALUE self) {
|
208
211
|
Queue_t *queue;
|
212
|
+
VALUE result;
|
213
|
+
|
209
214
|
GetQueue(self, queue);
|
210
215
|
|
211
|
-
|
216
|
+
result = ring_buffer_shift_all(&queue->values);
|
212
217
|
if (queue->capacity) queue_schedule_blocked_fibers_to_capacity(queue);
|
213
218
|
return result;
|
214
219
|
}
|
@@ -24,9 +24,11 @@ inline void runqueue_ring_buffer_clear(runqueue_ring_buffer *buffer) {
|
|
24
24
|
static runqueue_entry nil_runqueue_entry = {(Qnil), (Qnil)};
|
25
25
|
|
26
26
|
inline runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
|
27
|
+
runqueue_entry value;
|
28
|
+
|
27
29
|
if (buffer->count == 0) return nil_runqueue_entry;
|
28
30
|
|
29
|
-
|
31
|
+
value = buffer->entries[buffer->head];
|
30
32
|
buffer->head = (buffer->head + 1) % buffer->size;
|
31
33
|
buffer->count--;
|
32
34
|
return value;
|
@@ -17,10 +17,13 @@ VALUE Socket_double_chevron(VALUE self, VALUE msg) {
|
|
17
17
|
}
|
18
18
|
|
19
19
|
void Init_SocketExtensions() {
|
20
|
+
VALUE cSocket;
|
21
|
+
VALUE cTCPSocket;
|
22
|
+
|
20
23
|
rb_require("socket");
|
21
24
|
|
22
|
-
|
23
|
-
|
25
|
+
cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
|
26
|
+
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
24
27
|
|
25
28
|
rb_define_method(cSocket, "send", Socket_send, 2);
|
26
29
|
rb_define_method(cTCPSocket, "send", Socket_send, 2);
|
@@ -5,17 +5,40 @@ require_relative '../core/exceptions'
|
|
5
5
|
module Polyphony
|
6
6
|
# Fiber control API
|
7
7
|
module FiberControl
|
8
|
+
# Returns the fiber's monitoring mailbox queue, used for receiving fiber
|
9
|
+
# monitoring messages.
|
10
|
+
#
|
11
|
+
# @return [Polyphony::Queue] Monitoring mailbox queue
|
8
12
|
def monitor_mailbox
|
9
13
|
@monitor_mailbox ||= Polyphony::Queue.new
|
10
14
|
end
|
11
15
|
|
16
|
+
# call-seq:
|
17
|
+
# fiber.stop(value = nil) -> fiber
|
18
|
+
# Fiber.interrupt(value = nil) -> fiber
|
19
|
+
#
|
20
|
+
# Stops the fiber by raising a Polyphony::MoveOn exception. The given value
|
21
|
+
# will become the fiber's return value.
|
22
|
+
#
|
23
|
+
# @param value [any] Fiber's eventual return value
|
24
|
+
# @return [Fiber] fiber
|
12
25
|
def interrupt(value = nil)
|
13
26
|
return if @running == false
|
14
27
|
|
15
28
|
schedule Polyphony::MoveOn.new(value)
|
29
|
+
self
|
16
30
|
end
|
17
31
|
alias_method :stop, :interrupt
|
18
32
|
|
33
|
+
# call-seq:
|
34
|
+
# fiber.reset(value = nil) -> fiber
|
35
|
+
# fiber.restart(value = nil) -> fiber
|
36
|
+
#
|
37
|
+
# Restarts the fiber, with the given value serving as the first value passed
|
38
|
+
# to the fiber's block.
|
39
|
+
#
|
40
|
+
# @param value [any] value passed to fiber block
|
41
|
+
# @return [Fiber] restarted fiber
|
19
42
|
def restart(value = nil)
|
20
43
|
raise "Can't restart main fiber" if @main
|
21
44
|
|
@@ -31,32 +54,58 @@ module Polyphony
|
|
31
54
|
end
|
32
55
|
alias_method :reset, :restart
|
33
56
|
|
57
|
+
# Stops a fiber by raising a Polyphony::Cancel exception.
|
58
|
+
#
|
59
|
+
# @return [Fiber] fiber
|
34
60
|
def cancel
|
35
61
|
return if @running == false
|
36
62
|
|
37
63
|
schedule Polyphony::Cancel.new
|
64
|
+
self
|
38
65
|
end
|
39
66
|
|
67
|
+
# Sets the graceful shutdown flag for the fiber.
|
68
|
+
#
|
69
|
+
# @param graceful [bool] Whether or not to perform a graceful shutdown
|
40
70
|
def graceful_shutdown=(graceful)
|
41
71
|
@graceful_shutdown = graceful
|
42
72
|
end
|
43
73
|
|
74
|
+
# Returns the graceful shutdown flag for the fiber.
|
75
|
+
#
|
76
|
+
# @return [bool]
|
44
77
|
def graceful_shutdown?
|
45
78
|
@graceful_shutdown
|
46
79
|
end
|
47
80
|
|
81
|
+
# Terminates the fiber, optionally setting the graceful shutdown flag.
|
82
|
+
#
|
83
|
+
# @param graceful [bool] Whether to perform a graceful shutdown
|
84
|
+
# @return [Fiber]
|
48
85
|
def terminate(graceful = false)
|
49
86
|
return if @running == false
|
50
87
|
|
51
88
|
@graceful_shutdown = graceful
|
52
89
|
schedule Polyphony::Terminate.new
|
90
|
+
self
|
53
91
|
end
|
54
92
|
|
93
|
+
# call-seq:
|
94
|
+
# fiber.raise(message) -> fiber
|
95
|
+
# fiber.raise(exception_class) -> fiber
|
96
|
+
# fiber.raise(exception_class, exception_message) -> fiber
|
97
|
+
# fiber.raise(exception) -> fiber
|
98
|
+
#
|
99
|
+
# Raises an exception in the context of the fiber.
|
100
|
+
#
|
101
|
+
# @return [Fiber]
|
55
102
|
def raise(*args)
|
56
103
|
error = error_from_raise_args(args)
|
57
104
|
schedule(error)
|
105
|
+
self
|
58
106
|
end
|
59
107
|
|
108
|
+
# :no-doc:
|
60
109
|
def error_from_raise_args(args)
|
61
110
|
case (arg = args.shift)
|
62
111
|
when String then RuntimeError.new(arg)
|
@@ -125,6 +174,9 @@ module Polyphony
|
|
125
174
|
# return values for all terminated fibers. If any of the awaited fibers
|
126
175
|
# terminates with an uncaught exception, `Fiber.await` will await all the
|
127
176
|
# other fibers to terminate, then reraise the exception.
|
177
|
+
#
|
178
|
+
# @param *fibers [Array<Fiber>] fibers to wait for
|
179
|
+
# @return [Array<any>] return values of given fibers
|
128
180
|
def await(*fibers)
|
129
181
|
return [] if fibers.empty?
|
130
182
|
|
@@ -158,6 +210,12 @@ module Polyphony
|
|
158
210
|
end
|
159
211
|
alias_method :join, :await
|
160
212
|
|
213
|
+
# Waits for at least one of the given fibers to terminate, returning an
|
214
|
+
# array containing the first terminated fiber and its return value. If an
|
215
|
+
# exception occurs in one of the given fibers, it will be reraised.
|
216
|
+
#
|
217
|
+
# @param *fibers [Array<Fiber>] Fibers to wait for
|
218
|
+
# @return [Array] Array containing the first terminated fiber and its return value
|
161
219
|
def select(*fibers)
|
162
220
|
return nil if fibers.empty?
|
163
221
|
|
@@ -31,7 +31,7 @@ class ::Socket
|
|
31
31
|
alias_method :orig_read, :read
|
32
32
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
33
33
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
34
|
-
return Polyphony.backend_recv(self,
|
34
|
+
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
35
35
|
|
36
36
|
buf = +''
|
37
37
|
len = buf.bytesize
|
@@ -120,8 +120,16 @@ class ::TCPSocket
|
|
120
120
|
|
121
121
|
attr_reader :io
|
122
122
|
|
123
|
+
def self.open(*args)
|
124
|
+
new(*args)
|
125
|
+
end
|
126
|
+
|
127
|
+
def address_family(host)
|
128
|
+
host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
|
129
|
+
end
|
130
|
+
|
123
131
|
def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
|
124
|
-
@io = Socket.new
|
132
|
+
@io = Socket.new address_family(remote_host), Socket::SOCK_STREAM
|
125
133
|
if local_host && local_port
|
126
134
|
addr = Addrinfo.tcp(local_host, local_port)
|
127
135
|
@io.bind(addr)
|
@@ -167,7 +175,7 @@ class ::TCPSocket
|
|
167
175
|
alias_method :orig_read, :read
|
168
176
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
169
177
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
170
|
-
return Polyphony.backend_recv(self,
|
178
|
+
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
171
179
|
|
172
180
|
buf = +''
|
173
181
|
len = buf.bytesize
|
@@ -223,8 +231,12 @@ end
|
|
223
231
|
|
224
232
|
# Override stock TCPServer code by encapsulating a Socket instance.
|
225
233
|
class ::TCPServer
|
234
|
+
def address_family(host)
|
235
|
+
host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
|
236
|
+
end
|
237
|
+
|
226
238
|
def initialize(hostname = nil, port = 0)
|
227
|
-
@io = Socket.new
|
239
|
+
@io = Socket.new address_family(hostname), Socket::SOCK_STREAM
|
228
240
|
@io.bind(Addrinfo.tcp(hostname, port))
|
229
241
|
@io.listen(0)
|
230
242
|
end
|
@@ -259,7 +271,7 @@ class ::UNIXSocket
|
|
259
271
|
alias_method :orig_read, :read
|
260
272
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
261
273
|
return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
|
262
|
-
return Polyphony.backend_recv(self,
|
274
|
+
return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
|
263
275
|
|
264
276
|
buf = +''
|
265
277
|
len = buf.bytesize
|
@@ -18,14 +18,20 @@ class ::Thread
|
|
18
18
|
def execute
|
19
19
|
# backend must be created in the context of the new thread, therefore it
|
20
20
|
# cannot be created in Thread#initialize
|
21
|
-
|
21
|
+
raise_error = false
|
22
|
+
begin
|
23
|
+
@backend = Polyphony::Backend.new
|
24
|
+
rescue Exception => e
|
25
|
+
raise_error = true
|
26
|
+
raise e
|
27
|
+
end
|
22
28
|
setup
|
23
29
|
@ready = true
|
24
30
|
result = @block.(*@args)
|
25
31
|
rescue Polyphony::MoveOn, Polyphony::Terminate => e
|
26
32
|
result = e.value
|
27
33
|
rescue Exception => e
|
28
|
-
result = e
|
34
|
+
raise_error ? (raise e) : (result = e)
|
29
35
|
ensure
|
30
36
|
@ready = true
|
31
37
|
finalize(result)
|
@@ -48,7 +54,7 @@ class ::Thread
|
|
48
54
|
@result = result
|
49
55
|
signal_waiters(result)
|
50
56
|
end
|
51
|
-
@backend
|
57
|
+
@backend&.finalize
|
52
58
|
end
|
53
59
|
|
54
60
|
def signal_waiters(result)
|
data/lib/polyphony/version.rb
CHANGED
data/lib/polyphony.rb
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
require 'fiber'
|
4
4
|
require_relative './polyphony_ext'
|
5
|
-
require_relative './polyphony/extensions'
|
5
|
+
require_relative './polyphony/extensions/thread'
|
6
6
|
|
7
7
|
Thread.current.setup_fiber_scheduling
|
8
8
|
Thread.current.backend = Polyphony::Backend.new
|
9
9
|
|
10
|
+
require_relative './polyphony/extensions'
|
10
11
|
require_relative './polyphony/core/exceptions'
|
11
12
|
require_relative './polyphony/core/global_api'
|
12
13
|
require_relative './polyphony/core/resource_pool'
|
data/test/test_backend.rb
CHANGED
@@ -243,16 +243,14 @@ class BackendTest < MiniTest::Test
|
|
243
243
|
end
|
244
244
|
|
245
245
|
def test_timer_loop
|
246
|
-
|
247
|
-
|
248
|
-
i = 0
|
246
|
+
counter = 0
|
249
247
|
f = spin do
|
250
|
-
@backend.timer_loop(0.01) {
|
248
|
+
@backend.timer_loop(0.01) { counter += 1 }
|
251
249
|
end
|
252
250
|
@backend.sleep(0.05)
|
253
251
|
f.stop
|
254
252
|
f.await # TODO: check why this test sometimes segfaults if we don't a<wait fiber
|
255
|
-
assert_in_range 4..6,
|
253
|
+
assert_in_range 4..6, counter if IS_LINUX
|
256
254
|
end
|
257
255
|
|
258
256
|
class MyTimeoutException < Exception
|
data/test/test_global_api.rb
CHANGED
@@ -162,7 +162,7 @@ class MoveOnAfterTest < MiniTest::Test
|
|
162
162
|
end
|
163
163
|
t1 = Time.now
|
164
164
|
assert_equal 1, o
|
165
|
-
assert_in_range 0.008..0.015, t1 - t0
|
165
|
+
assert_in_range 0.008..0.015, t1 - t0 if IS_LINUX
|
166
166
|
|
167
167
|
t0 = Time.now
|
168
168
|
o = move_on_after(0.05, with_value: 1) do
|
@@ -172,7 +172,7 @@ class MoveOnAfterTest < MiniTest::Test
|
|
172
172
|
end
|
173
173
|
t1 = Time.now
|
174
174
|
assert_equal 2, o
|
175
|
-
assert_in_range 0.008..0.013, t1 - t0
|
175
|
+
assert_in_range 0.008..0.013, t1 - t0 if IS_LINUX
|
176
176
|
end
|
177
177
|
end
|
178
178
|
|
@@ -297,7 +297,7 @@ class SpinLoopTest < MiniTest::Test
|
|
297
297
|
f = spin_loop(rate: 100) { buffer << (counter += 1) }
|
298
298
|
sleep 0.02
|
299
299
|
f.stop
|
300
|
-
assert_in_range 1..3, counter
|
300
|
+
assert_in_range 1..3, counter if IS_LINUX
|
301
301
|
end
|
302
302
|
|
303
303
|
def test_spin_loop_with_interval
|
@@ -307,7 +307,7 @@ class SpinLoopTest < MiniTest::Test
|
|
307
307
|
f = spin_loop(interval: 0.01) { buffer << (counter += 1) }
|
308
308
|
sleep 0.02
|
309
309
|
f.stop
|
310
|
-
assert_in_range 1..3, counter
|
310
|
+
assert_in_range 1..3, counter if IS_LINUX
|
311
311
|
end
|
312
312
|
|
313
313
|
def test_spin_loop_break
|
@@ -386,10 +386,10 @@ class ThrottledLoopTest < MiniTest::Test
|
|
386
386
|
counter = 0
|
387
387
|
t0 = Time.now
|
388
388
|
f = spin do
|
389
|
-
throttled_loop(
|
389
|
+
throttled_loop(10) { buffer << (counter += 1) }
|
390
390
|
end
|
391
|
-
sleep 0.
|
392
|
-
assert_in_range 2..4, counter
|
391
|
+
sleep 0.3
|
392
|
+
assert_in_range 2..4, counter if IS_LINUX
|
393
393
|
end
|
394
394
|
|
395
395
|
def test_throttled_loop_with_count
|
@@ -417,8 +417,6 @@ class GlobalAPIEtcTest < MiniTest::Test
|
|
417
417
|
end
|
418
418
|
|
419
419
|
def test_every
|
420
|
-
skip unless IS_LINUX
|
421
|
-
|
422
420
|
buffer = []
|
423
421
|
t0 = Time.now
|
424
422
|
f = spin do
|
@@ -426,12 +424,10 @@ class GlobalAPIEtcTest < MiniTest::Test
|
|
426
424
|
end
|
427
425
|
sleep 0.05
|
428
426
|
f.stop
|
429
|
-
assert_in_range 4..6, buffer.size
|
427
|
+
assert_in_range 4..6, buffer.size if IS_LINUX
|
430
428
|
end
|
431
429
|
|
432
430
|
def test_every_with_slow_op
|
433
|
-
skip unless IS_LINUX
|
434
|
-
|
435
431
|
buffer = []
|
436
432
|
t0 = Time.now
|
437
433
|
f = spin do
|
@@ -439,14 +435,14 @@ class GlobalAPIEtcTest < MiniTest::Test
|
|
439
435
|
end
|
440
436
|
sleep 0.15
|
441
437
|
f.stop
|
442
|
-
assert_in_range 2..3, buffer.size
|
438
|
+
assert_in_range 2..3, buffer.size if IS_LINUX
|
443
439
|
end
|
444
440
|
|
445
441
|
def test_sleep
|
446
442
|
t0 = Time.now
|
447
443
|
sleep 0.1
|
448
444
|
elapsed = Time.now - t0
|
449
|
-
|
445
|
+
assert_in_range 0.05..0.15, elapsed if IS_LINUX
|
450
446
|
|
451
447
|
f = spin { sleep }
|
452
448
|
snooze
|
data/test/test_io.rb
CHANGED
@@ -354,9 +354,9 @@ class IOClassMethodsTest < MiniTest::Test
|
|
354
354
|
skip unless IS_LINUX
|
355
355
|
|
356
356
|
counter = 0
|
357
|
-
timer = spin { throttled_loop(
|
357
|
+
timer = spin { throttled_loop(20) { counter += 1 } }
|
358
358
|
|
359
|
-
IO.popen('sleep 0.
|
359
|
+
IO.popen('sleep 0.5') { |io| io.read(8192) }
|
360
360
|
assert(counter >= 5)
|
361
361
|
|
362
362
|
result = nil
|
data/test/test_kernel.rb
CHANGED
@@ -51,8 +51,8 @@ class KernelTest < MiniTest::Test
|
|
51
51
|
counter = 0
|
52
52
|
timer = spin { throttled_loop(200) { counter += 1 } }
|
53
53
|
|
54
|
-
`sleep 0.
|
55
|
-
|
54
|
+
`sleep 0.05`
|
55
|
+
assert_in_range 8..14, counter if IS_LINUX
|
56
56
|
|
57
57
|
result = `echo "hello"`
|
58
58
|
assert_equal "hello\n", result
|
data/test/test_socket.rb
CHANGED
@@ -9,9 +9,9 @@ class SocketTest < MiniTest::Test
|
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
12
|
-
def start_tcp_server_on_random_port
|
12
|
+
def start_tcp_server_on_random_port(host = '127.0.0.1')
|
13
13
|
port = rand(1100..60000)
|
14
|
-
server = TCPServer.new(
|
14
|
+
server = TCPServer.new(host, port)
|
15
15
|
[port, server]
|
16
16
|
rescue Errno::EADDRINUSE
|
17
17
|
retry
|
@@ -40,6 +40,39 @@ class SocketTest < MiniTest::Test
|
|
40
40
|
server&.close
|
41
41
|
end
|
42
42
|
|
43
|
+
def test_tcpsocket_open_with_hostname
|
44
|
+
client = TCPSocket.open('google.com', 80)
|
45
|
+
client.write("GET / HTTP/1.0\r\nHost: google.com\r\n\r\n")
|
46
|
+
result = nil
|
47
|
+
move_on_after(1) {
|
48
|
+
result = client.read
|
49
|
+
}
|
50
|
+
assert result =~ /HTTP\/1.0 301 Moved Permanently/
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_tcp_ipv6
|
54
|
+
port, server = start_tcp_server_on_random_port('::1')
|
55
|
+
server_fiber = spin do
|
56
|
+
while (socket = server.accept)
|
57
|
+
spin do
|
58
|
+
while (data = socket.gets(8192))
|
59
|
+
socket << data
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
snooze
|
66
|
+
client = TCPSocket.new('::1', port)
|
67
|
+
client.write("1234\n")
|
68
|
+
assert_equal "1234\n", client.recv(8192)
|
69
|
+
client.close
|
70
|
+
ensure
|
71
|
+
server_fiber&.stop
|
72
|
+
server_fiber&.await
|
73
|
+
server&.close
|
74
|
+
end
|
75
|
+
|
43
76
|
def test_read
|
44
77
|
port, server = start_tcp_server_on_random_port
|
45
78
|
server_fiber = spin do
|
data/test/test_thread_pool.rb
CHANGED