polyphony 0.71 → 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/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +15 -11
- data/.github/workflows/test_io_uring.yml +32 -0
- data/.gitignore +3 -1
- data/CHANGELOG.md +33 -4
- data/Gemfile.lock +16 -13
- data/TODO.md +1 -1
- data/bin/pdbg +1 -1
- data/docs/_user-guide/all-about-timers.md +1 -1
- data/docs/api-reference/exception.md +5 -1
- data/docs/api-reference/fiber.md +2 -2
- data/docs/faq.md +1 -1
- data/docs/getting-started/overview.md +8 -8
- data/docs/getting-started/tutorial.md +3 -3
- data/docs/main-concepts/concurrency.md +1 -1
- data/docs/main-concepts/extending.md +3 -3
- data/docs/main-concepts/fiber-scheduling.md +1 -1
- data/examples/core/calc.rb +37 -0
- data/examples/core/calc_with_restart.rb +40 -0
- data/examples/core/calc_with_supervise.rb +37 -0
- data/examples/core/message_based_supervision.rb +1 -1
- data/examples/core/ring.rb +29 -0
- data/examples/io/rack_server.rb +1 -1
- data/examples/io/tunnel.rb +1 -1
- data/examples/performance/fiber_transfer.rb +1 -1
- data/examples/performance/line_splitting.rb +1 -1
- data/examples/performance/thread-vs-fiber/compare.rb +1 -1
- data/ext/polyphony/backend_common.c +88 -18
- data/ext/polyphony/backend_common.h +8 -1
- data/ext/polyphony/backend_io_uring.c +280 -164
- data/ext/polyphony/backend_io_uring_context.c +2 -1
- data/ext/polyphony/backend_io_uring_context.h +3 -2
- data/ext/polyphony/backend_libev.c +42 -38
- data/ext/polyphony/event.c +5 -2
- data/ext/polyphony/extconf.rb +25 -13
- data/ext/polyphony/polyphony.c +10 -1
- data/ext/polyphony/polyphony.h +7 -1
- data/ext/polyphony/queue.c +12 -7
- data/ext/polyphony/runqueue_ring_buffer.c +6 -3
- data/ext/polyphony/socket_extensions.c +5 -2
- data/ext/polyphony/thread.c +1 -1
- data/lib/polyphony/adapters/irb.rb +11 -1
- data/lib/polyphony/{extensions → core}/debug.rb +0 -0
- data/lib/polyphony/core/global_api.rb +3 -6
- data/lib/polyphony/core/timer.rb +2 -2
- data/lib/polyphony/debugger.rb +3 -3
- data/lib/polyphony/extensions/exception.rb +45 -0
- data/lib/polyphony/extensions/fiber.rb +87 -11
- data/lib/polyphony/extensions/io.rb +2 -2
- data/lib/polyphony/extensions/{core.rb → kernel.rb} +0 -73
- data/lib/polyphony/extensions/openssl.rb +20 -5
- data/lib/polyphony/extensions/process.rb +19 -0
- data/lib/polyphony/extensions/socket.rb +20 -9
- data/lib/polyphony/extensions/thread.rb +9 -3
- 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 -4
- data/polyphony.gemspec +1 -1
- data/test/coverage.rb +2 -2
- data/test/test_backend.rb +15 -17
- data/test/test_event.rb +1 -1
- data/test/test_ext.rb +1 -1
- data/test/test_fiber.rb +31 -7
- data/test/test_global_api.rb +23 -14
- data/test/test_io.rb +5 -5
- data/test/test_kernel.rb +2 -2
- data/test/test_process_supervision.rb +1 -1
- data/test/test_queue.rb +6 -6
- data/test/test_signal.rb +20 -1
- data/test/test_socket.rb +45 -10
- data/test/test_supervise.rb +85 -0
- data/test/test_sync.rb +2 -2
- data/test/test_thread.rb +22 -2
- data/test/test_thread_pool.rb +2 -2
- data/test/test_throttler.rb +3 -3
- data/test/test_timer.rb +3 -3
- data/test/test_trace.rb +1 -1
- metadata +19 -9
data/test/test_backend.rb
CHANGED
@@ -36,7 +36,7 @@ class BackendTest < MiniTest::Test
|
|
36
36
|
f = spin { @backend.read(i, buf, 5, false, 0) }
|
37
37
|
@backend.write(o, 'Hello world')
|
38
38
|
return_value = f.await
|
39
|
-
|
39
|
+
|
40
40
|
assert_equal 'Hello', buf
|
41
41
|
assert_equal return_value, buf
|
42
42
|
end
|
@@ -51,7 +51,7 @@ class BackendTest < MiniTest::Test
|
|
51
51
|
snooze
|
52
52
|
o.close
|
53
53
|
return_value = f.await
|
54
|
-
|
54
|
+
|
55
55
|
assert_equal 'Hello', buf
|
56
56
|
assert_equal return_value, buf
|
57
57
|
end
|
@@ -66,7 +66,7 @@ class BackendTest < MiniTest::Test
|
|
66
66
|
snooze
|
67
67
|
o.close
|
68
68
|
return_value = f.await
|
69
|
-
|
69
|
+
|
70
70
|
assert_equal 'Hello world', buf
|
71
71
|
assert_equal return_value, buf
|
72
72
|
end
|
@@ -77,7 +77,7 @@ class BackendTest < MiniTest::Test
|
|
77
77
|
f = spin { @backend.read(i, buf, 20, false, 0) }
|
78
78
|
@backend.write(o, 'blah')
|
79
79
|
return_value = f.await
|
80
|
-
|
80
|
+
|
81
81
|
assert_equal 'blah', buf
|
82
82
|
assert_equal return_value, buf
|
83
83
|
|
@@ -85,7 +85,7 @@ class BackendTest < MiniTest::Test
|
|
85
85
|
f = spin { @backend.read(i, buf, 20, false, -1) }
|
86
86
|
@backend.write(o, 'klmn')
|
87
87
|
return_value = f.await
|
88
|
-
|
88
|
+
|
89
89
|
assert_equal 'abcdefghijklmn', buf
|
90
90
|
assert_equal return_value, buf
|
91
91
|
|
@@ -93,7 +93,7 @@ class BackendTest < MiniTest::Test
|
|
93
93
|
f = spin { @backend.read(i, buf, 20, false, 3) }
|
94
94
|
@backend.write(o, 'DEF')
|
95
95
|
return_value = f.await
|
96
|
-
|
96
|
+
|
97
97
|
assert_equal 'abcDEF', buf
|
98
98
|
assert_equal return_value, buf
|
99
99
|
end
|
@@ -109,12 +109,12 @@ class BackendTest < MiniTest::Test
|
|
109
109
|
|
110
110
|
o << data
|
111
111
|
o.close
|
112
|
-
|
112
|
+
|
113
113
|
buf = +''
|
114
114
|
|
115
115
|
@backend.read(i, buf, 4096, false, -1)
|
116
116
|
assert_equal 4096, buf.bytesize
|
117
|
-
|
117
|
+
|
118
118
|
@backend.read(i, buf, 1, false, -1)
|
119
119
|
assert_equal 4097, buf.bytesize
|
120
120
|
|
@@ -129,7 +129,7 @@ class BackendTest < MiniTest::Test
|
|
129
129
|
@backend.post_fork
|
130
130
|
exit(42)
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
result = @backend.waitpid(pid)
|
134
134
|
assert_equal [pid, 42], result
|
135
135
|
end
|
@@ -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
|
@@ -427,7 +425,7 @@ class BackendTest < MiniTest::Test
|
|
427
425
|
counter = 0
|
428
426
|
|
429
427
|
@backend.idle_proc = proc { counter += 1 }
|
430
|
-
|
428
|
+
|
431
429
|
3.times { snooze }
|
432
430
|
assert_equal 0, counter
|
433
431
|
|
@@ -488,7 +486,7 @@ class BackendChainTest < MiniTest::Test
|
|
488
486
|
|
489
487
|
snooze
|
490
488
|
client = TCPSocket.new('127.0.0.1', port)
|
491
|
-
|
489
|
+
|
492
490
|
result = Thread.backend.chain(
|
493
491
|
[:send, client, 'hello', 0],
|
494
492
|
[:send, client, " world\n", 0]
|
@@ -512,7 +510,7 @@ class BackendChainTest < MiniTest::Test
|
|
512
510
|
while true
|
513
511
|
len = o.splice(from, 8192)
|
514
512
|
break if len == 0
|
515
|
-
|
513
|
+
|
516
514
|
backend.chain(
|
517
515
|
[:write, to, chunk_header(len)],
|
518
516
|
[:splice, i, to, len]
|
data/test/test_event.rb
CHANGED
data/test/test_ext.rb
CHANGED
data/test/test_fiber.rb
CHANGED
@@ -47,7 +47,7 @@ class FiberTest < MiniTest::Test
|
|
47
47
|
f1 = spin { :foo }
|
48
48
|
f2 = spin { :bar }
|
49
49
|
4.times { snooze }
|
50
|
-
|
50
|
+
|
51
51
|
assert_equal [:foo, :bar], Fiber.await(f1, f2)
|
52
52
|
end
|
53
53
|
|
@@ -739,7 +739,7 @@ class FiberTest < MiniTest::Test
|
|
739
739
|
def test_setup_raw
|
740
740
|
buffer = []
|
741
741
|
f = Fiber.new { buffer << receive }
|
742
|
-
|
742
|
+
|
743
743
|
assert_nil f.thread
|
744
744
|
snooze
|
745
745
|
f.setup_raw
|
@@ -771,10 +771,11 @@ class FiberTest < MiniTest::Test
|
|
771
771
|
|
772
772
|
snooze
|
773
773
|
assert_equal parent, child.parent
|
774
|
-
child.detach
|
774
|
+
result = child.detach
|
775
|
+
assert_equal result, child
|
775
776
|
assert_equal Fiber.current, child.parent
|
776
777
|
parent.await
|
777
|
-
|
778
|
+
|
778
779
|
child << :bye
|
779
780
|
child.await
|
780
781
|
|
@@ -807,7 +808,7 @@ class FiberTest < MiniTest::Test
|
|
807
808
|
child.attach_to(new_parent)
|
808
809
|
assert_equal new_parent, child.parent
|
809
810
|
parent.await
|
810
|
-
|
811
|
+
|
811
812
|
child << :bye
|
812
813
|
new_parent << :bye_new_parent
|
813
814
|
snooze
|
@@ -820,6 +821,29 @@ class FiberTest < MiniTest::Test
|
|
820
821
|
:bye_new_parent
|
821
822
|
], buf
|
822
823
|
end
|
824
|
+
|
825
|
+
def test_attach_all_children_to
|
826
|
+
children = []
|
827
|
+
f1 = spin do
|
828
|
+
3.times {
|
829
|
+
children << spin { receive }
|
830
|
+
}
|
831
|
+
Fiber.current.parent << :ok
|
832
|
+
receive
|
833
|
+
end
|
834
|
+
|
835
|
+
result = receive
|
836
|
+
assert_equal :ok, result
|
837
|
+
assert_equal 3, children.size
|
838
|
+
|
839
|
+
f2 = spin { supervise }
|
840
|
+
f1.attach_all_children_to(f2)
|
841
|
+
|
842
|
+
snooze
|
843
|
+
|
844
|
+
assert_equal [], f1.children
|
845
|
+
assert_equal children, f2.children
|
846
|
+
end
|
823
847
|
end
|
824
848
|
|
825
849
|
class MailboxTest < MiniTest::Test
|
@@ -1126,7 +1150,7 @@ class RestartTest < MiniTest::Test
|
|
1126
1150
|
assert_equal [1], buffer
|
1127
1151
|
snooze
|
1128
1152
|
assert_equal [1, 1], buffer
|
1129
|
-
|
1153
|
+
|
1130
1154
|
f << 'foo'
|
1131
1155
|
sleep 0.1
|
1132
1156
|
assert_equal [1, 1, 2], buffer
|
@@ -1252,7 +1276,7 @@ class DebugTest < MiniTest::Test
|
|
1252
1276
|
assert_equal true, f.__parked__?
|
1253
1277
|
10.times { snooze }
|
1254
1278
|
assert_equal [], buf
|
1255
|
-
|
1279
|
+
|
1256
1280
|
f.__unpark__
|
1257
1281
|
assert_nil f.__parked__?
|
1258
1282
|
10.times { snooze }
|
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
|
|
@@ -280,7 +280,7 @@ class SpinLoopTest < MiniTest::Test
|
|
280
280
|
def test_spin_loop_location
|
281
281
|
location = /^#{__FILE__}:#{__LINE__ + 1}/
|
282
282
|
f = spin_loop { snooze }
|
283
|
-
|
283
|
+
|
284
284
|
assert_match location, f.location
|
285
285
|
end
|
286
286
|
|
@@ -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
|
@@ -402,7 +402,7 @@ class ThrottledLoopTest < MiniTest::Test
|
|
402
402
|
f.await
|
403
403
|
t1 = Time.now
|
404
404
|
assert_in_range 0.075..0.15, t1 - t0 if IS_LINUX
|
405
|
-
assert_equal [1, 2, 3, 4, 5], buffer
|
405
|
+
assert_equal [1, 2, 3, 4, 5], buffer
|
406
406
|
end
|
407
407
|
end
|
408
408
|
|
@@ -412,13 +412,11 @@ 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
|
|
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,14 +424,25 @@ 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
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_every_with_slow_op
|
431
|
+
buffer = []
|
432
|
+
t0 = Time.now
|
433
|
+
f = spin do
|
434
|
+
every(0.01) { sleep 0.05; buffer << 1 }
|
435
|
+
end
|
436
|
+
sleep 0.15
|
437
|
+
f.stop
|
438
|
+
assert_in_range 2..3, buffer.size if IS_LINUX
|
430
439
|
end
|
431
440
|
|
432
441
|
def test_sleep
|
433
442
|
t0 = Time.now
|
434
443
|
sleep 0.1
|
435
444
|
elapsed = Time.now - t0
|
436
|
-
|
445
|
+
assert_in_range 0.05..0.15, elapsed if IS_LINUX
|
437
446
|
|
438
447
|
f = spin { sleep }
|
439
448
|
snooze
|
data/test/test_io.rb
CHANGED
@@ -107,10 +107,10 @@ class IOTest < MiniTest::Test
|
|
107
107
|
sleep 0.01
|
108
108
|
o << 'hi'
|
109
109
|
}
|
110
|
-
assert_equal 'hi', i.readpartial(2)
|
110
|
+
assert_equal 'hi', i.readpartial(2)
|
111
111
|
o.close
|
112
112
|
|
113
|
-
assert_raises(EOFError) { i.readpartial(1) }
|
113
|
+
assert_raises(EOFError) { i.readpartial(1) }
|
114
114
|
end
|
115
115
|
|
116
116
|
def test_gets
|
@@ -132,7 +132,7 @@ class IOTest < MiniTest::Test
|
|
132
132
|
f << Fiber.current
|
133
133
|
sleep 0.05
|
134
134
|
assert_equal [], buf
|
135
|
-
|
135
|
+
|
136
136
|
o << "ulous\n"
|
137
137
|
receive
|
138
138
|
assert_equal ["fabulous\n"], buf
|
@@ -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_queue.rb
CHANGED
@@ -70,7 +70,7 @@ class QueueTest < MiniTest::Test
|
|
70
70
|
|
71
71
|
def test_empty?
|
72
72
|
assert @queue.empty?
|
73
|
-
|
73
|
+
|
74
74
|
@queue << :foo
|
75
75
|
assert !@queue.empty?
|
76
76
|
|
@@ -82,7 +82,7 @@ class QueueTest < MiniTest::Test
|
|
82
82
|
f1 = spin { @queue.shift }
|
83
83
|
f2 = spin { @queue.shift }
|
84
84
|
f3 = spin { @queue.shift }
|
85
|
-
|
85
|
+
|
86
86
|
# let fibers run
|
87
87
|
snooze
|
88
88
|
|
@@ -99,7 +99,7 @@ class QueueTest < MiniTest::Test
|
|
99
99
|
|
100
100
|
def test_fiber_removal_from_queue_simple
|
101
101
|
f1 = spin { @queue.shift }
|
102
|
-
|
102
|
+
|
103
103
|
# let fibers run
|
104
104
|
snooze
|
105
105
|
|
@@ -114,11 +114,11 @@ class QueueTest < MiniTest::Test
|
|
114
114
|
assert_equal 0, @queue.size
|
115
115
|
|
116
116
|
@queue.push 1
|
117
|
-
|
117
|
+
|
118
118
|
assert_equal 1, @queue.size
|
119
119
|
|
120
120
|
@queue.push 2
|
121
|
-
|
121
|
+
|
122
122
|
assert_equal 2, @queue.size
|
123
123
|
|
124
124
|
@queue.shift
|
@@ -231,7 +231,7 @@ class CappedQueueTest < MiniTest::Test
|
|
231
231
|
i = 0
|
232
232
|
spin_loop do
|
233
233
|
i += 1
|
234
|
-
snooze
|
234
|
+
snooze
|
235
235
|
end
|
236
236
|
|
237
237
|
5.times { snooze }
|
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
|
data/test/test_socket.rb
CHANGED
@@ -9,9 +9,16 @@ class SocketTest < MiniTest::Test
|
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
12
|
+
def start_tcp_server_on_random_port(host = '127.0.0.1')
|
13
|
+
port = rand(1100..60000)
|
14
|
+
server = TCPServer.new(host, port)
|
15
|
+
[port, server]
|
16
|
+
rescue Errno::EADDRINUSE
|
17
|
+
retry
|
18
|
+
end
|
19
|
+
|
12
20
|
def test_tcp
|
13
|
-
port =
|
14
|
-
server = TCPServer.new('127.0.0.1', port)
|
21
|
+
port, server = start_tcp_server_on_random_port
|
15
22
|
server_fiber = spin do
|
16
23
|
while (socket = server.accept)
|
17
24
|
spin do
|
@@ -33,9 +40,41 @@ class SocketTest < MiniTest::Test
|
|
33
40
|
server&.close
|
34
41
|
end
|
35
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
|
+
|
36
76
|
def test_read
|
37
|
-
port =
|
38
|
-
server = TCPServer.new('127.0.0.1', port)
|
77
|
+
port, server = start_tcp_server_on_random_port
|
39
78
|
server_fiber = spin do
|
40
79
|
while (socket = server.accept)
|
41
80
|
spin do
|
@@ -74,9 +113,7 @@ class SocketTest < MiniTest::Test
|
|
74
113
|
|
75
114
|
# sending multiple strings at once
|
76
115
|
def test_sendv
|
77
|
-
port =
|
78
|
-
server = TCPServer.new('127.0.0.1', port)
|
79
|
-
|
116
|
+
port, server = start_tcp_server_on_random_port
|
80
117
|
server_fiber = spin do
|
81
118
|
while (socket = server.accept)
|
82
119
|
spin do
|
@@ -100,9 +137,7 @@ class SocketTest < MiniTest::Test
|
|
100
137
|
|
101
138
|
|
102
139
|
def test_feed_loop
|
103
|
-
port =
|
104
|
-
server = TCPServer.new('127.0.0.1', port)
|
105
|
-
|
140
|
+
port, server = start_tcp_server_on_random_port
|
106
141
|
server_fiber = spin do
|
107
142
|
reader = MessagePack::Unpacker.new
|
108
143
|
while (socket = server.accept)
|
data/test/test_supervise.rb
CHANGED
@@ -135,6 +135,44 @@ class SuperviseTest < MiniTest::Test
|
|
135
135
|
assert_equal supervisor, f3.parent
|
136
136
|
end
|
137
137
|
|
138
|
+
def test_supervise_with_restart_true
|
139
|
+
buffer = []
|
140
|
+
f1 = spin(:f1) do
|
141
|
+
buffer << receive
|
142
|
+
rescue => e
|
143
|
+
buffer << e
|
144
|
+
e
|
145
|
+
end
|
146
|
+
supervisor = spin(:supervisor) { supervise(f1, restart: true) }
|
147
|
+
|
148
|
+
snooze
|
149
|
+
f1 << 'foo'
|
150
|
+
f1.await
|
151
|
+
snooze
|
152
|
+
assert_equal ['foo'], buffer
|
153
|
+
|
154
|
+
10.times { snooze }
|
155
|
+
|
156
|
+
assert_equal 1, supervisor.children.size
|
157
|
+
f2 = supervisor.children.first
|
158
|
+
assert f1 != f2
|
159
|
+
assert_equal :f1, f2.tag
|
160
|
+
assert_equal supervisor, f2.parent
|
161
|
+
|
162
|
+
e = RuntimeError.new('bar')
|
163
|
+
f2.raise(e)
|
164
|
+
f2.await rescue nil
|
165
|
+
3.times { snooze }
|
166
|
+
assert_equal ['foo', e], buffer
|
167
|
+
|
168
|
+
assert_equal 1, supervisor.children.size
|
169
|
+
f3 = supervisor.children.first
|
170
|
+
assert f2 != f3
|
171
|
+
assert f1 != f3
|
172
|
+
assert_equal :f1, f3.tag
|
173
|
+
assert_equal supervisor, f3.parent
|
174
|
+
end
|
175
|
+
|
138
176
|
def test_supervise_with_restart_on_error
|
139
177
|
buffer = []
|
140
178
|
f1 = spin(:f1) do
|
@@ -184,4 +222,51 @@ class SuperviseTest < MiniTest::Test
|
|
184
222
|
|
185
223
|
assert_equal [], buffer
|
186
224
|
end
|
225
|
+
|
226
|
+
def test_supervise_without_explicit_fibers
|
227
|
+
buffer = []
|
228
|
+
first = nil
|
229
|
+
supervisor = spin do
|
230
|
+
3.times do |i|
|
231
|
+
f = spin do
|
232
|
+
first = Fiber.current if i == 0
|
233
|
+
receive
|
234
|
+
buffer << i
|
235
|
+
end
|
236
|
+
end
|
237
|
+
Fiber.current.parent << :ok
|
238
|
+
supervise(restart: :always)
|
239
|
+
end
|
240
|
+
msg = receive
|
241
|
+
assert_equal :ok, msg
|
242
|
+
assert_equal 3, supervisor.children.size
|
243
|
+
|
244
|
+
sleep 0.1
|
245
|
+
assert_equal [], buffer
|
246
|
+
|
247
|
+
old_first = first
|
248
|
+
first << :foo
|
249
|
+
first = nil
|
250
|
+
snooze
|
251
|
+
assert_equal [0], buffer
|
252
|
+
|
253
|
+
snooze
|
254
|
+
assert_equal 3, supervisor.children.size
|
255
|
+
snooze
|
256
|
+
assert first
|
257
|
+
assert first != old_first
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_supervise_with_added_fibers
|
261
|
+
buffer = []
|
262
|
+
supervisor = spin do
|
263
|
+
supervise { |f, r| buffer << [f, r] }
|
264
|
+
end
|
265
|
+
snooze
|
266
|
+
f1 = supervisor.spin { snooze; :foo }
|
267
|
+
f2 = supervisor.spin { snooze; :bar }
|
268
|
+
Fiber.await(f1, f2)
|
269
|
+
snooze
|
270
|
+
assert_equal [[f1, :foo], [f2, :bar]], buffer
|
271
|
+
end
|
187
272
|
end
|
data/test/test_sync.rb
CHANGED
data/test/test_thread.rb
CHANGED
@@ -180,7 +180,7 @@ class ThreadTest < MiniTest::Test
|
|
180
180
|
assert_equal count, GC.count
|
181
181
|
sleep 0.05
|
182
182
|
assert_equal count, GC.count
|
183
|
-
|
183
|
+
|
184
184
|
return unless IS_LINUX
|
185
185
|
|
186
186
|
# The idle tasks are ran at most once per fiber switch, before the backend
|
@@ -207,7 +207,7 @@ class ThreadTest < MiniTest::Test
|
|
207
207
|
counter = 0
|
208
208
|
|
209
209
|
Thread.current.on_idle { counter += 1 }
|
210
|
-
|
210
|
+
|
211
211
|
3.times { snooze }
|
212
212
|
assert_equal 0, counter
|
213
213
|
|
@@ -220,4 +220,24 @@ class ThreadTest < MiniTest::Test
|
|
220
220
|
3.times { snooze }
|
221
221
|
assert_equal 2, counter
|
222
222
|
end
|
223
|
+
|
224
|
+
def test_cross_thread_receive
|
225
|
+
buf = []
|
226
|
+
f = Fiber.current
|
227
|
+
t = Thread.new do
|
228
|
+
f << true
|
229
|
+
while (msg = receive)
|
230
|
+
buf << msg
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
receive # wait for thread to be ready
|
235
|
+
t << 1
|
236
|
+
t << 2
|
237
|
+
t << 3
|
238
|
+
t << nil
|
239
|
+
|
240
|
+
t.join
|
241
|
+
assert_equal [1, 2, 3], buf
|
242
|
+
end
|
223
243
|
end
|