polyphony 1.4 → 1.6
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +22 -0
- data/TODO.md +5 -14
- data/examples/pipes/http_server.rb +42 -12
- data/examples/pipes/http_server2.rb +45 -0
- data/ext/polyphony/backend_common.h +5 -0
- data/ext/polyphony/backend_io_uring.c +174 -121
- data/ext/polyphony/backend_io_uring_context.c +24 -18
- data/ext/polyphony/backend_io_uring_context.h +4 -2
- data/ext/polyphony/backend_libev.c +46 -22
- data/ext/polyphony/event.c +21 -0
- data/ext/polyphony/extconf.rb +25 -19
- data/ext/polyphony/fiber.c +0 -2
- data/ext/polyphony/pipe.c +1 -1
- data/ext/polyphony/polyphony.c +2 -20
- data/ext/polyphony/polyphony.h +5 -5
- data/ext/polyphony/ring_buffer.c +1 -0
- data/ext/polyphony/runqueue_ring_buffer.c +1 -0
- data/ext/polyphony/thread.c +63 -0
- data/ext/polyphony/win_uio.h +18 -0
- data/lib/polyphony/adapters/open3.rb +190 -0
- data/lib/polyphony/core/sync.rb +83 -13
- data/lib/polyphony/core/timer.rb +7 -25
- data/lib/polyphony/extensions/exception.rb +15 -0
- data/lib/polyphony/extensions/fiber.rb +14 -13
- data/lib/polyphony/extensions/io.rb +56 -14
- data/lib/polyphony/extensions/kernel.rb +1 -1
- data/lib/polyphony/extensions/object.rb +1 -13
- data/lib/polyphony/extensions/process.rb +76 -1
- data/lib/polyphony/extensions/socket.rb +0 -14
- data/lib/polyphony/extensions/thread.rb +19 -27
- data/lib/polyphony/extensions/timeout.rb +5 -1
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +11 -5
- data/test/helper.rb +46 -4
- data/test/open3/envutil.rb +380 -0
- data/test/open3/find_executable.rb +24 -0
- data/test/stress.rb +11 -7
- data/test/test_backend.rb +11 -4
- data/test/test_event.rb +10 -3
- data/test/test_ext.rb +16 -1
- data/test/test_fiber.rb +16 -4
- data/test/test_global_api.rb +17 -16
- data/test/test_io.rb +39 -0
- data/test/test_kernel.rb +2 -2
- data/test/test_monitor.rb +356 -0
- data/test/test_open3.rb +338 -0
- data/test/test_signal.rb +5 -1
- data/test/test_socket.rb +6 -98
- data/test/test_sync.rb +46 -0
- data/test/test_thread.rb +10 -1
- data/test/test_thread_pool.rb +5 -0
- data/test/test_throttler.rb +1 -1
- data/test/test_timer.rb +8 -2
- data/test/test_trace.rb +2 -0
- data/vendor/liburing/.github/workflows/build.yml +8 -0
- data/vendor/liburing/.gitignore +1 -0
- data/vendor/liburing/CHANGELOG +8 -0
- data/vendor/liburing/configure +17 -25
- data/vendor/liburing/debian/liburing-dev.manpages +2 -0
- data/vendor/liburing/debian/rules +2 -1
- data/vendor/liburing/examples/Makefile +2 -1
- data/vendor/liburing/examples/io_uring-udp.c +11 -3
- data/vendor/liburing/examples/rsrc-update-bench.c +100 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/make-debs.sh +4 -2
- data/vendor/liburing/src/Makefile +5 -5
- data/vendor/liburing/src/arch/aarch64/lib.h +1 -1
- data/vendor/liburing/src/include/liburing/io_uring.h +41 -16
- data/vendor/liburing/src/include/liburing.h +86 -11
- data/vendor/liburing/src/int_flags.h +1 -0
- data/vendor/liburing/src/liburing-ffi.map +12 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/register.c +7 -2
- data/vendor/liburing/src/setup.c +373 -81
- data/vendor/liburing/test/232c93d07b74.c +3 -3
- data/vendor/liburing/test/Makefile +10 -3
- data/vendor/liburing/test/accept.c +2 -1
- data/vendor/liburing/test/buf-ring.c +35 -75
- data/vendor/liburing/test/connect-rep.c +204 -0
- data/vendor/liburing/test/coredump.c +59 -0
- data/vendor/liburing/test/fallocate.c +9 -0
- data/vendor/liburing/test/fd-pass.c +34 -3
- data/vendor/liburing/test/file-verify.c +27 -6
- data/vendor/liburing/test/helpers.c +3 -1
- data/vendor/liburing/test/io_uring_register.c +25 -28
- data/vendor/liburing/test/io_uring_setup.c +1 -1
- data/vendor/liburing/test/poll-cancel-all.c +29 -5
- data/vendor/liburing/test/poll-race-mshot.c +6 -22
- data/vendor/liburing/test/read-write.c +53 -0
- data/vendor/liburing/test/recv-msgall.c +21 -23
- data/vendor/liburing/test/reg-fd-only.c +55 -0
- data/vendor/liburing/test/reg-hint.c +56 -0
- data/vendor/liburing/test/regbuf-merge.c +91 -0
- data/vendor/liburing/test/ringbuf-read.c +2 -10
- data/vendor/liburing/test/send_recvmsg.c +5 -16
- data/vendor/liburing/test/shutdown.c +2 -1
- data/vendor/liburing/test/socket-io-cmd.c +215 -0
- data/vendor/liburing/test/socket-rw-eagain.c +2 -1
- data/vendor/liburing/test/socket-rw-offset.c +2 -1
- data/vendor/liburing/test/socket-rw.c +2 -1
- data/vendor/liburing/test/timeout.c +276 -0
- data/vendor/liburing/test/xattr.c +38 -25
- metadata +20 -7
- data/vendor/liburing/test/timeout-overflow.c +0 -204
data/test/test_io.rb
CHANGED
@@ -100,6 +100,12 @@ class IOTest < MiniTest::Test
|
|
100
100
|
assert_equal '', i.read(0)
|
101
101
|
end
|
102
102
|
|
103
|
+
def test_read_empty_pipe
|
104
|
+
i, o = IO.pipe
|
105
|
+
o.close
|
106
|
+
assert_equal '', i.read
|
107
|
+
end
|
108
|
+
|
103
109
|
def test_readpartial
|
104
110
|
i, o = IO.pipe
|
105
111
|
|
@@ -345,6 +351,39 @@ class IOTest < MiniTest::Test
|
|
345
351
|
assert_equal [6, 0], splice_lens
|
346
352
|
end
|
347
353
|
|
354
|
+
def test_copy_stream
|
355
|
+
p1 = Polyphony::Pipe.new
|
356
|
+
p2 = Polyphony::Pipe.new
|
357
|
+
|
358
|
+
spin { p1 << 'foobar'; p1.close }
|
359
|
+
|
360
|
+
count = IO.copy_stream(p1, p2)
|
361
|
+
p2.close
|
362
|
+
assert_equal 6, count
|
363
|
+
assert_equal 'foobar', p2.read
|
364
|
+
end
|
365
|
+
|
366
|
+
def test_copy_stream_with_length
|
367
|
+
p1 = Polyphony::Pipe.new
|
368
|
+
p2 = Polyphony::Pipe.new
|
369
|
+
|
370
|
+
spin { p1 << 'foobar'; p1.close }
|
371
|
+
|
372
|
+
count = IO.copy_stream(p1, p2, 3)
|
373
|
+
p2.close
|
374
|
+
assert_equal 3, count
|
375
|
+
assert_equal 'foo', p2.read
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_copy_stream_with_length_and_offset
|
379
|
+
p2 = Polyphony::Pipe.new
|
380
|
+
|
381
|
+
count = IO.copy_stream(__FILE__, p2, 34, 4)
|
382
|
+
p2.close
|
383
|
+
assert_equal 34, count
|
384
|
+
assert_equal IO.read(__FILE__)[4, 34], p2.read
|
385
|
+
end
|
386
|
+
|
348
387
|
def test_splice_from_to_eof
|
349
388
|
i1, o1 = IO.pipe
|
350
389
|
i2, o2 = IO.pipe
|
data/test/test_kernel.rb
CHANGED
@@ -8,9 +8,9 @@ class KernelTest < MiniTest::Test
|
|
8
8
|
FileUtils.rm(fn) rescue nil
|
9
9
|
|
10
10
|
counter = 0
|
11
|
-
timer = spin { throttled_loop(
|
11
|
+
timer = spin { throttled_loop(20) { counter += 1 } }
|
12
12
|
|
13
|
-
system('sleep 0.
|
13
|
+
system('sleep 0.13')
|
14
14
|
assert(counter >= 2)
|
15
15
|
|
16
16
|
system('echo "hello" > ' + fn)
|
@@ -0,0 +1,356 @@
|
|
1
|
+
# Adapted from: https://github.com/ruby/ruby/blob/master/test/monitor/test_monitor.rb
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require_relative 'helper'
|
6
|
+
|
7
|
+
class TestMonitor < MiniTest::Test
|
8
|
+
Queue = Polyphony::Queue
|
9
|
+
|
10
|
+
def setup
|
11
|
+
super
|
12
|
+
@monitor = Polyphony::Monitor.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_enter_in_different_fibers
|
16
|
+
@monitor.enter
|
17
|
+
Fiber.new {
|
18
|
+
assert_equal false, @monitor.try_enter
|
19
|
+
}.resume
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_enter
|
23
|
+
ary = []
|
24
|
+
queue = Thread::Queue.new
|
25
|
+
f1 = spin {
|
26
|
+
queue.pop
|
27
|
+
@monitor.enter
|
28
|
+
for i in 6 .. 10
|
29
|
+
ary.push(i)
|
30
|
+
snooze
|
31
|
+
end
|
32
|
+
@monitor.exit
|
33
|
+
}
|
34
|
+
f2 = spin {
|
35
|
+
@monitor.enter
|
36
|
+
queue.enq(nil)
|
37
|
+
for i in 1 .. 5
|
38
|
+
ary.push(i)
|
39
|
+
snooze
|
40
|
+
end
|
41
|
+
@monitor.exit
|
42
|
+
}
|
43
|
+
Fiber.await(f1, f2)
|
44
|
+
assert_equal((1..10).to_a, ary)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_exit
|
48
|
+
m = Polyphony::Monitor.new
|
49
|
+
m.enter
|
50
|
+
assert_equal true, m.mon_owned?
|
51
|
+
m.exit
|
52
|
+
assert_equal false, m.mon_owned?
|
53
|
+
|
54
|
+
assert_raises ThreadError do
|
55
|
+
m.exit
|
56
|
+
end
|
57
|
+
|
58
|
+
assert_equal false, m.mon_owned?
|
59
|
+
|
60
|
+
m.enter
|
61
|
+
Thread.new{
|
62
|
+
assert_raises ThreadError do
|
63
|
+
m.exit
|
64
|
+
end
|
65
|
+
true
|
66
|
+
}.join
|
67
|
+
assert_equal true, m.mon_owned?
|
68
|
+
m.exit
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_enter_second_after_killed_thread
|
72
|
+
th = Thread.new {
|
73
|
+
@monitor.enter
|
74
|
+
Thread.current.kill
|
75
|
+
@monitor.exit
|
76
|
+
}
|
77
|
+
th.join
|
78
|
+
@monitor.enter
|
79
|
+
@monitor.exit
|
80
|
+
th2 = Thread.new {
|
81
|
+
@monitor.enter
|
82
|
+
@monitor.exit
|
83
|
+
}
|
84
|
+
assert_join_threads([th, th2])
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_synchronize
|
88
|
+
ary = []
|
89
|
+
f1 = spin {
|
90
|
+
receive
|
91
|
+
@monitor.synchronize do
|
92
|
+
for i in 6 .. 10
|
93
|
+
ary.push(i)
|
94
|
+
snooze
|
95
|
+
end
|
96
|
+
end
|
97
|
+
}
|
98
|
+
f2 = spin {
|
99
|
+
@monitor.synchronize do
|
100
|
+
f1 << :continue
|
101
|
+
for i in 1 .. 5
|
102
|
+
ary.push(i)
|
103
|
+
snooze
|
104
|
+
end
|
105
|
+
end
|
106
|
+
}
|
107
|
+
Fiber.await(f1, f2)
|
108
|
+
assert_equal((1..10).to_a, ary)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_killed_thread_in_synchronize
|
112
|
+
ary = []
|
113
|
+
queue = Thread::Queue.new
|
114
|
+
t1 = Thread.new {
|
115
|
+
queue.pop
|
116
|
+
@monitor.synchronize {
|
117
|
+
ary << :t1
|
118
|
+
}
|
119
|
+
}
|
120
|
+
t2 = Thread.new {
|
121
|
+
queue.pop
|
122
|
+
@monitor.synchronize {
|
123
|
+
ary << :t2
|
124
|
+
}
|
125
|
+
}
|
126
|
+
t3 = Thread.new {
|
127
|
+
@monitor.synchronize do
|
128
|
+
queue.enq(nil)
|
129
|
+
queue.enq(nil)
|
130
|
+
assert_equal([], ary)
|
131
|
+
t1.kill
|
132
|
+
t2.kill
|
133
|
+
ary << :main
|
134
|
+
end
|
135
|
+
assert_equal([:main], ary)
|
136
|
+
}
|
137
|
+
assert_join_threads([t1, t2, t3])
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_try_enter
|
141
|
+
queue1 = Thread::Queue.new
|
142
|
+
queue2 = Thread::Queue.new
|
143
|
+
th = Thread.new {
|
144
|
+
queue1.deq
|
145
|
+
@monitor.enter
|
146
|
+
queue2.enq(nil)
|
147
|
+
queue1.deq
|
148
|
+
@monitor.exit
|
149
|
+
queue2.enq(nil)
|
150
|
+
}
|
151
|
+
th2 = Thread.new {
|
152
|
+
assert_equal(true, @monitor.try_enter)
|
153
|
+
@monitor.exit
|
154
|
+
queue1.enq(nil)
|
155
|
+
queue2.deq
|
156
|
+
assert_equal(false, @monitor.try_enter)
|
157
|
+
queue1.enq(nil)
|
158
|
+
queue2.deq
|
159
|
+
assert_equal(true, @monitor.try_enter)
|
160
|
+
}
|
161
|
+
assert_join_threads([th, th2])
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_try_enter_second_after_killed_thread
|
165
|
+
th = Thread.new {
|
166
|
+
assert_equal(true, @monitor.try_enter)
|
167
|
+
Thread.current.kill
|
168
|
+
@monitor.exit
|
169
|
+
}
|
170
|
+
th.join
|
171
|
+
assert_equal(true, @monitor.try_enter)
|
172
|
+
@monitor.exit
|
173
|
+
th2 = Thread.new {
|
174
|
+
assert_equal(true, @monitor.try_enter)
|
175
|
+
@monitor.exit
|
176
|
+
}
|
177
|
+
assert_join_threads([th, th2])
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_mon_locked_and_owned
|
181
|
+
queue1 = Thread::Queue.new
|
182
|
+
queue2 = Thread::Queue.new
|
183
|
+
th = Thread.new {
|
184
|
+
@monitor.enter
|
185
|
+
queue1.enq(nil)
|
186
|
+
queue2.deq
|
187
|
+
@monitor.exit
|
188
|
+
queue1.enq(nil)
|
189
|
+
}
|
190
|
+
queue1.deq
|
191
|
+
assert(@monitor.mon_locked?)
|
192
|
+
assert(!@monitor.mon_owned?)
|
193
|
+
|
194
|
+
queue2.enq(nil)
|
195
|
+
queue1.deq
|
196
|
+
assert(!@monitor.mon_locked?)
|
197
|
+
|
198
|
+
@monitor.enter
|
199
|
+
assert @monitor.mon_locked?
|
200
|
+
assert @monitor.mon_owned?
|
201
|
+
@monitor.exit
|
202
|
+
|
203
|
+
@monitor.synchronize do
|
204
|
+
assert @monitor.mon_locked?
|
205
|
+
assert @monitor.mon_owned?
|
206
|
+
end
|
207
|
+
ensure
|
208
|
+
th.join
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_cond
|
212
|
+
cond = @monitor.new_cond
|
213
|
+
|
214
|
+
a = "foo"
|
215
|
+
queue1 = Thread::Queue.new
|
216
|
+
th = Thread.new do
|
217
|
+
queue1.deq
|
218
|
+
@monitor.synchronize do
|
219
|
+
a = "bar"
|
220
|
+
cond.signal
|
221
|
+
end
|
222
|
+
end
|
223
|
+
th2 = Thread.new do
|
224
|
+
@monitor.synchronize do
|
225
|
+
queue1.enq(nil)
|
226
|
+
assert_equal("foo", a)
|
227
|
+
result1 = cond.wait
|
228
|
+
assert_equal(true, result1)
|
229
|
+
assert_equal("bar", a)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
assert_join_threads([th, th2])
|
233
|
+
end
|
234
|
+
|
235
|
+
class NewCondTest
|
236
|
+
include ::MonitorMixin
|
237
|
+
attr_reader :cond
|
238
|
+
def initialize
|
239
|
+
@cond = new_cond
|
240
|
+
super # mon_initialize
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_new_cond_before_initialize
|
245
|
+
assert NewCondTest.new.cond.instance_variable_get(:@monitor) != nil
|
246
|
+
end
|
247
|
+
|
248
|
+
class KeywordInitializeParent
|
249
|
+
def initialize(x:)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
class KeywordInitializeChild < KeywordInitializeParent
|
254
|
+
include ::MonitorMixin
|
255
|
+
def initialize
|
256
|
+
super(x: 1)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_initialize_with_keyword_arg
|
261
|
+
assert KeywordInitializeChild.new
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_timedwait
|
265
|
+
cond = @monitor.new_cond
|
266
|
+
b = "foo"
|
267
|
+
queue2 = Thread::Queue.new
|
268
|
+
th = Thread.new do
|
269
|
+
queue2.deq
|
270
|
+
@monitor.synchronize do
|
271
|
+
b = "bar"
|
272
|
+
cond.signal
|
273
|
+
end
|
274
|
+
end
|
275
|
+
result2 = nil
|
276
|
+
@monitor.synchronize do
|
277
|
+
queue2.enq(nil)
|
278
|
+
assert_equal("foo", b)
|
279
|
+
result2 = cond.wait(0.1)
|
280
|
+
assert_equal(true, result2)
|
281
|
+
assert_equal("bar", b)
|
282
|
+
end
|
283
|
+
th.join
|
284
|
+
|
285
|
+
c = "foo"
|
286
|
+
queue3 = Thread::Queue.new
|
287
|
+
th = Thread.new do
|
288
|
+
queue3.deq
|
289
|
+
@monitor.synchronize do
|
290
|
+
c = "bar"
|
291
|
+
cond.signal
|
292
|
+
end
|
293
|
+
end
|
294
|
+
th2 = Thread.new do
|
295
|
+
@monitor.synchronize do
|
296
|
+
assert_equal("foo", c)
|
297
|
+
result3 = cond.wait(0.1)
|
298
|
+
assert_equal(false, result3)
|
299
|
+
assert_equal("foo", c)
|
300
|
+
queue3.enq(nil)
|
301
|
+
result4 = cond.wait
|
302
|
+
assert_equal(true, result4)
|
303
|
+
assert_equal("bar", c)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
assert_join_threads([th, th2])
|
307
|
+
|
308
|
+
# d = "foo"
|
309
|
+
# cumber_thread = Thread.new {
|
310
|
+
# loop do
|
311
|
+
# @monitor.synchronize do
|
312
|
+
# d = "foo"
|
313
|
+
# end
|
314
|
+
# end
|
315
|
+
# }
|
316
|
+
# queue3 = Thread::Queue.new
|
317
|
+
# Thread.new do
|
318
|
+
# queue3.pop
|
319
|
+
# @monitor.synchronize do
|
320
|
+
# d = "bar"
|
321
|
+
# cond.signal
|
322
|
+
# end
|
323
|
+
# end
|
324
|
+
# @monitor.synchronize do
|
325
|
+
# queue3.enq(nil)
|
326
|
+
# assert_equal("foo", d)
|
327
|
+
# result5 = cond.wait
|
328
|
+
# assert_equal(true, result5)
|
329
|
+
# # this thread has priority over cumber_thread
|
330
|
+
# assert_equal("bar", d)
|
331
|
+
# end
|
332
|
+
# cumber_thread.kill
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_wait_interruption
|
336
|
+
cond = @monitor.new_cond
|
337
|
+
|
338
|
+
th = Thread.new {
|
339
|
+
@monitor.synchronize do
|
340
|
+
begin
|
341
|
+
cond.wait(0.1)
|
342
|
+
@monitor.mon_owned?
|
343
|
+
rescue Interrupt
|
344
|
+
@monitor.mon_owned?
|
345
|
+
end
|
346
|
+
end
|
347
|
+
}
|
348
|
+
sleep(0.1)
|
349
|
+
th.raise(Interrupt)
|
350
|
+
|
351
|
+
begin
|
352
|
+
assert_equal true, th.value
|
353
|
+
rescue Interrupt
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|