uringmachine 0.19 → 0.20.0
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/CHANGELOG.md +15 -0
- data/TODO.md +40 -0
- data/examples/bm_fileno.rb +33 -0
- data/examples/bm_mutex.rb +85 -0
- data/examples/bm_mutex_single.rb +33 -0
- data/examples/bm_queue.rb +27 -28
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/fiber_scheduler_demo.rb +15 -51
- data/examples/fiber_scheduler_fork.rb +24 -0
- data/examples/nc_ssl.rb +71 -0
- data/ext/um/extconf.rb +5 -15
- data/ext/um/um.c +73 -42
- data/ext/um/um.h +21 -11
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +94 -23
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_queue_class.c +1 -1
- data/ext/um/um_stream.c +5 -5
- data/ext/um/um_stream_class.c +3 -0
- data/ext/um/um_sync.c +22 -27
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +229 -0
- data/grant-2025/tasks.md +66 -0
- data/lib/uringmachine/fiber_scheduler.rb +180 -48
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +138 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +451 -33
- data/vendor/liburing/.github/workflows/ci.yml +94 -1
- data/vendor/liburing/.github/workflows/test_build.c +9 -0
- data/vendor/liburing/configure +27 -0
- data/vendor/liburing/examples/Makefile +6 -0
- data/vendor/liburing/examples/helpers.c +8 -0
- data/vendor/liburing/examples/helpers.h +5 -0
- data/vendor/liburing/liburing.spec +1 -1
- data/vendor/liburing/src/Makefile +9 -3
- data/vendor/liburing/src/include/liburing/barrier.h +11 -5
- data/vendor/liburing/src/include/liburing/io_uring/query.h +41 -0
- data/vendor/liburing/src/include/liburing/io_uring.h +50 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +445 -121
- data/vendor/liburing/src/liburing-ffi.map +15 -0
- data/vendor/liburing/src/liburing.map +8 -0
- data/vendor/liburing/src/sanitize.c +4 -1
- data/vendor/liburing/src/setup.c +7 -4
- data/vendor/liburing/test/232c93d07b74.c +4 -16
- data/vendor/liburing/test/Makefile +15 -1
- data/vendor/liburing/test/accept.c +2 -13
- data/vendor/liburing/test/conn-unreach.c +132 -0
- data/vendor/liburing/test/fd-pass.c +32 -7
- data/vendor/liburing/test/fdinfo.c +39 -12
- data/vendor/liburing/test/fifo-futex-poll.c +114 -0
- data/vendor/liburing/test/fifo-nonblock-read.c +1 -12
- data/vendor/liburing/test/futex.c +1 -1
- data/vendor/liburing/test/helpers.c +99 -2
- data/vendor/liburing/test/helpers.h +9 -0
- data/vendor/liburing/test/io_uring_passthrough.c +6 -12
- data/vendor/liburing/test/mock_file.c +379 -0
- data/vendor/liburing/test/mock_file.h +47 -0
- data/vendor/liburing/test/nop.c +2 -2
- data/vendor/liburing/test/nop32-overflow.c +150 -0
- data/vendor/liburing/test/nop32.c +126 -0
- data/vendor/liburing/test/pipe.c +166 -0
- data/vendor/liburing/test/poll-race-mshot.c +13 -1
- data/vendor/liburing/test/recv-mshot-fair.c +81 -34
- data/vendor/liburing/test/recvsend_bundle.c +1 -1
- data/vendor/liburing/test/resize-rings.c +2 -0
- data/vendor/liburing/test/ring-query.c +322 -0
- data/vendor/liburing/test/ringbuf-loop.c +87 -0
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +102 -32
- data/vendor/liburing/test/shutdown.c +2 -12
- data/vendor/liburing/test/socket-nb.c +3 -14
- data/vendor/liburing/test/socket-rw-eagain.c +2 -12
- data/vendor/liburing/test/socket-rw-offset.c +2 -12
- data/vendor/liburing/test/socket-rw.c +2 -12
- data/vendor/liburing/test/sqe-mixed-bad-wrap.c +87 -0
- data/vendor/liburing/test/sqe-mixed-nop.c +82 -0
- data/vendor/liburing/test/sqe-mixed-uring_cmd.c +153 -0
- data/vendor/liburing/test/timestamp.c +56 -19
- data/vendor/liburing/test/vec-regbuf.c +2 -4
- data/vendor/liburing/test/wq-aff.c +7 -0
- metadata +24 -2
|
@@ -1,32 +1,120 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
class UringMachine
|
|
4
|
+
# UringMachine::FiberScheduler implements the Fiber::Scheduler interface for
|
|
5
|
+
# creating fiber-based concurrent applications in Ruby, in tight integration
|
|
6
|
+
# with the standard Ruby I/O and locking APIs.
|
|
4
7
|
class FiberScheduler
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
attr_reader :machine, :fiber_map
|
|
9
|
+
|
|
10
|
+
# Instantiates a scheduler with the given UringMachine instance.
|
|
11
|
+
#
|
|
12
|
+
# machine = UM.new
|
|
13
|
+
# scheduler = UM::FiberScheduler.new(machine)
|
|
14
|
+
# Fiber.set_scheduler(scheduler)
|
|
15
|
+
#
|
|
16
|
+
# @param machine [UringMachine, nil] UringMachine instance
|
|
17
|
+
# @return [void]
|
|
18
|
+
def initialize(machine = nil)
|
|
19
|
+
@machine = machine || UM.new
|
|
20
|
+
@ios = ObjectSpace::WeakMap.new
|
|
21
|
+
@fiber_map = ObjectSpace::WeakMap.new
|
|
7
22
|
end
|
|
8
23
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
24
|
+
def instance_variables_to_inspect
|
|
25
|
+
[:@machine]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Should be called after a fork (eventually, we'll want Ruby to call this
|
|
29
|
+
# automatically after a fork).
|
|
30
|
+
#
|
|
31
|
+
# @return [self]
|
|
32
|
+
def post_fork
|
|
33
|
+
@machine = UM.new
|
|
34
|
+
@ios = ObjectSpace::WeakMap.new
|
|
35
|
+
@fiber_map = ObjectSpace::WeakMap.new
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# For debugging purposes
|
|
40
|
+
def method_missing(sym, *a, **b)
|
|
41
|
+
@machine.write(1, "method_missing: #{sym.inspect} #{a.inspect} #{b.inspect}\n")
|
|
42
|
+
@machine.write(1, "#{caller.inspect}\n")
|
|
43
|
+
super
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# scheduler_close hook: Waits for all fiber to terminate. Called upon thread
|
|
47
|
+
# termination or when the thread's fiber scheduler is changed.
|
|
48
|
+
#
|
|
49
|
+
# @return [void]
|
|
50
|
+
def scheduler_close
|
|
51
|
+
join()
|
|
13
52
|
end
|
|
14
53
|
|
|
15
|
-
|
|
16
|
-
|
|
54
|
+
# fiber_interrupt hook: to be implemented.
|
|
55
|
+
def fiber_interrupt(fiber, exception)
|
|
56
|
+
raise NotImplementedError, "Implement me!"
|
|
17
57
|
end
|
|
18
58
|
|
|
19
|
-
|
|
20
|
-
|
|
59
|
+
# For debugging purposes
|
|
60
|
+
def p(o) = UM.debug(o.inspect)
|
|
61
|
+
|
|
62
|
+
# Waits for the given fibers to terminate. If no fibers are given, waits for
|
|
63
|
+
# all fibers to terminate.
|
|
64
|
+
#
|
|
65
|
+
# @param fibers [Array<Fiber>] fibers to terminate
|
|
66
|
+
# @return [void]
|
|
67
|
+
def join(*fibers)
|
|
68
|
+
if fibers.empty?
|
|
69
|
+
fibers = @fiber_map.keys
|
|
70
|
+
@fiber_map = ObjectSpace::WeakMap.new
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
@machine.join(*fibers)
|
|
74
|
+
end
|
|
21
75
|
|
|
76
|
+
# blocking_operation_wait hook: runs the given operation in a separate
|
|
77
|
+
# thread, so as not to block other fibers.
|
|
78
|
+
#
|
|
79
|
+
# @param blocking_operation [callable] blocking operation
|
|
80
|
+
# @return [void]
|
|
81
|
+
def blocking_operation_wait(blocking_operation)
|
|
82
|
+
start_blocking_operation_thread if !@blocking_op_queue
|
|
83
|
+
|
|
84
|
+
queue = UM::Queue.new
|
|
85
|
+
@machine.push(@blocking_op_queue, [queue, blocking_operation])
|
|
86
|
+
@machine.shift(queue)
|
|
22
87
|
end
|
|
23
88
|
|
|
89
|
+
# block hook: blocks the current fiber by yielding to the machine. This hook
|
|
90
|
+
# is called when a synchronization mechanism blocks, e.g. a mutex, a queue,
|
|
91
|
+
# etc.
|
|
92
|
+
#
|
|
93
|
+
# @param blocker [any] blocker object
|
|
94
|
+
# @param timeout [Number, nil] optional
|
|
95
|
+
# timeout @return [void]
|
|
96
|
+
def block(blocker, timeout = nil)
|
|
97
|
+
raise NotImplementedError, "Implement me!" if timeout
|
|
98
|
+
|
|
99
|
+
@machine.yield
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# unblock hook: unblocks the given fiber by scheduling it. This hook is
|
|
103
|
+
# called when a synchronization mechanism unblocks, e.g. a mutex, a queue,
|
|
104
|
+
# etc.
|
|
105
|
+
#
|
|
106
|
+
# @param blocker [any] blocker object
|
|
107
|
+
# @param fiber [Fiber] fiber to resume
|
|
108
|
+
# @return [void]
|
|
24
109
|
def unblock(blocker, fiber)
|
|
25
|
-
|
|
110
|
+
@machine.schedule(fiber, nil)
|
|
26
111
|
end
|
|
27
112
|
|
|
113
|
+
# kernel_sleep hook: sleeps for the given duration.
|
|
114
|
+
#
|
|
115
|
+
# @param duration [Number, nil] sleep duration
|
|
116
|
+
# @return [void]
|
|
28
117
|
def kernel_sleep(duration = nil)
|
|
29
|
-
# p sleep: [duration]
|
|
30
118
|
if duration
|
|
31
119
|
@machine.sleep(duration)
|
|
32
120
|
else
|
|
@@ -34,17 +122,19 @@ class UringMachine
|
|
|
34
122
|
end
|
|
35
123
|
end
|
|
36
124
|
|
|
125
|
+
# io_wait hook: waits for the given io to become ready.
|
|
126
|
+
#
|
|
127
|
+
# @param io [IO] IO object
|
|
128
|
+
# @param events [Number] readiness bitmask
|
|
129
|
+
# @param timeout [Number, nil] optional timeout
|
|
130
|
+
# @param return
|
|
37
131
|
def io_wait(io, events, timeout = nil)
|
|
38
132
|
timeout ||= io.timeout
|
|
39
|
-
p timeout: timeout
|
|
40
133
|
if timeout
|
|
41
|
-
p 1
|
|
42
134
|
@machine.timeout(timeout, Timeout::Error) {
|
|
43
|
-
p 2
|
|
44
135
|
@machine.poll(io.fileno, events).tap { p 3 }
|
|
45
|
-
|
|
136
|
+
}
|
|
46
137
|
else
|
|
47
|
-
p 5
|
|
48
138
|
@machine.poll(io.fileno, events).tap { p 6 }
|
|
49
139
|
|
|
50
140
|
end
|
|
@@ -53,52 +143,94 @@ class UringMachine
|
|
|
53
143
|
raise
|
|
54
144
|
end
|
|
55
145
|
|
|
146
|
+
# fiber hook: creates a new fiber with the given block. The created fiber is
|
|
147
|
+
# added to the fiber map, scheduled on the scheduler machine, and started
|
|
148
|
+
# before this method returns (by calling snooze).
|
|
149
|
+
#
|
|
150
|
+
# @param block [Proc] fiber block @return [Fiber]
|
|
56
151
|
def fiber(&block)
|
|
57
|
-
|
|
152
|
+
fiber = Fiber.new(blocking: false) { @machine.run(fiber, &block) }
|
|
153
|
+
@fiber_map[fiber] = true
|
|
154
|
+
@machine.schedule(fiber, nil)
|
|
58
155
|
@machine.snooze
|
|
59
|
-
|
|
156
|
+
fiber
|
|
60
157
|
end
|
|
61
158
|
|
|
159
|
+
# io_write hook: writes to the given IO.
|
|
160
|
+
#
|
|
161
|
+
# @param io [IO] IO object
|
|
162
|
+
# @param buffer [IO::Buffer] write buffer
|
|
163
|
+
# @param length [Integer] write length
|
|
164
|
+
# @param offset [Integer] write offset
|
|
165
|
+
# @return [Integer] bytes written
|
|
62
166
|
def io_write(io, buffer, length, offset)
|
|
63
|
-
|
|
64
|
-
|
|
167
|
+
if offset > 0
|
|
168
|
+
raise NotImplementedError, "UringMachine currently does not support writing at an offset"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
ensure_nonblock(io)
|
|
172
|
+
@machine.write(io.fileno, buffer)
|
|
173
|
+
rescue Errno::EINTR
|
|
174
|
+
retry
|
|
65
175
|
end
|
|
66
176
|
|
|
177
|
+
# io_read hook: reads from the given IO.
|
|
178
|
+
#
|
|
179
|
+
# @param io [IO] IO object
|
|
180
|
+
# @param buffer [IO::Buffer] read buffer
|
|
181
|
+
# @param length [Integer] read length
|
|
182
|
+
# @param offset [Integer] read offset
|
|
183
|
+
# @return [Integer] bytes read
|
|
67
184
|
def io_read(io, buffer, length, offset)
|
|
68
|
-
|
|
69
|
-
|
|
185
|
+
if offset > 0
|
|
186
|
+
raise NotImplementedError, "UringMachine currently does not support reading at an offset"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
ensure_nonblock(io)
|
|
70
190
|
length = buffer.size if length == 0
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
rescue SystemCallError => e
|
|
75
|
-
-e.errno
|
|
191
|
+
@machine.read(io.fileno, buffer, length)
|
|
192
|
+
rescue Errno::EINTR
|
|
193
|
+
retry
|
|
76
194
|
end
|
|
77
195
|
|
|
78
|
-
|
|
79
|
-
|
|
196
|
+
if UM.instance_methods.include?(:waitid_status)
|
|
197
|
+
def process_wait(pid, flags)
|
|
198
|
+
flags = UM::WEXITED if flags == 0
|
|
199
|
+
@machine.waitid_status(UM::P_PID, pid, flags)
|
|
200
|
+
end
|
|
80
201
|
end
|
|
81
202
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
203
|
+
private
|
|
204
|
+
|
|
205
|
+
# Ensures the given IO is in blocking mode.
|
|
206
|
+
#
|
|
207
|
+
# @param io [IO] IO object
|
|
208
|
+
# @return [void]
|
|
209
|
+
def ensure_nonblock(io)
|
|
210
|
+
return if @ios.key?(io)
|
|
85
211
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
# # fiber.resume
|
|
90
|
-
# return fiber
|
|
91
|
-
# end
|
|
212
|
+
@ios[io] = true
|
|
213
|
+
UM.io_set_nonblock(io, false)
|
|
214
|
+
end
|
|
92
215
|
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
216
|
+
# Starts a background thread for running blocking operations.
|
|
217
|
+
#
|
|
218
|
+
# @return [void]
|
|
219
|
+
def start_blocking_operation_thread
|
|
220
|
+
@blocking_op_queue = UM::Queue.new
|
|
221
|
+
@blocking_op_thread = Thread.new do
|
|
222
|
+
m = UM.new
|
|
223
|
+
loop do
|
|
224
|
+
q, op = m.shift(@blocking_op_queue)
|
|
225
|
+
res = begin
|
|
226
|
+
op.()
|
|
227
|
+
rescue Exception => e
|
|
228
|
+
e
|
|
229
|
+
end
|
|
230
|
+
m.push(q, res)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
96
234
|
|
|
97
|
-
# def process_wait(pid, flags)
|
|
98
|
-
# # This is a very simple way to implement a non-blocking wait:
|
|
99
|
-
# Thread.new do
|
|
100
|
-
# Process::Status.wait(pid, flags)
|
|
101
|
-
# end.value
|
|
102
|
-
# end
|
|
103
235
|
end
|
|
104
236
|
end
|
data/lib/uringmachine/version.rb
CHANGED
data/lib/uringmachine.rb
CHANGED
|
@@ -23,6 +23,12 @@ class UringMachine
|
|
|
23
23
|
@@fiber_map[fiber] = fiber
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def run(fiber, &block)
|
|
27
|
+
run_block_in_fiber(block, fiber, nil)
|
|
28
|
+
self.schedule(fiber, nil)
|
|
29
|
+
@@fiber_map[fiber] = fiber
|
|
30
|
+
end
|
|
31
|
+
|
|
26
32
|
def join(*fibers)
|
|
27
33
|
results = fibers.inject({}) { |h, f| h[f] = nil; h }
|
|
28
34
|
queue = nil
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'helper'
|
|
4
|
+
require 'uringmachine/fiber_scheduler'
|
|
5
|
+
|
|
6
|
+
class FiberSchedulerTest < UMBaseTest
|
|
7
|
+
def setup
|
|
8
|
+
super
|
|
9
|
+
@scheduler = UM::FiberScheduler.new(@machine)
|
|
10
|
+
Fiber.set_scheduler(@scheduler)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def teardown
|
|
14
|
+
Fiber.set_scheduler(nil)
|
|
15
|
+
GC.start
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def test_fiber_scheduler_initialize_without_machine
|
|
19
|
+
s = UM::FiberScheduler.new
|
|
20
|
+
assert_kind_of UringMachine, s.machine
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_fiber_scheduler_post_fork
|
|
24
|
+
Fiber.schedule {}
|
|
25
|
+
assert_equal 1, @scheduler.fiber_map.size
|
|
26
|
+
|
|
27
|
+
machine_before = @scheduler.machine
|
|
28
|
+
@scheduler.post_fork
|
|
29
|
+
refute_equal machine_before, @scheduler.machine
|
|
30
|
+
assert_equal 0, @scheduler.fiber_map.size
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_fiber_scheduler_spinning
|
|
34
|
+
f1 = Fiber.schedule do
|
|
35
|
+
sleep 0.001
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
f2 = Fiber.schedule do
|
|
39
|
+
sleep 0.001
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
assert_kind_of Fiber, f1
|
|
43
|
+
assert_kind_of Fiber, f2
|
|
44
|
+
assert_equal 2, @scheduler.fiber_map.size
|
|
45
|
+
|
|
46
|
+
# close scheduler
|
|
47
|
+
Fiber.set_scheduler nil
|
|
48
|
+
GC.start
|
|
49
|
+
assert_equal 0, @scheduler.fiber_map.size
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_fiber_scheduler_basic_io
|
|
53
|
+
i, o = IO.pipe
|
|
54
|
+
buffer = []
|
|
55
|
+
|
|
56
|
+
f1 = Fiber.schedule do
|
|
57
|
+
sleep 0.001
|
|
58
|
+
o.write 'foo'
|
|
59
|
+
buffer << :f1
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
f2 = Fiber.schedule do
|
|
63
|
+
sleep 0.002
|
|
64
|
+
o.write 'bar'
|
|
65
|
+
buffer << :f2
|
|
66
|
+
o.close
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
f3 = Fiber.schedule do
|
|
70
|
+
str = i.read
|
|
71
|
+
buffer << str
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
@scheduler.join
|
|
75
|
+
assert_equal [true] * 3, [f1, f2, f3].map(&:done?)
|
|
76
|
+
assert_equal [:f1, :f2, 'foobar'], buffer
|
|
77
|
+
ensure
|
|
78
|
+
i.close rescue nil
|
|
79
|
+
o.close rescue nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_fiber_scheduler_sleep
|
|
83
|
+
t0 = monotonic_clock
|
|
84
|
+
assert_equal 0, machine.pending_count
|
|
85
|
+
Fiber.schedule do
|
|
86
|
+
sleep(0.01)
|
|
87
|
+
end
|
|
88
|
+
Fiber.schedule do
|
|
89
|
+
sleep(0.02)
|
|
90
|
+
end
|
|
91
|
+
assert_equal 2, machine.pending_count
|
|
92
|
+
@scheduler.join
|
|
93
|
+
t1 = monotonic_clock
|
|
94
|
+
assert_in_range 0.02..0.025, t1 - t0
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_fiber_scheduler_lock
|
|
98
|
+
mutex = Mutex.new
|
|
99
|
+
buffer = []
|
|
100
|
+
t0 = monotonic_clock
|
|
101
|
+
Fiber.schedule do
|
|
102
|
+
10.times { sleep 0.001; buffer << it }
|
|
103
|
+
end
|
|
104
|
+
Fiber.schedule do
|
|
105
|
+
mutex.synchronize { sleep(0.005) }
|
|
106
|
+
end
|
|
107
|
+
Fiber.schedule do
|
|
108
|
+
mutex.synchronize { sleep(0.005) }
|
|
109
|
+
end
|
|
110
|
+
@scheduler.join
|
|
111
|
+
t1 = monotonic_clock
|
|
112
|
+
assert_in_range 0.01..0.015, t1 - t0
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def test_fiber_scheduler_process_wait
|
|
116
|
+
child_pid = nil
|
|
117
|
+
status = nil
|
|
118
|
+
f1 = Fiber.schedule do
|
|
119
|
+
child_pid = fork {
|
|
120
|
+
Fiber.scheduler.post_fork
|
|
121
|
+
Fiber.set_scheduler nil
|
|
122
|
+
sleep(0.01);
|
|
123
|
+
exit! 42
|
|
124
|
+
}
|
|
125
|
+
status = Process::Status.wait(child_pid)
|
|
126
|
+
rescue => e
|
|
127
|
+
p e
|
|
128
|
+
end
|
|
129
|
+
@scheduler.join(f1)
|
|
130
|
+
assert_kind_of Process::Status, status
|
|
131
|
+
assert_equal child_pid, status.pid
|
|
132
|
+
assert_equal 42, status.exitstatus
|
|
133
|
+
ensure
|
|
134
|
+
if child_pid
|
|
135
|
+
Process.wait(child_pid) rescue nil
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
data/test/test_stream.rb
CHANGED
|
@@ -110,12 +110,12 @@ class StreamRespTest < StreamBaseTest
|
|
|
110
110
|
|
|
111
111
|
machine.write(@wfd, "-foobar\r\n")
|
|
112
112
|
o = @stream.resp_decode
|
|
113
|
-
assert_kind_of
|
|
113
|
+
assert_kind_of UM::Stream::RESPError, o
|
|
114
114
|
assert_equal "foobar", o.message
|
|
115
115
|
|
|
116
116
|
machine.write(@wfd, "!3\r\nbaz\r\n")
|
|
117
117
|
o = @stream.resp_decode
|
|
118
|
-
assert_kind_of
|
|
118
|
+
assert_kind_of UM::Stream::RESPError, o
|
|
119
119
|
assert_equal "baz", o.message
|
|
120
120
|
|
|
121
121
|
machine.write(@wfd, ":123\r\n")
|