polyphony 1.0.2 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/.github/workflows/test_io_uring.yml +1 -1
- data/.yardopts +1 -0
- data/CHANGELOG.md +9 -0
- data/README.md +1 -0
- data/TODO.md +3 -13
- data/docs/advanced-io.md +313 -0
- data/docs/cheat-sheet.md +2 -2
- data/docs/readme.md +1 -0
- data/examples/core/rpc_benchmark.rb +14 -14
- data/examples/core/stream_mockup.rb +68 -0
- data/examples/core/throttled_loop_inside_move_on_after.rb +13 -0
- data/ext/polyphony/backend_common.c +3 -5
- data/ext/polyphony/backend_common.h +10 -1
- data/ext/polyphony/backend_io_uring.c +6 -6
- data/ext/polyphony/backend_libev.c +5 -5
- data/ext/polyphony/extconf.rb +6 -0
- data/ext/polyphony/fiber.c +21 -1
- data/lib/polyphony/extensions/io.rb +74 -74
- data/lib/polyphony/extensions/object.rb +6 -0
- data/lib/polyphony/extensions/socket.rb +9 -9
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -1
- data/test/stress.rb +1 -1
- data/test/test_fiber.rb +45 -1
- data/test/test_io.rb +46 -0
- data/test/test_process_supervision.rb +1 -1
- data/test/test_resource_pool.rb +1 -1
- data/test/test_scenarios.rb +38 -0
- data/test/test_socket.rb +0 -1
- data/test/test_thread_pool.rb +4 -2
- data/test/test_timer.rb +2 -2
- metadata +7 -3
@@ -277,10 +277,10 @@ static inline int fd_from_io(VALUE io, rb_io_t **fptr, int write_mode, int recti
|
|
277
277
|
if (underlying_io != Qnil) io = underlying_io;
|
278
278
|
|
279
279
|
GetOpenFile(io, *fptr);
|
280
|
-
|
280
|
+
int fd = rb_io_descriptor(io);
|
281
|
+
io_verify_blocking_mode(io, fd, Qfalse);
|
281
282
|
if (rectify_file_pos) rectify_io_file_pos(*fptr);
|
282
|
-
|
283
|
-
return (*fptr)->fd;
|
283
|
+
return fd;
|
284
284
|
}
|
285
285
|
}
|
286
286
|
|
@@ -681,7 +681,7 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
681
681
|
fp->fd = fd;
|
682
682
|
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
683
683
|
rb_io_ascii8bit_binmode(socket);
|
684
|
-
io_verify_blocking_mode(
|
684
|
+
io_verify_blocking_mode(socket, fd, Qfalse);
|
685
685
|
rb_io_synchronized(fp);
|
686
686
|
|
687
687
|
// if (rsock_do_not_reverse_lookup) {
|
@@ -736,7 +736,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
|
|
736
736
|
fp->fd = fd;
|
737
737
|
fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
|
738
738
|
rb_io_ascii8bit_binmode(socket);
|
739
|
-
io_verify_blocking_mode(
|
739
|
+
io_verify_blocking_mode(socket, fd, Qfalse);
|
740
740
|
rb_io_synchronized(fp);
|
741
741
|
|
742
742
|
rb_yield(socket);
|
data/ext/polyphony/extconf.rb
CHANGED
data/ext/polyphony/fiber.c
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
#include <stdnoreturn.h>
|
1
2
|
#include "polyphony.h"
|
2
3
|
|
3
4
|
ID ID_ivar_auto_watcher;
|
@@ -129,7 +130,7 @@ VALUE Fiber_send(VALUE self, VALUE msg) {
|
|
129
130
|
return self;
|
130
131
|
}
|
131
132
|
|
132
|
-
/*
|
133
|
+
/* Receives a message from the fiber's mailbox. If no message is available,
|
133
134
|
* waits for a message to be sent to it.
|
134
135
|
*
|
135
136
|
* @return [any] received message
|
@@ -144,6 +145,24 @@ VALUE Fiber_receive(VALUE self) {
|
|
144
145
|
return Queue_shift(0, 0, mailbox);
|
145
146
|
}
|
146
147
|
|
148
|
+
/* Receives messages from the fiber's mailbox in an infinite loop.
|
149
|
+
*
|
150
|
+
*/
|
151
|
+
|
152
|
+
noreturn VALUE Fiber_receive_loop(VALUE self) {
|
153
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
154
|
+
if (mailbox == Qnil) {
|
155
|
+
mailbox = rb_funcall(cQueue, ID_new, 0);
|
156
|
+
rb_ivar_set(self, ID_ivar_mailbox, mailbox);
|
157
|
+
}
|
158
|
+
|
159
|
+
while (1) {
|
160
|
+
VALUE msg = Queue_shift(0, 0,mailbox);
|
161
|
+
rb_yield(msg);
|
162
|
+
RB_GC_GUARD(msg);
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
147
166
|
/* Returns the fiber's mailbox.
|
148
167
|
*
|
149
168
|
* @return [Queue]
|
@@ -201,6 +220,7 @@ void Init_Fiber(void) {
|
|
201
220
|
rb_define_method(cFiber, "<<", Fiber_send, 1);
|
202
221
|
rb_define_method(cFiber, "send", Fiber_send, 1);
|
203
222
|
rb_define_method(cFiber, "receive", Fiber_receive, 0);
|
223
|
+
rb_define_method(cFiber, "receive_loop", Fiber_receive_loop, 0);
|
204
224
|
rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
|
205
225
|
rb_define_method(cFiber, "mailbox", Fiber_mailbox, 0);
|
206
226
|
|
@@ -7,7 +7,7 @@ class ::IO
|
|
7
7
|
class << self
|
8
8
|
# @!visibility private
|
9
9
|
alias_method :orig_binread, :binread
|
10
|
-
|
10
|
+
|
11
11
|
# @!visibility private
|
12
12
|
def binread(name, length = nil, offset = nil)
|
13
13
|
File.open(name, 'rb:ASCII-8BIT') do |f|
|
@@ -15,10 +15,10 @@ class ::IO
|
|
15
15
|
length ? f.read(length) : f.read
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
# @!visibility private
|
20
20
|
alias_method :orig_binwrite, :binwrite
|
21
|
-
|
21
|
+
|
22
22
|
# @!visibility private
|
23
23
|
def binwrite(name, string, offset = nil)
|
24
24
|
File.open(name, 'wb:ASCII-8BIT') do |f|
|
@@ -26,13 +26,13 @@ class ::IO
|
|
26
26
|
f.write(string)
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# @!visibility private
|
31
31
|
EMPTY_HASH = {}.freeze
|
32
|
-
|
32
|
+
|
33
33
|
# @!visibility private
|
34
34
|
alias_method :orig_foreach, :foreach
|
35
|
-
|
35
|
+
|
36
36
|
# @!visibility private
|
37
37
|
def foreach(name, sep = $/, limit = nil, getline_args = EMPTY_HASH, &block)
|
38
38
|
if sep.is_a?(Integer)
|
@@ -43,10 +43,10 @@ class ::IO
|
|
43
43
|
f.each_line(sep, limit, chomp: getline_args[:chomp], &block)
|
44
44
|
end
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
# @!visibility private
|
48
48
|
alias_method :orig_read, :read
|
49
|
-
|
49
|
+
|
50
50
|
# @!visibility private
|
51
51
|
def read(name, length = nil, offset = nil, opt = EMPTY_HASH)
|
52
52
|
if length.is_a?(Hash)
|
@@ -58,17 +58,17 @@ class ::IO
|
|
58
58
|
length ? f.read(length) : f.read
|
59
59
|
end
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
# alias_method :orig_readlines, :readlines
|
63
63
|
# def readlines(name, sep = $/, limit = nil, getline_args = EMPTY_HASH)
|
64
64
|
# File.open(name, 'r') do |f|
|
65
65
|
# f.readlines(sep, limit, getline_args)
|
66
66
|
# end
|
67
67
|
# end
|
68
|
-
|
68
|
+
|
69
69
|
# @!visibility private
|
70
70
|
alias_method :orig_write, :write
|
71
|
-
|
71
|
+
|
72
72
|
# @!visibility private
|
73
73
|
def write(name, string, offset = nil, opt = EMPTY_HASH)
|
74
74
|
File.open(name, opt[:mode] || 'w') do |f|
|
@@ -76,18 +76,18 @@ class ::IO
|
|
76
76
|
f.write(string)
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
# @!visibility private
|
81
81
|
alias_method :orig_popen, :popen
|
82
|
-
|
83
|
-
|
82
|
+
|
83
|
+
|
84
84
|
# @!visibility private
|
85
85
|
def popen(cmd, mode = 'r')
|
86
86
|
return orig_popen(cmd, mode) unless block_given?
|
87
|
-
|
87
|
+
|
88
88
|
Open3.popen2(cmd) { |_i, o, _t| yield o }
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
# Splices from one IO to another IO. At least one of the IOs must be a pipe.
|
92
92
|
# If maxlen is negative, splices repeatedly using absolute value of maxlen
|
93
93
|
# until EOF is encountered.
|
@@ -99,9 +99,9 @@ class ::IO
|
|
99
99
|
def splice(src, dest, maxlen)
|
100
100
|
Polyphony.backend_splice(src, dest, maxlen)
|
101
101
|
end
|
102
|
-
|
103
|
-
# Creates a pipe and splices data between the two given IOs using the
|
104
|
-
#
|
102
|
+
|
103
|
+
# Creates a pipe and splices data between the two given IOs, using the pipe,
|
104
|
+
# splicing until EOF.
|
105
105
|
#
|
106
106
|
# @param src [IO, Polyphony::Pipe] source to splice from
|
107
107
|
# @param dest [IO, Polyphony::Pipe] destination to splice to
|
@@ -109,7 +109,7 @@ class ::IO
|
|
109
109
|
def double_splice(src, dest)
|
110
110
|
Polyphony.backend_double_splice(src, dest)
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# Tees data from the source to the desination.
|
114
114
|
#
|
115
115
|
# @param src [IO, Polyphony::Pipe] source to tee from
|
@@ -125,7 +125,7 @@ class ::IO
|
|
125
125
|
def double_splice(src, dest)
|
126
126
|
raise NotImplementedError
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
# @!visibility private
|
130
130
|
def tee(src, dest, maxlen)
|
131
131
|
raise NotImplementedError
|
@@ -140,51 +140,51 @@ class ::IO
|
|
140
140
|
def __read_method__
|
141
141
|
:backend_read
|
142
142
|
end
|
143
|
-
|
143
|
+
|
144
144
|
# @!visibility private
|
145
145
|
def __write_method__
|
146
146
|
:backend_write
|
147
147
|
end
|
148
|
-
|
148
|
+
|
149
149
|
# def each(sep = $/, limit = nil, chomp: nil)
|
150
150
|
# sep, limit = $/, sep if sep.is_a?(Integer)
|
151
151
|
# end
|
152
152
|
# alias_method :each_line, :each
|
153
|
-
|
153
|
+
|
154
154
|
# def each_byte
|
155
155
|
# end
|
156
|
-
|
156
|
+
|
157
157
|
# def each_char
|
158
158
|
# end
|
159
|
-
|
159
|
+
|
160
160
|
# def each_codepoint
|
161
161
|
# end
|
162
|
-
|
162
|
+
|
163
163
|
# @!visibility private
|
164
164
|
alias_method :orig_getbyte, :getbyte
|
165
|
-
|
166
|
-
|
165
|
+
|
166
|
+
|
167
167
|
# @!visibility private
|
168
168
|
def getbyte
|
169
169
|
char = getc
|
170
|
-
char
|
170
|
+
char&.getbyte(0)
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
# @!visibility private
|
174
174
|
alias_method :orig_getc, :getc
|
175
|
-
|
176
|
-
|
175
|
+
|
176
|
+
|
177
177
|
# @!visibility private
|
178
178
|
def getc
|
179
179
|
return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
|
180
|
-
|
180
|
+
|
181
181
|
@read_buffer ||= +''
|
182
182
|
Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
|
183
183
|
return @read_buffer.slice!(0) if !@read_buffer.empty?
|
184
|
-
|
184
|
+
|
185
185
|
nil
|
186
186
|
end
|
187
|
-
|
187
|
+
|
188
188
|
# @!visibility private
|
189
189
|
def ungetc(c)
|
190
190
|
c = c.chr if c.is_a?(Integer)
|
@@ -195,59 +195,59 @@ class ::IO
|
|
195
195
|
end
|
196
196
|
end
|
197
197
|
alias_method :ungetbyte, :ungetc
|
198
|
-
|
198
|
+
|
199
199
|
# @!visibility private
|
200
200
|
alias_method :orig_read, :read
|
201
|
-
|
202
|
-
|
201
|
+
|
202
|
+
|
203
203
|
# @!visibility private
|
204
204
|
def read(len = nil, buf = nil, buf_pos = 0)
|
205
205
|
return '' if len == 0
|
206
|
-
|
206
|
+
|
207
207
|
if buf
|
208
208
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
209
209
|
end
|
210
|
-
|
210
|
+
|
211
211
|
@read_buffer ||= +''
|
212
212
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
213
213
|
return nil unless result
|
214
|
-
|
214
|
+
|
215
215
|
already_read = @read_buffer
|
216
216
|
@read_buffer = +''
|
217
217
|
already_read
|
218
218
|
end
|
219
|
-
|
219
|
+
|
220
220
|
# @!visibility private
|
221
221
|
alias_method :orig_readpartial, :read
|
222
|
-
|
222
|
+
|
223
223
|
# @!visibility private
|
224
224
|
def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
|
225
225
|
result = Polyphony.backend_read(self, str, len, false, buffer_pos)
|
226
226
|
raise EOFError if !result && raise_on_eof
|
227
|
-
|
227
|
+
|
228
228
|
result
|
229
229
|
end
|
230
|
-
|
230
|
+
|
231
231
|
# @!visibility private
|
232
232
|
alias_method :orig_write, :write
|
233
|
-
|
233
|
+
|
234
234
|
# @!visibility private
|
235
235
|
def write(str, *args)
|
236
236
|
Polyphony.backend_write(self, str, *args)
|
237
237
|
end
|
238
|
-
|
238
|
+
|
239
239
|
# @!visibility private
|
240
240
|
alias_method :orig_write_chevron, :<<
|
241
|
-
|
241
|
+
|
242
242
|
# @!visibility private
|
243
243
|
def <<(str)
|
244
244
|
Polyphony.backend_write(self, str)
|
245
245
|
self
|
246
246
|
end
|
247
|
-
|
247
|
+
|
248
248
|
# @!visibility private
|
249
249
|
alias_method :orig_gets, :gets
|
250
|
-
|
250
|
+
|
251
251
|
# @!visibility private
|
252
252
|
def gets(sep = $/, _limit = nil, _chomp: nil)
|
253
253
|
if sep.is_a?(Integer)
|
@@ -255,20 +255,20 @@ class ::IO
|
|
255
255
|
_limit = sep
|
256
256
|
end
|
257
257
|
sep_size = sep.bytesize
|
258
|
-
|
258
|
+
|
259
259
|
@read_buffer ||= +''
|
260
|
-
|
260
|
+
|
261
261
|
while true
|
262
262
|
idx = @read_buffer.index(sep)
|
263
263
|
return @read_buffer.slice!(0, idx + sep_size) if idx
|
264
|
-
|
264
|
+
|
265
265
|
result = readpartial(8192, @read_buffer, -1)
|
266
266
|
return nil unless result
|
267
267
|
end
|
268
268
|
rescue EOFError
|
269
269
|
return nil
|
270
270
|
end
|
271
|
-
|
271
|
+
|
272
272
|
# @!visibility private
|
273
273
|
def each_line(sep = $/, limit = nil, chomp: false)
|
274
274
|
if sep.is_a?(Integer)
|
@@ -276,48 +276,48 @@ class ::IO
|
|
276
276
|
sep = $/
|
277
277
|
end
|
278
278
|
sep_size = sep.bytesize
|
279
|
-
|
280
|
-
|
279
|
+
|
280
|
+
|
281
281
|
@read_buffer ||= +''
|
282
|
-
|
282
|
+
|
283
283
|
while true
|
284
284
|
while (idx = @read_buffer.index(sep))
|
285
285
|
line = @read_buffer.slice!(0, idx + sep_size)
|
286
286
|
line = line.chomp if chomp
|
287
287
|
yield line
|
288
288
|
end
|
289
|
-
|
289
|
+
|
290
290
|
result = readpartial(8192, @read_buffer, -1)
|
291
291
|
return self if !result
|
292
292
|
end
|
293
293
|
rescue EOFError
|
294
294
|
return self
|
295
295
|
end
|
296
|
-
|
296
|
+
|
297
297
|
# def print(*args)
|
298
298
|
# end
|
299
|
-
|
299
|
+
|
300
300
|
# def printf(format, *args)
|
301
301
|
# end
|
302
|
-
|
302
|
+
|
303
303
|
# def putc(obj)
|
304
304
|
# end
|
305
|
-
|
305
|
+
|
306
306
|
# @!visibility private
|
307
307
|
LINEFEED = "\n"
|
308
308
|
# @!visibility private
|
309
309
|
LINEFEED_RE = /\n$/.freeze
|
310
|
-
|
310
|
+
|
311
311
|
# @!visibility private
|
312
312
|
alias_method :orig_puts, :puts
|
313
|
-
|
313
|
+
|
314
314
|
# @!visibility private
|
315
315
|
def puts(*args)
|
316
316
|
if args.empty?
|
317
317
|
write LINEFEED
|
318
318
|
return
|
319
319
|
end
|
320
|
-
|
320
|
+
|
321
321
|
idx = 0
|
322
322
|
while idx < args.size
|
323
323
|
arg = args[idx]
|
@@ -329,26 +329,26 @@ class ::IO
|
|
329
329
|
idx += 2
|
330
330
|
end
|
331
331
|
end
|
332
|
-
|
332
|
+
|
333
333
|
write(*args)
|
334
334
|
nil
|
335
335
|
end
|
336
|
-
|
336
|
+
|
337
337
|
# def readbyte
|
338
338
|
# end
|
339
|
-
|
339
|
+
|
340
340
|
# def readchar
|
341
341
|
# end
|
342
|
-
|
342
|
+
|
343
343
|
# def readline(sep = $/, limit = nil, chomp: nil)
|
344
344
|
# end
|
345
|
-
|
345
|
+
|
346
346
|
# def readlines(sep = $/, limit = nil, chomp: nil)
|
347
347
|
# end
|
348
|
-
|
348
|
+
|
349
349
|
# @!visibility private
|
350
350
|
alias_method :orig_write_nonblock, :write_nonblock
|
351
|
-
|
351
|
+
|
352
352
|
# @!visibility private
|
353
353
|
def write_nonblock(string, _options = {})
|
354
354
|
write(string)
|
@@ -396,7 +396,7 @@ end
|
|
396
396
|
# @return [IO] self
|
397
397
|
def wait_readable(timeout = nil)
|
398
398
|
return self if @read_buffer && @read_buffer.size > 0
|
399
|
-
|
399
|
+
|
400
400
|
if timeout
|
401
401
|
move_on_after(timeout) do
|
402
402
|
Polyphony.backend_wait_io(self, false)
|
@@ -171,6 +171,12 @@ class ::Object
|
|
171
171
|
Fiber.current.receive
|
172
172
|
end
|
173
173
|
|
174
|
+
# Receives messages in an infinite loop from the current fiber's mailbox,
|
175
|
+
# passing them to the given block.
|
176
|
+
def receive_loop(&block)
|
177
|
+
Fiber.current.receive_loop(&block)
|
178
|
+
end
|
179
|
+
|
174
180
|
# Returns all messages currently pending on the current fiber's mailbox.
|
175
181
|
#
|
176
182
|
# @return [Array] array of received messages
|
@@ -75,15 +75,15 @@ class ::Socket < ::BasicSocket
|
|
75
75
|
# @return [String] buffer used for reading
|
76
76
|
def read(len = nil, buf = nil, buf_pos = 0)
|
77
77
|
return '' if len == 0
|
78
|
-
|
78
|
+
|
79
79
|
if buf
|
80
80
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
@read_buffer ||= +''
|
84
84
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
85
85
|
return nil unless result
|
86
|
-
|
86
|
+
|
87
87
|
already_read = @read_buffer
|
88
88
|
@read_buffer = +''
|
89
89
|
already_read
|
@@ -339,15 +339,15 @@ class ::TCPSocket < ::IPSocket
|
|
339
339
|
# @return [String] buffer used for reading
|
340
340
|
def read(len = nil, buf = nil, buf_pos = 0)
|
341
341
|
return '' if len == 0
|
342
|
-
|
342
|
+
|
343
343
|
if buf
|
344
344
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
345
345
|
end
|
346
|
-
|
346
|
+
|
347
347
|
@read_buffer ||= +''
|
348
348
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
349
349
|
return nil unless result
|
350
|
-
|
350
|
+
|
351
351
|
already_read = @read_buffer
|
352
352
|
@read_buffer = +''
|
353
353
|
already_read
|
@@ -548,15 +548,15 @@ class ::UNIXSocket < ::BasicSocket
|
|
548
548
|
# @return [String] buffer used for reading
|
549
549
|
def read(len = nil, buf = nil, buf_pos = 0)
|
550
550
|
return '' if len == 0
|
551
|
-
|
551
|
+
|
552
552
|
if buf
|
553
553
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
554
554
|
end
|
555
|
-
|
555
|
+
|
556
556
|
@read_buffer ||= +''
|
557
557
|
result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
|
558
558
|
return nil unless result
|
559
|
-
|
559
|
+
|
560
560
|
already_read = @read_buffer
|
561
561
|
@read_buffer = +''
|
562
562
|
already_read
|
data/lib/polyphony/version.rb
CHANGED
data/polyphony.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.author = 'Sharon Rosner'
|
9
9
|
s.email = 'sharon@noteflakes.com'
|
10
10
|
s.files = `git ls-files --recurse-submodules`.split.reject { |fn| fn =~ /liburing\/man/ }
|
11
|
-
s.homepage = 'https://digital-fabric
|
11
|
+
s.homepage = 'https://github.com/digital-fabric/polyphony'
|
12
12
|
s.metadata = {
|
13
13
|
"source_code_uri" => "https://github.com/digital-fabric/polyphony",
|
14
14
|
"documentation_uri" => "https://www.rubydoc.info/gems/polyphony",
|
data/test/stress.rb
CHANGED
data/test/test_fiber.rb
CHANGED
@@ -975,6 +975,50 @@ class MailboxTest < MiniTest::Test
|
|
975
975
|
assert_equal ['foo'] * 100, messages
|
976
976
|
end
|
977
977
|
|
978
|
+
def test_receive_loop
|
979
|
+
buffer = []
|
980
|
+
f = spin do
|
981
|
+
receive_loop { |msg| buffer << msg }
|
982
|
+
ensure
|
983
|
+
buffer << :done
|
984
|
+
end
|
985
|
+
|
986
|
+
snooze
|
987
|
+
f << :foo
|
988
|
+
snooze
|
989
|
+
assert_equal [:foo], buffer
|
990
|
+
|
991
|
+
f << :bar
|
992
|
+
snooze
|
993
|
+
assert_equal [:foo, :bar], buffer
|
994
|
+
|
995
|
+
f.kill
|
996
|
+
f.join
|
997
|
+
assert_equal [:foo, :bar, :done], buffer
|
998
|
+
end
|
999
|
+
|
1000
|
+
def test_receive_loop_break
|
1001
|
+
buffer = []
|
1002
|
+
f = spin do
|
1003
|
+
receive_loop do |msg|
|
1004
|
+
buffer << msg
|
1005
|
+
break if msg == :bar
|
1006
|
+
end
|
1007
|
+
buffer << :done
|
1008
|
+
end
|
1009
|
+
|
1010
|
+
snooze
|
1011
|
+
f << :foo
|
1012
|
+
snooze
|
1013
|
+
assert_equal [:foo], buffer
|
1014
|
+
|
1015
|
+
f << :bar
|
1016
|
+
snooze
|
1017
|
+
assert_equal [:foo, :bar, :done], buffer
|
1018
|
+
|
1019
|
+
assert_equal :dead, f.state
|
1020
|
+
end
|
1021
|
+
|
978
1022
|
def test_receive_exception
|
979
1023
|
e = RuntimeError.new 'foo'
|
980
1024
|
spin { Fiber.current.parent << e }
|
@@ -1287,4 +1331,4 @@ class DebugTest < MiniTest::Test
|
|
1287
1331
|
10.times { snooze }
|
1288
1332
|
assert_equal [0, 1, 2], buf
|
1289
1333
|
end
|
1290
|
-
end
|
1334
|
+
end
|
data/test/test_io.rb
CHANGED
@@ -321,11 +321,36 @@ class IOTest < MiniTest::Test
|
|
321
321
|
assert_equal 6, len
|
322
322
|
end
|
323
323
|
|
324
|
+
def test_splice_class_method_with_eof_detection
|
325
|
+
i1, o1 = IO.pipe
|
326
|
+
i2, o2 = IO.pipe
|
327
|
+
splice_lens = []
|
328
|
+
|
329
|
+
spin {
|
330
|
+
loop {
|
331
|
+
len = IO.splice(i1, o2, 1000)
|
332
|
+
splice_lens << len
|
333
|
+
break if len == 0
|
334
|
+
}
|
335
|
+
|
336
|
+
o2.close
|
337
|
+
}
|
338
|
+
|
339
|
+
o1.write('foobar')
|
340
|
+
snooze
|
341
|
+
o1.close
|
342
|
+
|
343
|
+
result = i2.read
|
344
|
+
assert_equal 'foobar', result
|
345
|
+
assert_equal [6, 0], splice_lens
|
346
|
+
end
|
347
|
+
|
324
348
|
def test_splice_from_to_eof
|
325
349
|
i1, o1 = IO.pipe
|
326
350
|
i2, o2 = IO.pipe
|
327
351
|
len = nil
|
328
352
|
|
353
|
+
|
329
354
|
f = spin {
|
330
355
|
len = o2.splice_from(i1, -1000)
|
331
356
|
o2.close
|
@@ -672,6 +697,27 @@ class IOClassMethodsTest < MiniTest::Test
|
|
672
697
|
assert_equal [:ready, 'foo', 'bar', :done], buf
|
673
698
|
end
|
674
699
|
|
700
|
+
def test_read_loop_break
|
701
|
+
i, o = IO.pipe
|
702
|
+
|
703
|
+
buf = []
|
704
|
+
f = spin do
|
705
|
+
buf << :ready
|
706
|
+
i.read_loop do |d|
|
707
|
+
buf << d
|
708
|
+
break if d == 'bar'
|
709
|
+
end
|
710
|
+
buf << :done
|
711
|
+
end
|
712
|
+
|
713
|
+
# writing always causes snoozing
|
714
|
+
o << 'foo'
|
715
|
+
3.times { snooze }
|
716
|
+
o << 'bar'
|
717
|
+
f.await
|
718
|
+
assert_equal [:ready, 'foo', 'bar', :done], buf
|
719
|
+
end
|
720
|
+
|
675
721
|
def test_read_loop_with_max_len
|
676
722
|
r, w = IO.pipe
|
677
723
|
|