uringmachine 0.19.1 → 0.21.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/.github/workflows/test.yml +3 -4
- data/CHANGELOG.md +32 -1
- data/TODO.md +0 -39
- 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 +29 -29
- data/examples/bm_send.rb +2 -5
- data/examples/bm_snooze.rb +20 -42
- data/examples/bm_write.rb +4 -1
- 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 +310 -74
- data/ext/um/um.h +66 -29
- data/ext/um/um_async_op.c +1 -1
- data/ext/um/um_async_op_class.c +2 -2
- data/ext/um/um_buffer.c +1 -1
- data/ext/um/um_class.c +178 -31
- data/ext/um/um_const.c +51 -3
- data/ext/um/um_mutex_class.c +1 -1
- data/ext/um/um_op.c +37 -0
- 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 +28 -39
- data/ext/um/um_utils.c +59 -19
- data/grant-2025/journal.md +353 -0
- data/grant-2025/tasks.md +135 -0
- data/lib/uringmachine/fiber_scheduler.rb +316 -57
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +6 -0
- data/test/test_fiber_scheduler.rb +640 -0
- data/test/test_stream.rb +2 -2
- data/test/test_um.rb +722 -54
- data/uringmachine.gemspec +5 -5
- 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 +51 -0
- data/vendor/liburing/src/include/liburing/sanitize.h +16 -4
- data/vendor/liburing/src/include/liburing.h +458 -121
- data/vendor/liburing/src/liburing-ffi.map +16 -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/bind-listen.c +175 -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/read-write.c +4 -4
- 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/ringbuf-read.c +4 -4
- data/vendor/liburing/test/runtests.sh +2 -2
- data/vendor/liburing/test/send-zerocopy.c +43 -5
- data/vendor/liburing/test/send_recv.c +103 -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 +37 -15
|
@@ -1,32 +1,182 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'resolv'
|
|
4
|
+
require 'etc'
|
|
5
|
+
|
|
3
6
|
class UringMachine
|
|
7
|
+
# Implements a thread pool for running blocking operations.
|
|
8
|
+
class BlockingOperationThreadPool
|
|
9
|
+
def initialize
|
|
10
|
+
@blocking_op_queue = UM::Queue.new
|
|
11
|
+
@pending_count = 0
|
|
12
|
+
@worker_count = 0
|
|
13
|
+
@max_workers = Etc.nprocessors
|
|
14
|
+
@worker_mutex = UM::Mutex.new
|
|
15
|
+
@workers = []
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def process(machine, job)
|
|
19
|
+
queue = UM::Queue.new
|
|
20
|
+
|
|
21
|
+
if @worker_count == 0 || (@pending_count > 0 && @worker_count < @max_workers)
|
|
22
|
+
start_worker(machine)
|
|
23
|
+
end
|
|
24
|
+
machine.push(@blocking_op_queue, [queue, job])
|
|
25
|
+
machine.shift(queue)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def start_worker(machine)
|
|
31
|
+
machine.synchronize(@worker_mutex) do
|
|
32
|
+
return if @worker_count == @max_workers
|
|
33
|
+
|
|
34
|
+
@workers << Thread.new { run_worker_thread }
|
|
35
|
+
@worker_count += 1
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def run_worker_thread
|
|
40
|
+
machine = UM.new(4).mark(1)
|
|
41
|
+
loop do
|
|
42
|
+
q, op = machine.shift(@blocking_op_queue)
|
|
43
|
+
@pending_count += 1
|
|
44
|
+
res = begin
|
|
45
|
+
op.()
|
|
46
|
+
rescue Exception => e
|
|
47
|
+
e
|
|
48
|
+
end
|
|
49
|
+
@pending_count -= 1
|
|
50
|
+
machine.push(q, res)
|
|
51
|
+
rescue => e
|
|
52
|
+
UM.debug("worker e: #{e.inspect}")
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# UringMachine::FiberScheduler implements the Fiber::Scheduler interface for
|
|
58
|
+
# creating fiber-based concurrent applications in Ruby, in tight integration
|
|
59
|
+
# with the standard Ruby I/O and locking APIs.
|
|
4
60
|
class FiberScheduler
|
|
5
|
-
|
|
6
|
-
|
|
61
|
+
@@blocking_operation_thread_pool = BlockingOperationThreadPool.new
|
|
62
|
+
|
|
63
|
+
attr_reader :machine, :fiber_map
|
|
64
|
+
|
|
65
|
+
# Instantiates a scheduler with the given UringMachine instance.
|
|
66
|
+
#
|
|
67
|
+
# machine = UM.new
|
|
68
|
+
# scheduler = UM::FiberScheduler.new(machine)
|
|
69
|
+
# Fiber.set_scheduler(scheduler)
|
|
70
|
+
#
|
|
71
|
+
# @param machine [UringMachine, nil] UringMachine instance
|
|
72
|
+
# @return [void]
|
|
73
|
+
def initialize(machine = nil)
|
|
74
|
+
@machine = machine || UM.new
|
|
75
|
+
@fiber_map = ObjectSpace::WeakMap.new
|
|
7
76
|
end
|
|
8
77
|
|
|
9
|
-
def
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
78
|
+
def instance_variables_to_inspect
|
|
79
|
+
[:@machine]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Should be called after a fork (eventually, we'll want Ruby to call this
|
|
83
|
+
# automatically after a fork).
|
|
84
|
+
#
|
|
85
|
+
# @return [self]
|
|
86
|
+
def process_fork
|
|
87
|
+
@machine = UM.new
|
|
88
|
+
@fiber_map = ObjectSpace::WeakMap.new
|
|
89
|
+
self
|
|
13
90
|
end
|
|
14
91
|
|
|
15
|
-
|
|
16
|
-
|
|
92
|
+
# For debugging purposes
|
|
93
|
+
def method_missing(sym, *a, **b)
|
|
94
|
+
@machine.write(1, "method_missing: #{sym.inspect} #{a.inspect} #{b.inspect}\n")
|
|
95
|
+
@machine.write(1, "#{caller.inspect}\n")
|
|
96
|
+
super
|
|
17
97
|
end
|
|
18
98
|
|
|
19
|
-
|
|
20
|
-
|
|
99
|
+
# scheduler_close hook: Waits for all fiber to terminate. Called upon thread
|
|
100
|
+
# termination or when the thread's fiber scheduler is changed.
|
|
101
|
+
#
|
|
102
|
+
# @return [void]
|
|
103
|
+
def scheduler_close
|
|
104
|
+
join()
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# For debugging purposes
|
|
108
|
+
def p(o) = UM.debug(o.inspect)
|
|
109
|
+
|
|
110
|
+
# Waits for the given fibers to terminate. If no fibers are given, waits for
|
|
111
|
+
# all fibers to terminate.
|
|
112
|
+
#
|
|
113
|
+
# @param fibers [Array<Fiber>] fibers to terminate
|
|
114
|
+
# @return [void]
|
|
115
|
+
def join(*fibers)
|
|
116
|
+
if fibers.empty?
|
|
117
|
+
fibers = @fiber_map.keys
|
|
118
|
+
@fiber_map = ObjectSpace::WeakMap.new
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
@machine.join(*fibers)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# blocking_operation_wait hook: runs the given operation in a separate
|
|
125
|
+
# thread, so as not to block other fibers.
|
|
126
|
+
#
|
|
127
|
+
# @param blocking_operation [callable] blocking operation
|
|
128
|
+
# @return [void]
|
|
129
|
+
def blocking_operation_wait(blocking_operation)
|
|
130
|
+
# naive_blocking_peration_wait(blocking_operation)
|
|
131
|
+
@@blocking_operation_thread_pool.process(@machine, blocking_operation)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def naive_blocking_peration_wait(blocking_operation)
|
|
135
|
+
res = nil
|
|
136
|
+
Thread.new do
|
|
137
|
+
res = blocking_operation.()
|
|
138
|
+
rescue => e
|
|
139
|
+
res = e
|
|
140
|
+
end.join
|
|
141
|
+
res
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# block hook: blocks the current fiber by yielding to the machine. This hook
|
|
145
|
+
# is called when a synchronization mechanism blocks, e.g. a mutex, a queue,
|
|
146
|
+
# etc.
|
|
147
|
+
#
|
|
148
|
+
# @param blocker [any] blocker object
|
|
149
|
+
# @param timeout [Number, nil] optional
|
|
150
|
+
# timeout @return [bool] was the operation successful
|
|
151
|
+
def block(blocker, timeout = nil)
|
|
152
|
+
if timeout
|
|
153
|
+
@machine.timeout(timeout, Timeout::Error) { @machine.yield }
|
|
154
|
+
else
|
|
155
|
+
@machine.yield
|
|
156
|
+
end
|
|
21
157
|
|
|
158
|
+
true
|
|
159
|
+
rescue Timeout::Error
|
|
160
|
+
false
|
|
22
161
|
end
|
|
23
162
|
|
|
163
|
+
# unblock hook: unblocks the given fiber by scheduling it. This hook is
|
|
164
|
+
# called when a synchronization mechanism unblocks, e.g. a mutex, a queue,
|
|
165
|
+
# etc.
|
|
166
|
+
#
|
|
167
|
+
# @param blocker [any] blocker object
|
|
168
|
+
# @param fiber [Fiber] fiber to resume
|
|
169
|
+
# @return [void]
|
|
24
170
|
def unblock(blocker, fiber)
|
|
25
|
-
|
|
171
|
+
@machine.schedule(fiber, nil)
|
|
172
|
+
@machine.wakeup
|
|
26
173
|
end
|
|
27
174
|
|
|
175
|
+
# kernel_sleep hook: sleeps for the given duration.
|
|
176
|
+
#
|
|
177
|
+
# @param duration [Number, nil] sleep duration
|
|
178
|
+
# @return [void]
|
|
28
179
|
def kernel_sleep(duration = nil)
|
|
29
|
-
# p sleep: [duration]
|
|
30
180
|
if duration
|
|
31
181
|
@machine.sleep(duration)
|
|
32
182
|
else
|
|
@@ -34,71 +184,180 @@ class UringMachine
|
|
|
34
184
|
end
|
|
35
185
|
end
|
|
36
186
|
|
|
187
|
+
# io_wait hook: waits for the given io to become ready.
|
|
188
|
+
#
|
|
189
|
+
# @param io [IO] IO object
|
|
190
|
+
# @param events [Number] readiness bitmask
|
|
191
|
+
# @param timeout [Number, nil] optional timeout
|
|
192
|
+
# @param return
|
|
37
193
|
def io_wait(io, events, timeout = nil)
|
|
38
194
|
timeout ||= io.timeout
|
|
39
|
-
p timeout: timeout
|
|
40
195
|
if timeout
|
|
41
|
-
p 1
|
|
42
196
|
@machine.timeout(timeout, Timeout::Error) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}.tap { p 4 }
|
|
197
|
+
@machine.poll(io.fileno, events)
|
|
198
|
+
}
|
|
46
199
|
else
|
|
47
|
-
|
|
48
|
-
|
|
200
|
+
@machine.poll(io.fileno, events)
|
|
201
|
+
end
|
|
202
|
+
end
|
|
49
203
|
|
|
204
|
+
def io_select(rios, wios, eios, timeout = nil)
|
|
205
|
+
map_r = map_io_fds(rios)
|
|
206
|
+
map_w = map_io_fds(wios)
|
|
207
|
+
map_e = map_io_fds(eios)
|
|
208
|
+
|
|
209
|
+
r, w, e = nil
|
|
210
|
+
if timeout
|
|
211
|
+
@machine.timeout(timeout, Timeout::Error) {
|
|
212
|
+
r, w, e = @machine.select(map_r.keys, map_w.keys, map_e.keys)
|
|
213
|
+
}
|
|
214
|
+
else
|
|
215
|
+
r, w, e = @machine.select(map_r.keys, map_w.keys, map_e.keys)
|
|
50
216
|
end
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
raise
|
|
217
|
+
|
|
218
|
+
[unmap_fds(r, map_r), unmap_fds(w, map_w), unmap_fds(e, map_e)]
|
|
54
219
|
end
|
|
55
220
|
|
|
221
|
+
# fiber hook: creates a new fiber with the given block. The created fiber is
|
|
222
|
+
# added to the fiber map, scheduled on the scheduler machine, and started
|
|
223
|
+
# before this method returns (by calling snooze).
|
|
224
|
+
#
|
|
225
|
+
# @param block [Proc] fiber block @return [Fiber]
|
|
56
226
|
def fiber(&block)
|
|
57
|
-
|
|
227
|
+
fiber = Fiber.new(blocking: false) { @machine.run(fiber, &block) }
|
|
228
|
+
@fiber_map[fiber] = true
|
|
229
|
+
@machine.schedule(fiber, nil)
|
|
58
230
|
@machine.snooze
|
|
59
|
-
|
|
231
|
+
fiber
|
|
60
232
|
end
|
|
61
233
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
234
|
+
# io_read hook: reads from the given IO.
|
|
235
|
+
#
|
|
236
|
+
# @param io [IO] IO object
|
|
237
|
+
# @param buffer [IO::Buffer] read buffer
|
|
238
|
+
# @param length [Integer] read length
|
|
239
|
+
# @param offset [Integer] buffer offset
|
|
240
|
+
# @return [Integer] bytes read
|
|
241
|
+
def io_read(io, buffer, length, offset)
|
|
242
|
+
length = buffer.size if length == 0
|
|
243
|
+
|
|
244
|
+
if (timeout = io.timeout)
|
|
245
|
+
@machine.timeout(timeout, Timeout::Error) do
|
|
246
|
+
@machine.read(io.fileno, buffer, length, offset)
|
|
247
|
+
rescue Errno::EINTR
|
|
248
|
+
retry
|
|
249
|
+
end
|
|
250
|
+
else
|
|
251
|
+
@machine.read(io.fileno, buffer, length, offset)
|
|
252
|
+
end
|
|
253
|
+
rescue Errno::EINTR
|
|
254
|
+
retry
|
|
65
255
|
end
|
|
66
256
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
257
|
+
# io_pread hook: reads from the given IO at the given offset
|
|
258
|
+
#
|
|
259
|
+
# @param io [IO] IO object
|
|
260
|
+
# @param buffer [IO::Buffer] read buffer
|
|
261
|
+
# @param from [Integer] read offset
|
|
262
|
+
# @param length [Integer] read length
|
|
263
|
+
# @param offset [Integer] buffer offset
|
|
264
|
+
# @return [Integer] bytes read
|
|
265
|
+
def io_pread(io, buffer, from, length, offset)
|
|
266
|
+
length = buffer.size if length == 0
|
|
267
|
+
|
|
268
|
+
if (timeout = io.timeout)
|
|
269
|
+
@machine.timeout(timeout, Timeout::Error) do
|
|
270
|
+
@machine.read(io.fileno, buffer, length, offset, from)
|
|
271
|
+
rescue Errno::EINTR
|
|
272
|
+
retry
|
|
273
|
+
end
|
|
274
|
+
else
|
|
275
|
+
@machine.read(io.fileno, buffer, length, offset, from)
|
|
276
|
+
end
|
|
277
|
+
rescue Errno::EINTR
|
|
278
|
+
retry
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# io_write hook: writes to the given IO.
|
|
282
|
+
#
|
|
283
|
+
# @param io [IO] IO object
|
|
284
|
+
# @param buffer [IO::Buffer] write buffer
|
|
285
|
+
# @param length [Integer] write length
|
|
286
|
+
# @param offset [Integer] write offset
|
|
287
|
+
# @return [Integer] bytes written
|
|
288
|
+
def io_write(io, buffer, length, offset)
|
|
289
|
+
# p(io_write: io, length:, offset:, timeout: io.timeout)
|
|
70
290
|
length = buffer.size if length == 0
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
291
|
+
buffer = buffer.slice(offset) if offset > 0
|
|
292
|
+
|
|
293
|
+
if (timeout = io.timeout)
|
|
294
|
+
@machine.timeout(timeout, Timeout::Error) do
|
|
295
|
+
@machine.write(io.fileno, buffer, length)
|
|
296
|
+
rescue Errno::EINTR
|
|
297
|
+
retry
|
|
298
|
+
end
|
|
299
|
+
else
|
|
300
|
+
@machine.write(io.fileno, buffer, length)
|
|
301
|
+
end
|
|
302
|
+
rescue Errno::EINTR
|
|
303
|
+
retry
|
|
76
304
|
end
|
|
77
305
|
|
|
306
|
+
# io_pwrite hook: writes to the given IO at the given offset.
|
|
307
|
+
#
|
|
308
|
+
# @param io [IO] IO object
|
|
309
|
+
# @param buffer [IO::Buffer] write buffer
|
|
310
|
+
# @param length [Integer] file offset
|
|
311
|
+
# @param length [Integer] write length
|
|
312
|
+
# @param offset [Integer] buffer offset
|
|
313
|
+
# @return [Integer] bytes written
|
|
78
314
|
def io_pwrite(io, buffer, from, length, offset)
|
|
79
|
-
p
|
|
315
|
+
# p(io_pwrite: io, from:, length:, offset:, timeout: io.timeout)
|
|
316
|
+
length = buffer.size if length == 0
|
|
317
|
+
buffer = buffer.slice(offset) if offset > 0
|
|
318
|
+
|
|
319
|
+
if (timeout = io.timeout)
|
|
320
|
+
@machine.timeout(timeout, Timeout::Error) do
|
|
321
|
+
@machine.write(io.fileno, buffer, length, from)
|
|
322
|
+
rescue Errno::EINTR
|
|
323
|
+
retry
|
|
324
|
+
end
|
|
325
|
+
else
|
|
326
|
+
@machine.write(io.fileno, buffer, length, from)
|
|
327
|
+
end
|
|
328
|
+
rescue Errno::EINTR
|
|
329
|
+
retry
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
if UM.method_defined?(:waitid_status)
|
|
333
|
+
def process_wait(pid, flags)
|
|
334
|
+
flags = UM::WEXITED if flags == 0
|
|
335
|
+
@machine.waitid_status(UM::P_PID, pid, flags)
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def fiber_interrupt(fiber, exception)
|
|
340
|
+
@machine.schedule(fiber, exception)
|
|
341
|
+
@machine.wakeup
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def address_resolve(hostname)
|
|
345
|
+
Resolv.getaddresses(hostname)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def timeout_after(duration, exception, message, &block)
|
|
349
|
+
@machine.timeout(duration, exception, &block)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
private
|
|
353
|
+
|
|
354
|
+
def map_io_fds(ios)
|
|
355
|
+
ios.each_with_object({}) { |io, h| h[io.fileno] = io }
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def unmap_fds(fds, map)
|
|
359
|
+
fds.map { map[it] }
|
|
80
360
|
end
|
|
81
361
|
|
|
82
|
-
def io_pread(io, buffer, from, length, offset)
|
|
83
|
-
p io_pread: [io, buffer, from, length, offset]
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# def fiber(&block)
|
|
87
|
-
# fiber = Fiber.new(blocking: false, &block)
|
|
88
|
-
# unblock(nil, fiber)
|
|
89
|
-
# # fiber.resume
|
|
90
|
-
# return fiber
|
|
91
|
-
# end
|
|
92
|
-
|
|
93
|
-
# def kernel_sleep(duration = nil)
|
|
94
|
-
# block(:sleep, duration)
|
|
95
|
-
# end
|
|
96
|
-
|
|
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
362
|
end
|
|
104
363
|
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
|