uringmachine 0.1 → 0.3
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 +12 -0
- data/Rakefile +1 -1
- data/ext/um/um.c +228 -38
- data/ext/um/um.h +36 -8
- data/ext/um/um_class.c +98 -31
- data/ext/um/um_ext.c +0 -6
- data/ext/um/um_op.c +70 -6
- data/ext/um/um_utils.c +51 -1
- data/lib/uringmachine/version.rb +3 -1
- data/lib/uringmachine.rb +0 -3
- data/test/helper.rb +5 -12
- data/test/test_um.rb +259 -13
- data/uringmachine.gemspec +1 -1
- metadata +2 -6
- data/ext/um/iou.h +0 -101
- data/ext/um/op_ctx.c +0 -138
- data/ext/um/ring.c +0 -755
- data/test/test_iou.rb +0 -876
data/test/test_iou.rb
DELETED
@@ -1,876 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'helper'
|
4
|
-
require 'socket'
|
5
|
-
|
6
|
-
class IOURingTest < IOURingBaseTest
|
7
|
-
def test_close
|
8
|
-
ring2 = IOU::Ring.new
|
9
|
-
refute ring2.closed?
|
10
|
-
|
11
|
-
ring2.close
|
12
|
-
assert ring2.closed?
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_pending_ops
|
16
|
-
assert_equal({}, ring.pending_ops)
|
17
|
-
|
18
|
-
id = ring.prep_timeout(interval: 1)
|
19
|
-
spec = ring.pending_ops[id].spec
|
20
|
-
assert_equal id, spec[:id]
|
21
|
-
assert_equal :timeout, spec[:op]
|
22
|
-
assert_equal 1, spec[:interval]
|
23
|
-
|
24
|
-
ring.prep_cancel(id)
|
25
|
-
ring.submit
|
26
|
-
ring.process_completions(true)
|
27
|
-
|
28
|
-
assert_nil ring.pending_ops[id]
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class PrepTimeoutTest < IOURingBaseTest
|
33
|
-
def test_prep_timeout
|
34
|
-
interval = 0.03
|
35
|
-
|
36
|
-
t0 = monotonic_clock
|
37
|
-
id = ring.prep_timeout(interval: interval)
|
38
|
-
assert_equal 1, id
|
39
|
-
|
40
|
-
ring.submit
|
41
|
-
c = ring.wait_for_completion
|
42
|
-
elapsed = monotonic_clock - t0
|
43
|
-
assert_in_range interval..(interval + 0.02), elapsed
|
44
|
-
|
45
|
-
assert_kind_of Hash, c
|
46
|
-
assert_equal id, c[:id]
|
47
|
-
assert_equal :timeout, c[:op]
|
48
|
-
assert_equal interval, c[:interval]
|
49
|
-
assert_equal (-Errno::ETIME::Errno), c[:result]
|
50
|
-
end
|
51
|
-
|
52
|
-
def test_prep_timeout_invalid_args
|
53
|
-
assert_raises(ArgumentError) { ring.prep_timeout() }
|
54
|
-
assert_raises(ArgumentError) { ring.prep_timeout(foo: 1) }
|
55
|
-
assert_raises(ArgumentError) { ring.prep_timeout(1) }
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class PrepCancelTest < IOURingBaseTest
|
60
|
-
def test_prep_cancel
|
61
|
-
interval = 15
|
62
|
-
timeout_id = ring.prep_timeout(interval: interval)
|
63
|
-
assert_equal 1, timeout_id
|
64
|
-
|
65
|
-
cancel_id = ring.prep_cancel(timeout_id)
|
66
|
-
assert_equal 2, cancel_id
|
67
|
-
|
68
|
-
ring.submit
|
69
|
-
c = ring.wait_for_completion
|
70
|
-
assert_equal cancel_id, c[:id]
|
71
|
-
assert_equal 0, c[:result]
|
72
|
-
|
73
|
-
c = ring.wait_for_completion
|
74
|
-
assert_equal timeout_id, c[:id]
|
75
|
-
assert_equal :timeout, c[:op]
|
76
|
-
assert_equal interval, c[:interval]
|
77
|
-
assert_equal (-Errno::ECANCELED::Errno), c[:result]
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_prep_cancel_kw
|
81
|
-
interval = 15
|
82
|
-
timeout_id = ring.prep_timeout(interval: interval)
|
83
|
-
assert_equal 1, timeout_id
|
84
|
-
|
85
|
-
cancel_id = ring.prep_cancel(id: timeout_id)
|
86
|
-
assert_equal 2, cancel_id
|
87
|
-
|
88
|
-
ring.submit
|
89
|
-
c = ring.wait_for_completion
|
90
|
-
assert_equal cancel_id, c[:id]
|
91
|
-
assert_equal 0, c[:result]
|
92
|
-
|
93
|
-
c = ring.wait_for_completion
|
94
|
-
assert_equal timeout_id, c[:id]
|
95
|
-
assert_equal :timeout, c[:op]
|
96
|
-
assert_equal interval, c[:interval]
|
97
|
-
assert_equal (-Errno::ECANCELED::Errno), c[:result]
|
98
|
-
end
|
99
|
-
|
100
|
-
def test_prep_cancel_invalid_args
|
101
|
-
assert_raises(ArgumentError) { ring.prep_cancel() }
|
102
|
-
assert_raises(ArgumentError) { ring.prep_cancel('foo') }
|
103
|
-
assert_raises(ArgumentError) { ring.prep_cancel({}) }
|
104
|
-
assert_raises(TypeError) { ring.prep_cancel(id: 'bar') }
|
105
|
-
end
|
106
|
-
|
107
|
-
def test_prep_cancel_invalid_id
|
108
|
-
cancel_id = ring.prep_cancel(id: 42)
|
109
|
-
assert_equal 1, cancel_id
|
110
|
-
|
111
|
-
ring.submit
|
112
|
-
c = ring.wait_for_completion
|
113
|
-
assert_equal cancel_id, c[:id]
|
114
|
-
assert_equal (-Errno::ENOENT::Errno), c[:result]
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
class PrepTimeoutMultishotTest < IOURingBaseTest
|
119
|
-
def test_prep_timeout_multishot
|
120
|
-
interval = 0.03
|
121
|
-
count = 0
|
122
|
-
cancelled = false
|
123
|
-
|
124
|
-
t0 = monotonic_clock
|
125
|
-
id = ring.prep_timeout(interval: interval, multishot: true) do |c|
|
126
|
-
case c[:result]
|
127
|
-
when (-Errno::ETIME::Errno)
|
128
|
-
count += 1
|
129
|
-
when (-Errno::ECANCELED::Errno)
|
130
|
-
cancelled = true
|
131
|
-
end
|
132
|
-
end
|
133
|
-
ring.submit
|
134
|
-
|
135
|
-
ring.process_completions(true)
|
136
|
-
elapsed = monotonic_clock - t0
|
137
|
-
assert_in_range interval..(interval + 0.02), elapsed
|
138
|
-
assert_equal 1, count
|
139
|
-
|
140
|
-
t0 = monotonic_clock
|
141
|
-
ring.process_completions(true)
|
142
|
-
elapsed = monotonic_clock - t0
|
143
|
-
assert_in_range (interval - 0.01)..(interval + 0.02), elapsed
|
144
|
-
assert_equal 2, count
|
145
|
-
|
146
|
-
t0 = monotonic_clock
|
147
|
-
ring.process_completions(true)
|
148
|
-
elapsed = monotonic_clock - t0
|
149
|
-
assert_in_range (interval - 0.01)..(interval + 0.02), elapsed
|
150
|
-
assert_equal 3, count
|
151
|
-
|
152
|
-
ring.prep_cancel(id)
|
153
|
-
ring.submit
|
154
|
-
ring.process_completions(true)
|
155
|
-
assert_equal true, cancelled
|
156
|
-
assert_equal 3, count
|
157
|
-
assert_nil ring.pending_ops[id]
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
class PrepWriteTest < IOURingBaseTest
|
162
|
-
def test_prep_write
|
163
|
-
r, w = IO.pipe
|
164
|
-
s = 'foobar'
|
165
|
-
|
166
|
-
id = ring.prep_write(fd: w.fileno, buffer: s)
|
167
|
-
assert_equal 1, id
|
168
|
-
|
169
|
-
ring.submit
|
170
|
-
c = ring.wait_for_completion
|
171
|
-
|
172
|
-
assert_kind_of Hash, c
|
173
|
-
assert_equal id, c[:id]
|
174
|
-
assert_equal :write, c[:op]
|
175
|
-
assert_equal w.fileno, c[:fd]
|
176
|
-
assert_equal s.bytesize, c[:result]
|
177
|
-
|
178
|
-
w.close
|
179
|
-
assert_equal s, r.read
|
180
|
-
end
|
181
|
-
|
182
|
-
def test_prep_write_with_len
|
183
|
-
r, w = IO.pipe
|
184
|
-
s = 'foobar'
|
185
|
-
|
186
|
-
id = ring.prep_write(fd: w.fileno, buffer: s, len: 3)
|
187
|
-
assert_equal 1, id
|
188
|
-
|
189
|
-
ring.submit
|
190
|
-
c = ring.wait_for_completion
|
191
|
-
|
192
|
-
assert_kind_of Hash, c
|
193
|
-
assert_equal id, c[:id]
|
194
|
-
assert_equal :write, c[:op]
|
195
|
-
assert_equal w.fileno, c[:fd]
|
196
|
-
assert_equal 3, c[:result]
|
197
|
-
|
198
|
-
w.close
|
199
|
-
assert_equal s[0..2], r.read
|
200
|
-
end
|
201
|
-
|
202
|
-
def test_prep_write_invalid_args
|
203
|
-
assert_raises(ArgumentError) { ring.prep_write() }
|
204
|
-
assert_raises(ArgumentError) { ring.prep_write(foo: 1) }
|
205
|
-
assert_raises(ArgumentError) { ring.prep_write(fd: 'bar') }
|
206
|
-
assert_raises(ArgumentError) { ring.prep_write({}) }
|
207
|
-
end
|
208
|
-
|
209
|
-
def test_prep_write_invalid_fd
|
210
|
-
r, _w = IO.pipe
|
211
|
-
s = 'foobar'
|
212
|
-
|
213
|
-
id = ring.prep_write(fd: r.fileno, buffer: s)
|
214
|
-
assert_equal 1, id
|
215
|
-
|
216
|
-
ring.submit
|
217
|
-
c = ring.wait_for_completion
|
218
|
-
|
219
|
-
assert_kind_of Hash, c
|
220
|
-
assert_equal id, c[:id]
|
221
|
-
assert_equal :write, c[:op]
|
222
|
-
assert_equal r.fileno, c[:fd]
|
223
|
-
assert_equal (-Errno::EBADF::Errno), c[:result]
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
class PrepNopTest < IOURingBaseTest
|
228
|
-
def test_prep_nop
|
229
|
-
id = ring.prep_nop
|
230
|
-
assert_equal 1, id
|
231
|
-
|
232
|
-
ring.submit
|
233
|
-
c = ring.wait_for_completion
|
234
|
-
|
235
|
-
assert_kind_of Hash, c
|
236
|
-
assert_equal id, c[:id]
|
237
|
-
assert_nil c[:op]
|
238
|
-
assert_equal 0, c[:result]
|
239
|
-
end
|
240
|
-
|
241
|
-
def test_nop_as_signal
|
242
|
-
s1 = Queue.new
|
243
|
-
s2 = Queue.new
|
244
|
-
s3 = Queue.new
|
245
|
-
s4 = Queue.new
|
246
|
-
|
247
|
-
signaller = Thread.new do
|
248
|
-
s1.pop
|
249
|
-
id = ring.prep_nop
|
250
|
-
ring.submit
|
251
|
-
s2 << id
|
252
|
-
end
|
253
|
-
|
254
|
-
waiter = Thread.new do
|
255
|
-
s3.pop
|
256
|
-
s4 << ring.wait_for_completion
|
257
|
-
end
|
258
|
-
|
259
|
-
s3 << 'go'
|
260
|
-
s1 << 'go'
|
261
|
-
id = s2.pop
|
262
|
-
c = s4.pop
|
263
|
-
|
264
|
-
assert_kind_of Hash, c
|
265
|
-
assert_equal id, c[:id]
|
266
|
-
assert_nil c[:op]
|
267
|
-
assert_equal 0, c[:result]
|
268
|
-
ensure
|
269
|
-
signaller&.kill rescue nil
|
270
|
-
waiter&.kill rescue nil
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
class ProcessCompletionsTest < IOURingBaseTest
|
275
|
-
def test_process_completions_no_wait
|
276
|
-
ret = ring.process_completions
|
277
|
-
assert_equal 0, ret
|
278
|
-
|
279
|
-
(1..3).each do |i|
|
280
|
-
id = ring.prep_nop
|
281
|
-
assert_equal i, id
|
282
|
-
end
|
283
|
-
|
284
|
-
ring.submit
|
285
|
-
sleep 0.001
|
286
|
-
|
287
|
-
ret = ring.process_completions
|
288
|
-
assert_equal 3, ret
|
289
|
-
end
|
290
|
-
|
291
|
-
def test_process_completions_wait
|
292
|
-
(1..3).each do |i|
|
293
|
-
id = ring.prep_nop
|
294
|
-
assert_equal i, id
|
295
|
-
end
|
296
|
-
|
297
|
-
ring.submit
|
298
|
-
ret = ring.process_completions(true)
|
299
|
-
assert_equal 3, ret
|
300
|
-
end
|
301
|
-
|
302
|
-
def test_process_completions_with_block
|
303
|
-
r, w = IO.pipe
|
304
|
-
|
305
|
-
ring.prep_write(fd: w.fileno, buffer: 'foo')
|
306
|
-
ring.prep_write(fd: w.fileno, buffer: 'bar')
|
307
|
-
ring.prep_write(fd: w.fileno, buffer: 'baz')
|
308
|
-
ring.submit
|
309
|
-
sleep 0.01
|
310
|
-
|
311
|
-
completions = []
|
312
|
-
|
313
|
-
ret = ring.process_completions do |c|
|
314
|
-
completions << c
|
315
|
-
end
|
316
|
-
|
317
|
-
assert_equal 3, ret
|
318
|
-
assert_equal 3, completions.size
|
319
|
-
assert_equal [1, 2, 3], completions.map { _1[:id] }
|
320
|
-
assert_equal [:write], completions.map { _1[:op] }.uniq
|
321
|
-
assert_equal 9, completions.inject(0) { |t, c| t + c[:result] }
|
322
|
-
|
323
|
-
w.close
|
324
|
-
assert_equal 'foobarbaz', r.read
|
325
|
-
end
|
326
|
-
|
327
|
-
def test_process_completions_op_with_block
|
328
|
-
cc = []
|
329
|
-
|
330
|
-
ring.prep_timeout(interval: 0.01) { cc << 1 }
|
331
|
-
ring.prep_timeout(interval: 0.02) { cc << 2 }
|
332
|
-
ring.submit
|
333
|
-
|
334
|
-
ret = ring.process_completions
|
335
|
-
assert_equal 0, ret
|
336
|
-
assert_equal [], cc
|
337
|
-
|
338
|
-
sleep 0.02
|
339
|
-
ret = ring.process_completions(true)
|
340
|
-
|
341
|
-
assert_equal 2, ret
|
342
|
-
assert_equal [1, 2], cc
|
343
|
-
end
|
344
|
-
|
345
|
-
def test_process_completions_op_with_block_no_submit
|
346
|
-
cc = []
|
347
|
-
|
348
|
-
ring.prep_timeout(interval: 0.01) { cc << 1 }
|
349
|
-
ring.prep_timeout(interval: 0.02) { cc << 2 }
|
350
|
-
|
351
|
-
ret = ring.process_completions
|
352
|
-
assert_equal 0, ret
|
353
|
-
assert_equal [], cc
|
354
|
-
|
355
|
-
sleep 0.02
|
356
|
-
ret = ring.process_completions(true)
|
357
|
-
assert_equal 2, ret
|
358
|
-
assert_equal [1, 2], cc
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
class PrepReadTest < IOURingBaseTest
|
363
|
-
def test_prep_read
|
364
|
-
r, w = IO.pipe
|
365
|
-
s = 'foobar'
|
366
|
-
|
367
|
-
id = ring.prep_read(fd: r.fileno, buffer: +'', len: 8192)
|
368
|
-
assert_equal 1, id
|
369
|
-
ring.submit
|
370
|
-
|
371
|
-
w << s
|
372
|
-
|
373
|
-
c = ring.wait_for_completion
|
374
|
-
|
375
|
-
assert_kind_of Hash, c
|
376
|
-
assert_equal id, c[:id]
|
377
|
-
assert_equal :read, c[:op]
|
378
|
-
assert_equal r.fileno, c[:fd]
|
379
|
-
assert_equal s.bytesize, c[:result]
|
380
|
-
assert_equal s, c[:buffer]
|
381
|
-
end
|
382
|
-
|
383
|
-
def test_prep_read_empty
|
384
|
-
r, w = IO.pipe
|
385
|
-
|
386
|
-
id = ring.prep_read(fd: r.fileno, buffer: +'', len: 8192)
|
387
|
-
assert_equal 1, id
|
388
|
-
ring.submit
|
389
|
-
|
390
|
-
w.close
|
391
|
-
|
392
|
-
c = ring.wait_for_completion
|
393
|
-
|
394
|
-
assert_kind_of Hash, c
|
395
|
-
assert_equal id, c[:id]
|
396
|
-
assert_equal :read, c[:op]
|
397
|
-
assert_equal r.fileno, c[:fd]
|
398
|
-
assert_equal 0, c[:result]
|
399
|
-
assert_equal '', c[:buffer]
|
400
|
-
end
|
401
|
-
|
402
|
-
def test_prep_read_invalid_args
|
403
|
-
assert_raises(ArgumentError) { ring.prep_read() }
|
404
|
-
assert_raises(ArgumentError) { ring.prep_read(foo: 1) }
|
405
|
-
assert_raises(ArgumentError) { ring.prep_read(fd: 'bar', buffer: +'') }
|
406
|
-
assert_raises(ArgumentError) { ring.prep_read({}) }
|
407
|
-
end
|
408
|
-
|
409
|
-
def test_prep_read_bad_fd
|
410
|
-
_r, w = IO.pipe
|
411
|
-
|
412
|
-
id = ring.prep_read(fd: w.fileno, buffer: +'', len: 8192)
|
413
|
-
assert_equal 1, id
|
414
|
-
|
415
|
-
ring.submit
|
416
|
-
c = ring.wait_for_completion
|
417
|
-
|
418
|
-
assert_kind_of Hash, c
|
419
|
-
assert_equal id, c[:id]
|
420
|
-
assert_equal :read, c[:op]
|
421
|
-
assert_equal w.fileno, c[:fd]
|
422
|
-
assert_equal (-Errno::EBADF::Errno), c[:result]
|
423
|
-
end
|
424
|
-
|
425
|
-
def test_prep_read_with_block
|
426
|
-
r, w = IO.pipe
|
427
|
-
w << 'foobar'
|
428
|
-
|
429
|
-
cc = nil
|
430
|
-
id = ring.prep_read(fd: r.fileno, buffer: +'', len: 3) do |c|
|
431
|
-
cc = c
|
432
|
-
end
|
433
|
-
|
434
|
-
ring.submit
|
435
|
-
ring.process_completions
|
436
|
-
|
437
|
-
assert_kind_of Hash, cc
|
438
|
-
assert_equal id, cc[:id]
|
439
|
-
assert_equal :read, cc[:op]
|
440
|
-
assert_equal r.fileno, cc[:fd]
|
441
|
-
assert_equal 3, cc[:result]
|
442
|
-
assert_equal 'foo', cc[:buffer]
|
443
|
-
|
444
|
-
id = ring.prep_read(fd: r.fileno, buffer: +'', len: 5) do |c|
|
445
|
-
cc = c
|
446
|
-
end
|
447
|
-
assert_equal 'foo', cc[:buffer]
|
448
|
-
|
449
|
-
ring.submit
|
450
|
-
ring.process_completions
|
451
|
-
|
452
|
-
assert_kind_of Hash, cc
|
453
|
-
assert_equal id, cc[:id]
|
454
|
-
assert_equal :read, cc[:op]
|
455
|
-
assert_equal r.fileno, cc[:fd]
|
456
|
-
assert_equal 3, cc[:result]
|
457
|
-
assert_equal 'bar', cc[:buffer]
|
458
|
-
end
|
459
|
-
|
460
|
-
def test_prep_read_with_buffer_offset
|
461
|
-
buffer = +'foo'
|
462
|
-
|
463
|
-
r, w = IO.pipe
|
464
|
-
w << 'bar'
|
465
|
-
|
466
|
-
id = ring.prep_read(fd: r.fileno, buffer: buffer, len: 100, buffer_offset: buffer.bytesize)
|
467
|
-
ring.submit
|
468
|
-
cc = ring.wait_for_completion
|
469
|
-
|
470
|
-
assert_kind_of Hash, cc
|
471
|
-
assert_equal id, cc[:id]
|
472
|
-
assert_equal :read, cc[:op]
|
473
|
-
assert_equal r.fileno, cc[:fd]
|
474
|
-
assert_equal 3, cc[:result]
|
475
|
-
assert_equal 'foobar', buffer
|
476
|
-
end
|
477
|
-
|
478
|
-
def test_prep_read_with_negative_buffer_offset
|
479
|
-
buffer = +'foo'
|
480
|
-
|
481
|
-
r, w = IO.pipe
|
482
|
-
w << 'bar'
|
483
|
-
|
484
|
-
id = ring.prep_read(fd: r.fileno, buffer: buffer, len: 100, buffer_offset: -1)
|
485
|
-
ring.submit
|
486
|
-
cc = ring.wait_for_completion
|
487
|
-
|
488
|
-
assert_kind_of Hash, cc
|
489
|
-
assert_equal id, cc[:id]
|
490
|
-
assert_equal :read, cc[:op]
|
491
|
-
assert_equal r.fileno, cc[:fd]
|
492
|
-
assert_equal 3, cc[:result]
|
493
|
-
assert_equal 'foobar', buffer
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
buffer = +'foogrr'
|
498
|
-
|
499
|
-
r, w = IO.pipe
|
500
|
-
w << 'bar'
|
501
|
-
|
502
|
-
id = ring.prep_read(fd: r.fileno, buffer: buffer, len: 100, buffer_offset: -4)
|
503
|
-
ring.submit
|
504
|
-
cc = ring.wait_for_completion
|
505
|
-
|
506
|
-
assert_kind_of Hash, cc
|
507
|
-
assert_equal id, cc[:id]
|
508
|
-
assert_equal :read, cc[:op]
|
509
|
-
assert_equal r.fileno, cc[:fd]
|
510
|
-
assert_equal 3, cc[:result]
|
511
|
-
assert_equal 'foobar', buffer
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
class PrepCloseTest < IOURingBaseTest
|
516
|
-
def test_prep_close
|
517
|
-
_r, w = IO.pipe
|
518
|
-
fd = w.fileno
|
519
|
-
|
520
|
-
id = ring.prep_close(fd: fd)
|
521
|
-
assert_equal 1, id
|
522
|
-
ring.submit
|
523
|
-
|
524
|
-
c = ring.wait_for_completion
|
525
|
-
assert_kind_of Hash, c
|
526
|
-
assert_equal id, c[:id]
|
527
|
-
assert_equal :close, c[:op]
|
528
|
-
assert_equal fd, c[:fd]
|
529
|
-
assert_equal 0, c[:result]
|
530
|
-
|
531
|
-
assert_raises(Errno::EBADF) { w << 'fail' }
|
532
|
-
|
533
|
-
id = ring.prep_close(fd: fd)
|
534
|
-
assert_equal 2, id
|
535
|
-
ring.submit
|
536
|
-
|
537
|
-
c = ring.wait_for_completion
|
538
|
-
assert_kind_of Hash, c
|
539
|
-
assert_equal id, c[:id]
|
540
|
-
assert_equal :close, c[:op]
|
541
|
-
assert_equal fd, c[:fd]
|
542
|
-
assert_equal (-Errno::EBADF::Errno), c[:result]
|
543
|
-
|
544
|
-
end
|
545
|
-
|
546
|
-
def test_prep_close_invalid_args
|
547
|
-
assert_raises(ArgumentError) { ring.prep_close() }
|
548
|
-
assert_raises(ArgumentError) { ring.prep_close({}) }
|
549
|
-
assert_raises(ArgumentError) { ring.prep_close(foo: 1) }
|
550
|
-
assert_raises(TypeError) { ring.prep_close(fd: 'bar') }
|
551
|
-
end
|
552
|
-
|
553
|
-
def test_prep_close_invalid_fd
|
554
|
-
id = ring.prep_close(fd: 9999)
|
555
|
-
assert_equal 1, id
|
556
|
-
|
557
|
-
ring.submit
|
558
|
-
c = ring.wait_for_completion
|
559
|
-
|
560
|
-
assert_kind_of Hash, c
|
561
|
-
assert_equal id, c[:id]
|
562
|
-
assert_equal :close, c[:op]
|
563
|
-
assert_equal 9999, c[:fd]
|
564
|
-
assert_equal (-Errno::EBADF::Errno), c[:result]
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
class PrepAcceptTest < IOURingBaseTest
|
569
|
-
def setup
|
570
|
-
super
|
571
|
-
@port = 9000 + rand(1000)
|
572
|
-
@server = TCPServer.open('127.0.0.1', @port)
|
573
|
-
end
|
574
|
-
|
575
|
-
def teardown
|
576
|
-
@server.close
|
577
|
-
super
|
578
|
-
end
|
579
|
-
|
580
|
-
def test_prep_accept
|
581
|
-
id = ring.prep_accept(fd: @server.fileno)
|
582
|
-
ring.submit
|
583
|
-
|
584
|
-
t = Thread.new do
|
585
|
-
TCPSocket.new('127.0.0.1', @port)
|
586
|
-
end
|
587
|
-
|
588
|
-
c = ring.wait_for_completion
|
589
|
-
assert_equal id, c[:id]
|
590
|
-
assert_equal :accept, c[:op]
|
591
|
-
fd = c[:result]
|
592
|
-
assert fd > 0
|
593
|
-
ensure
|
594
|
-
t&.kill rescue nil
|
595
|
-
end
|
596
|
-
|
597
|
-
def test_prep_accept_invalid_args
|
598
|
-
assert_raises(ArgumentError) { ring.prep_accept() }
|
599
|
-
assert_raises(ArgumentError) { ring.prep_accept(foo: 1) }
|
600
|
-
assert_raises(TypeError) { ring.prep_accept(fd: 'bar') }
|
601
|
-
assert_raises(ArgumentError) { ring.prep_accept({}) }
|
602
|
-
end
|
603
|
-
|
604
|
-
def test_prep_accept_bad_fd
|
605
|
-
id = ring.prep_accept(fd: STDIN.fileno)
|
606
|
-
assert_equal 1, id
|
607
|
-
|
608
|
-
ring.submit
|
609
|
-
c = ring.wait_for_completion
|
610
|
-
|
611
|
-
assert_kind_of Hash, c
|
612
|
-
assert_equal id, c[:id]
|
613
|
-
assert_equal :accept, c[:op]
|
614
|
-
assert_equal STDIN.fileno, c[:fd]
|
615
|
-
assert_equal (-Errno::ENOTSOCK::Errno), c[:result]
|
616
|
-
end
|
617
|
-
|
618
|
-
def test_prep_accept_multishot
|
619
|
-
id = ring.prep_accept(fd: @server.fileno, multishot: true)
|
620
|
-
ring.submit
|
621
|
-
|
622
|
-
tt = []
|
623
|
-
|
624
|
-
connect = -> {
|
625
|
-
tt << Thread.new do
|
626
|
-
TCPSocket.new('127.0.0.1', @port)
|
627
|
-
end
|
628
|
-
}
|
629
|
-
|
630
|
-
fds = []
|
631
|
-
|
632
|
-
3.times do |i|
|
633
|
-
connect.call
|
634
|
-
c = ring.wait_for_completion
|
635
|
-
assert_equal id, c[:id]
|
636
|
-
assert_equal :accept, c[:op]
|
637
|
-
fd = c[:result]
|
638
|
-
assert fd > 0
|
639
|
-
assert ring.pending_ops[id]
|
640
|
-
|
641
|
-
fds << fd
|
642
|
-
end
|
643
|
-
|
644
|
-
assert_equal 3, fds.uniq.size
|
645
|
-
|
646
|
-
ring.prep_cancel(id)
|
647
|
-
ring.process_completions
|
648
|
-
|
649
|
-
assert_nil ring.pending_ops[id]
|
650
|
-
ensure
|
651
|
-
tt.each { |t| t&.kill rescue nil }
|
652
|
-
end
|
653
|
-
end
|
654
|
-
|
655
|
-
class EmitTest < IOURingBaseTest
|
656
|
-
def test_emit
|
657
|
-
o = { foo: 'bar' }
|
658
|
-
id = ring.emit(o)
|
659
|
-
assert_equal 1, id
|
660
|
-
|
661
|
-
c = ring.wait_for_completion
|
662
|
-
assert_equal o, c
|
663
|
-
assert_equal id, c[:id]
|
664
|
-
assert_equal :emit, c[:op]
|
665
|
-
assert_equal 0, c[:result]
|
666
|
-
end
|
667
|
-
end
|
668
|
-
|
669
|
-
class ProcessCompletionsLoopTest < IOURingBaseTest
|
670
|
-
def test_loop_stop
|
671
|
-
ring.emit(signal: :stop)
|
672
|
-
|
673
|
-
cc = []
|
674
|
-
ring.process_completions_loop do |c|
|
675
|
-
p c
|
676
|
-
cc << c
|
677
|
-
end
|
678
|
-
|
679
|
-
assert_equal [], cc
|
680
|
-
end
|
681
|
-
|
682
|
-
def test_loop
|
683
|
-
ring.emit(value: 1)
|
684
|
-
ring.emit(value: 2)
|
685
|
-
ring.emit(value: 3)
|
686
|
-
ring.emit(signal: :stop)
|
687
|
-
ring.emit(value: 4)
|
688
|
-
|
689
|
-
cc = []
|
690
|
-
ring.process_completions_loop do |c|
|
691
|
-
cc << c
|
692
|
-
end
|
693
|
-
assert_equal (1..3).to_a, cc.map { _1[:value] }
|
694
|
-
|
695
|
-
c = ring.wait_for_completion
|
696
|
-
assert_equal 4, c[:value]
|
697
|
-
end
|
698
|
-
end
|
699
|
-
|
700
|
-
class PrepReadMultishotTest < IOURingBaseTest
|
701
|
-
def test_prep_read_multishot_invalid_args
|
702
|
-
assert_raises(ArgumentError) { ring.prep_read(multishot: true, buffer_group: 1) }
|
703
|
-
assert_raises(ArgumentError) { ring.prep_read(multishot: true, foo: 1) }
|
704
|
-
assert_raises(ArgumentError) { ring.prep_read(multishot: true, fd: 'bar', buffer: +'') }
|
705
|
-
assert_raises(ArgumentError) { ring.prep_read(multishot: true) }
|
706
|
-
end
|
707
|
-
|
708
|
-
def test_prep_read_multishot
|
709
|
-
r, w = IO.pipe
|
710
|
-
|
711
|
-
bgid = ring.setup_buffer_ring(size: 4096, count: 1024)
|
712
|
-
assert_equal 0, bgid
|
713
|
-
|
714
|
-
id = ring.prep_read(fd: r.fileno, multishot: true, buffer_group: bgid)
|
715
|
-
assert_equal 1, id
|
716
|
-
ring.submit
|
717
|
-
|
718
|
-
w << 'foo'
|
719
|
-
c = ring.wait_for_completion
|
720
|
-
|
721
|
-
# make sure the OS supports this op (the liburing docs are not clear)
|
722
|
-
skip if c[:result] == (-Errno::EINVAL::Errno)
|
723
|
-
|
724
|
-
assert_kind_of Hash, c
|
725
|
-
assert_equal id, c[:id]
|
726
|
-
assert_equal :read, c[:op]
|
727
|
-
assert_equal r.fileno, c[:fd]
|
728
|
-
assert_equal 3, c[:result]
|
729
|
-
assert_equal 'foo', c[:buffer]
|
730
|
-
assert_equal Encoding::ASCII_8BIT, c[:buffer].encoding
|
731
|
-
refute_nil ring.pending_ops[id]
|
732
|
-
|
733
|
-
w << 'bar'
|
734
|
-
c = ring.wait_for_completion
|
735
|
-
assert_kind_of Hash, c
|
736
|
-
assert_equal id, c[:id]
|
737
|
-
assert_equal :read, c[:op]
|
738
|
-
assert_equal r.fileno, c[:fd]
|
739
|
-
assert_equal 3, c[:result]
|
740
|
-
assert_equal 'bar', c[:buffer]
|
741
|
-
refute_nil ring.pending_ops[id]
|
742
|
-
|
743
|
-
w.close
|
744
|
-
c = ring.wait_for_completion
|
745
|
-
assert_kind_of Hash, c
|
746
|
-
assert_equal id, c[:id]
|
747
|
-
assert_equal :read, c[:op]
|
748
|
-
assert_equal r.fileno, c[:fd]
|
749
|
-
assert_equal 0, c[:result]
|
750
|
-
assert_nil ring.pending_ops[id]
|
751
|
-
end
|
752
|
-
|
753
|
-
def test_prep_read_multishot_utf8
|
754
|
-
r, w = IO.pipe
|
755
|
-
|
756
|
-
bgid = ring.setup_buffer_ring(size: 4096, count: 1024)
|
757
|
-
assert_equal 0, bgid
|
758
|
-
|
759
|
-
id = ring.prep_read(fd: r.fileno, multishot: true, utf8: true, buffer_group: bgid)
|
760
|
-
assert_equal 1, id
|
761
|
-
ring.submit
|
762
|
-
|
763
|
-
w << 'foo'
|
764
|
-
c = ring.wait_for_completion
|
765
|
-
|
766
|
-
# make sure the OS supports this op (the liburing docs are not clear)
|
767
|
-
skip if c[:result] == (-Errno::EINVAL::Errno)
|
768
|
-
|
769
|
-
assert_kind_of Hash, c
|
770
|
-
assert_equal id, c[:id]
|
771
|
-
assert_equal :read, c[:op]
|
772
|
-
assert_equal r.fileno, c[:fd]
|
773
|
-
assert_equal 3, c[:result]
|
774
|
-
assert_equal 'foo', c[:buffer]
|
775
|
-
assert_equal Encoding::UTF_8, c[:buffer].encoding
|
776
|
-
refute_nil ring.pending_ops[id]
|
777
|
-
|
778
|
-
w << 'bar'
|
779
|
-
c = ring.wait_for_completion
|
780
|
-
assert_kind_of Hash, c
|
781
|
-
assert_equal id, c[:id]
|
782
|
-
assert_equal :read, c[:op]
|
783
|
-
assert_equal r.fileno, c[:fd]
|
784
|
-
assert_equal 3, c[:result]
|
785
|
-
assert_equal 'bar', c[:buffer]
|
786
|
-
refute_nil ring.pending_ops[id]
|
787
|
-
|
788
|
-
w.close
|
789
|
-
c = ring.wait_for_completion
|
790
|
-
assert_kind_of Hash, c
|
791
|
-
assert_equal id, c[:id]
|
792
|
-
assert_equal :read, c[:op]
|
793
|
-
assert_equal r.fileno, c[:fd]
|
794
|
-
assert_equal 0, c[:result]
|
795
|
-
assert_nil ring.pending_ops[id]
|
796
|
-
end
|
797
|
-
end
|
798
|
-
|
799
|
-
class OpCtxTest < IOURingBaseTest
|
800
|
-
def test_ctx_spec
|
801
|
-
id = ring.emit(foo: :bar)
|
802
|
-
assert_equal({ foo: :bar, id: 1, op: :emit }, ring.pending_ops[id].spec)
|
803
|
-
end
|
804
|
-
|
805
|
-
def test_ctx_type
|
806
|
-
id = ring.emit(v: 1)
|
807
|
-
assert_equal 1, id
|
808
|
-
assert_equal :emit, ring.pending_ops[id].spec[:op]
|
809
|
-
|
810
|
-
id = ring.prep_timeout(interval: 1)
|
811
|
-
assert_equal 2, id
|
812
|
-
assert_equal :timeout, ring.pending_ops[id].spec[:op]
|
813
|
-
|
814
|
-
id = ring.prep_read(fd: STDIN.fileno, buffer: +'', len: 42)
|
815
|
-
assert_equal 3, id
|
816
|
-
assert_equal :read, ring.pending_ops[id].spec[:op]
|
817
|
-
|
818
|
-
id = ring.prep_write(fd: STDOUT.fileno, buffer: '')
|
819
|
-
assert_equal 4, id
|
820
|
-
assert_equal :write, ring.pending_ops[id].spec[:op]
|
821
|
-
|
822
|
-
id = ring.prep_accept(fd: STDIN.fileno)
|
823
|
-
assert_equal 5, id
|
824
|
-
assert_equal :accept, ring.pending_ops[id].spec[:op]
|
825
|
-
|
826
|
-
id = ring.prep_close(fd: STDIN.fileno)
|
827
|
-
assert_equal 6, id
|
828
|
-
assert_equal :close, ring.pending_ops[id].spec[:op]
|
829
|
-
end
|
830
|
-
end
|
831
|
-
|
832
|
-
class LinkTest < IOURingBaseTest
|
833
|
-
def test_linked_submissions
|
834
|
-
r, w = IO.pipe
|
835
|
-
id1 = ring.prep_write(fd: w.fileno, buffer: 'foo', link: true)
|
836
|
-
id2 = ring.prep_write(fd: w.fileno, buffer: 'bar')
|
837
|
-
|
838
|
-
ret = ring.submit
|
839
|
-
assert_equal 2, ret
|
840
|
-
|
841
|
-
ret = ring.process_completions(true)
|
842
|
-
assert_equal 2, ret
|
843
|
-
|
844
|
-
w.close
|
845
|
-
assert_equal 'foobar', r.read
|
846
|
-
end
|
847
|
-
end
|
848
|
-
|
849
|
-
class RactorTest < Minitest::Test
|
850
|
-
def test_ractor
|
851
|
-
# Ractor is still experimental in Ruby 3.x.x
|
852
|
-
old_warning_status = Warning[:experimental]
|
853
|
-
Warning[:experimental] = false
|
854
|
-
|
855
|
-
r, w = IO.pipe
|
856
|
-
|
857
|
-
w << 'foobar'
|
858
|
-
|
859
|
-
ractor = Ractor.new(r.fileno) do |fd|
|
860
|
-
ring = IOU::Ring.new
|
861
|
-
id = ring.prep_read(fd: fd, buffer: +'', len: 42)
|
862
|
-
ring.submit
|
863
|
-
c = ring.wait_for_completion
|
864
|
-
[id, c]
|
865
|
-
end
|
866
|
-
|
867
|
-
id, c = ractor.take
|
868
|
-
assert_equal 1, id
|
869
|
-
assert_kind_of Hash, c
|
870
|
-
assert_equal :read, c[:op]
|
871
|
-
assert_equal 'foobar', c[:buffer]
|
872
|
-
|
873
|
-
ensure
|
874
|
-
Warning[:experimental] = old_warning_status
|
875
|
-
end
|
876
|
-
end
|