uringmachine 0.20.0 → 0.22.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/.rubocop.yml +2 -0
- data/CHANGELOG.md +34 -0
- data/TODO.md +132 -26
- data/benchmark/README.md +173 -0
- data/benchmark/bm_io_pipe.rb +70 -0
- data/benchmark/bm_io_socketpair.rb +71 -0
- data/benchmark/bm_mutex_cpu.rb +57 -0
- data/benchmark/bm_mutex_io.rb +64 -0
- data/benchmark/bm_pg_client.rb +109 -0
- data/benchmark/bm_queue.rb +76 -0
- data/benchmark/chart.png +0 -0
- data/benchmark/common.rb +135 -0
- data/benchmark/dns_client.rb +47 -0
- data/{examples/bm_http_parse.rb → benchmark/http_parse.rb} +1 -1
- data/benchmark/run_bm.rb +8 -0
- data/benchmark/sqlite.rb +108 -0
- data/{examples/bm_write.rb → benchmark/write.rb} +6 -3
- data/ext/um/extconf.rb +1 -1
- data/ext/um/um.c +404 -95
- data/ext/um/um.h +77 -24
- data/ext/um/um_async_op.c +2 -2
- data/ext/um/um_class.c +168 -18
- data/ext/um/um_op.c +43 -0
- data/ext/um/um_sync.c +10 -16
- data/ext/um/um_utils.c +16 -0
- data/grant-2025/journal.md +242 -1
- data/grant-2025/tasks.md +136 -41
- data/lib/uringmachine/actor.rb +8 -0
- data/lib/uringmachine/dns_resolver.rb +1 -2
- data/lib/uringmachine/fiber_scheduler.rb +283 -110
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +32 -3
- data/test/helper.rb +7 -18
- data/test/test_actor.rb +12 -3
- data/test/test_async_op.rb +10 -10
- data/test/test_fiber.rb +84 -1
- data/test/test_fiber_scheduler.rb +1425 -20
- data/test/test_um.rb +565 -113
- data/uringmachine.gemspec +6 -5
- data/vendor/liburing/src/include/liburing/io_uring.h +1 -0
- data/vendor/liburing/src/include/liburing.h +13 -0
- data/vendor/liburing/src/liburing-ffi.map +1 -0
- data/vendor/liburing/test/bind-listen.c +175 -13
- data/vendor/liburing/test/read-write.c +4 -4
- data/vendor/liburing/test/ringbuf-read.c +4 -4
- data/vendor/liburing/test/send_recv.c +8 -7
- metadata +50 -28
- data/examples/bm_fileno.rb +0 -33
- data/examples/bm_queue.rb +0 -110
- data/examples/bm_side_running.rb +0 -83
- data/examples/bm_sqlite.rb +0 -89
- data/examples/dns_client.rb +0 -12
- /data/{examples/bm_mutex.rb → benchmark/mutex.rb} +0 -0
- /data/{examples/bm_mutex_single.rb → benchmark/mutex_single.rb} +0 -0
- /data/{examples/bm_send.rb → benchmark/send.rb} +0 -0
- /data/{examples/bm_snooze.rb → benchmark/snooze.rb} +0 -0
data/test/test_um.rb
CHANGED
|
@@ -11,6 +11,82 @@ class UringMachineTest < Minitest::Test
|
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
class SizeTest < Minitest::Test
|
|
15
|
+
def test_default_size
|
|
16
|
+
m = UM.new
|
|
17
|
+
assert_equal 4096, m.size
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_custom_size_value
|
|
21
|
+
m = UM.new(13)
|
|
22
|
+
assert_equal 13, m.size
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class SQPOLLTest < Minitest::Test
|
|
27
|
+
def test_sqpoll_timeout
|
|
28
|
+
m = UM.new(10, 0.05)
|
|
29
|
+
|
|
30
|
+
r, w = UM.pipe
|
|
31
|
+
|
|
32
|
+
buf = nil
|
|
33
|
+
t = Thread.new { buf = IO.new(r).readpartial(3) }
|
|
34
|
+
|
|
35
|
+
# let SQPOLL worker thread timeout
|
|
36
|
+
sleep(0.06)
|
|
37
|
+
|
|
38
|
+
# SQE is prepared but not submitted
|
|
39
|
+
m.write_async(w, 'foo')
|
|
40
|
+
|
|
41
|
+
# thread should timeout
|
|
42
|
+
ret = t.join(0.03)
|
|
43
|
+
assert_nil buf
|
|
44
|
+
ensure
|
|
45
|
+
t.kill rescue nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_sqpoll_timeout_with_submit
|
|
49
|
+
m = UM.new(10, 0.05)
|
|
50
|
+
|
|
51
|
+
r, w = UM.pipe
|
|
52
|
+
|
|
53
|
+
buf = nil
|
|
54
|
+
t = Thread.new { buf = IO.new(r).readpartial(3) }
|
|
55
|
+
|
|
56
|
+
# let SQPOLL worker thread timeout
|
|
57
|
+
sleep(0.06)
|
|
58
|
+
|
|
59
|
+
# SQE is prepared but not submitted
|
|
60
|
+
m.write_async(w, 'foo')
|
|
61
|
+
ret = m.submit
|
|
62
|
+
assert_equal 1, ret
|
|
63
|
+
|
|
64
|
+
# thread should timeout
|
|
65
|
+
ret = t.join(0.1)
|
|
66
|
+
assert_equal 'foo', buf
|
|
67
|
+
ensure
|
|
68
|
+
t.kill rescue nil
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class SubmitTest < UMBaseTest
|
|
73
|
+
def test_submit
|
|
74
|
+
_r, w = UM.pipe
|
|
75
|
+
|
|
76
|
+
assert_equal 0, machine.pending_fibers.size
|
|
77
|
+
machine.write_async(w, 'foo')
|
|
78
|
+
machine.write_async(w, 'bar')
|
|
79
|
+
machine.write_async(w, 'baz')
|
|
80
|
+
assert_equal 0, machine.pending_fibers.size
|
|
81
|
+
|
|
82
|
+
assert_equal 3, machine.metrics[:ops_pending]
|
|
83
|
+
assert_equal 3, machine.submit
|
|
84
|
+
assert_equal 0, machine.submit
|
|
85
|
+
machine.snooze
|
|
86
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
14
90
|
class SpinTest < UMBaseTest
|
|
15
91
|
def test_spin
|
|
16
92
|
x = nil
|
|
@@ -35,7 +111,7 @@ end
|
|
|
35
111
|
|
|
36
112
|
class SnoozeTest < UMBaseTest
|
|
37
113
|
def test_snooze_while_sleeping_fiber
|
|
38
|
-
machine.spin do
|
|
114
|
+
f = machine.spin do
|
|
39
115
|
machine.sleep(0.1)
|
|
40
116
|
end
|
|
41
117
|
|
|
@@ -48,6 +124,9 @@ class SnoozeTest < UMBaseTest
|
|
|
48
124
|
machine.snooze
|
|
49
125
|
t1 = monotonic_clock
|
|
50
126
|
assert_in_range 0..0.001, t1 - t0
|
|
127
|
+
ensure
|
|
128
|
+
machine.schedule(f, nil)
|
|
129
|
+
machine.join(f)
|
|
51
130
|
end
|
|
52
131
|
end
|
|
53
132
|
|
|
@@ -59,7 +138,7 @@ class ScheduleTest < UMBaseTest
|
|
|
59
138
|
buf << [21, x]
|
|
60
139
|
machine.schedule(main, 21)
|
|
61
140
|
buf << 22
|
|
62
|
-
x = machine.
|
|
141
|
+
x = machine.switch
|
|
63
142
|
buf << [23, x]
|
|
64
143
|
end
|
|
65
144
|
|
|
@@ -78,11 +157,10 @@ class ScheduleTest < UMBaseTest
|
|
|
78
157
|
def test_schedule_exception
|
|
79
158
|
buf = []
|
|
80
159
|
f = Fiber.new do
|
|
81
|
-
# this should raise
|
|
82
|
-
machine.yield
|
|
160
|
+
machine.yield # this should raise
|
|
83
161
|
rescue Exception => e
|
|
84
162
|
buf << e
|
|
85
|
-
machine.
|
|
163
|
+
machine.switch
|
|
86
164
|
end
|
|
87
165
|
|
|
88
166
|
machine.schedule(f, nil)
|
|
@@ -102,19 +180,19 @@ class ScheduleTest < UMBaseTest
|
|
|
102
180
|
e = CustomError.new
|
|
103
181
|
f = Fiber.new do
|
|
104
182
|
machine.schedule(main, e)
|
|
105
|
-
machine.
|
|
183
|
+
machine.switch
|
|
106
184
|
end
|
|
107
185
|
|
|
108
186
|
machine.schedule(f, nil)
|
|
109
187
|
t0 = monotonic_clock
|
|
110
188
|
|
|
111
189
|
# the call to schedule means an op is checked out
|
|
112
|
-
assert_equal 0, machine.
|
|
190
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
113
191
|
begin
|
|
114
192
|
machine.sleep(1)
|
|
115
193
|
rescue Exception => e2
|
|
116
194
|
end
|
|
117
|
-
assert_equal 0, machine.
|
|
195
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
118
196
|
t1 = monotonic_clock
|
|
119
197
|
|
|
120
198
|
assert_equal e2, e
|
|
@@ -137,7 +215,7 @@ class ScheduleTest < UMBaseTest
|
|
|
137
215
|
buf << 5
|
|
138
216
|
end
|
|
139
217
|
|
|
140
|
-
assert_equal 0, machine.
|
|
218
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
141
219
|
assert_equal [1, 2, 5], buf
|
|
142
220
|
assert_kind_of TOError, e
|
|
143
221
|
end
|
|
@@ -176,9 +254,9 @@ class ScheduleTest < UMBaseTest
|
|
|
176
254
|
rescue => e
|
|
177
255
|
end
|
|
178
256
|
|
|
179
|
-
assert_equal 1, machine.
|
|
257
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
180
258
|
machine.sleep(0.01) # wait for cancelled CQEs
|
|
181
|
-
assert_equal 0, machine.
|
|
259
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
182
260
|
|
|
183
261
|
assert_kind_of RuntimeError, e
|
|
184
262
|
assert_equal 'hi', e.message
|
|
@@ -189,9 +267,9 @@ class ScheduleTest < UMBaseTest
|
|
|
189
267
|
|
|
190
268
|
assert_equal 42, v
|
|
191
269
|
|
|
192
|
-
assert_equal 1, machine.
|
|
270
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
193
271
|
machine.sleep 0.01 # wait for cancelled CQE
|
|
194
|
-
assert_equal 0, machine.
|
|
272
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
195
273
|
end
|
|
196
274
|
|
|
197
275
|
def test_timeout_with_no_timeout
|
|
@@ -200,9 +278,9 @@ class ScheduleTest < UMBaseTest
|
|
|
200
278
|
|
|
201
279
|
assert_equal 3, v
|
|
202
280
|
|
|
203
|
-
assert_equal 1, machine.
|
|
281
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
204
282
|
machine.sleep 0.01 # wait for cancelled CQE
|
|
205
|
-
assert_equal 0, machine.
|
|
283
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
206
284
|
end
|
|
207
285
|
|
|
208
286
|
class TO2Error < RuntimeError; end
|
|
@@ -215,7 +293,7 @@ class ScheduleTest < UMBaseTest
|
|
|
215
293
|
machine.timeout(0.04, TOError) do
|
|
216
294
|
machine.timeout(0.02, TO2Error) do
|
|
217
295
|
machine.timeout(0.03, TO3Error) do
|
|
218
|
-
buf << machine.
|
|
296
|
+
buf << machine.metrics[:ops_pending]
|
|
219
297
|
machine.sleep(1)
|
|
220
298
|
end
|
|
221
299
|
end
|
|
@@ -223,9 +301,9 @@ class ScheduleTest < UMBaseTest
|
|
|
223
301
|
rescue => e
|
|
224
302
|
end
|
|
225
303
|
|
|
226
|
-
assert_equal 2, machine.
|
|
304
|
+
assert_equal 2, machine.metrics[:ops_pending]
|
|
227
305
|
machine.sleep(0.01) # wait for cancelled CQEs
|
|
228
|
-
assert_equal 0, machine.
|
|
306
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
229
307
|
|
|
230
308
|
assert_kind_of TO2Error, e
|
|
231
309
|
assert_equal [3], buf
|
|
@@ -235,9 +313,9 @@ end
|
|
|
235
313
|
class SleepTest < UMBaseTest
|
|
236
314
|
def test_sleep
|
|
237
315
|
t0 = monotonic_clock
|
|
238
|
-
assert_equal 0, machine.
|
|
316
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
239
317
|
res = machine.sleep(0.1)
|
|
240
|
-
assert_equal 0, machine.
|
|
318
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
241
319
|
t1 = monotonic_clock
|
|
242
320
|
assert_in_range 0.09..0.13, t1 - t0
|
|
243
321
|
assert_equal 0.1, res
|
|
@@ -294,7 +372,7 @@ class PeriodicallyTest < UMBaseTest
|
|
|
294
372
|
cancel = 0
|
|
295
373
|
|
|
296
374
|
t0 = monotonic_clock
|
|
297
|
-
assert_equal 0, machine.
|
|
375
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
298
376
|
begin
|
|
299
377
|
machine.periodically(0.01) do
|
|
300
378
|
count += 1
|
|
@@ -304,7 +382,7 @@ class PeriodicallyTest < UMBaseTest
|
|
|
304
382
|
cancel = 1
|
|
305
383
|
end
|
|
306
384
|
machine.snooze
|
|
307
|
-
assert_equal 0, machine.
|
|
385
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
308
386
|
t1 = monotonic_clock
|
|
309
387
|
assert_in_range 0.05..0.09, t1 - t0
|
|
310
388
|
assert_equal 5, count
|
|
@@ -316,7 +394,7 @@ class PeriodicallyTest < UMBaseTest
|
|
|
316
394
|
cancel = 0
|
|
317
395
|
|
|
318
396
|
t0 = monotonic_clock
|
|
319
|
-
assert_equal 0, machine.
|
|
397
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
320
398
|
begin
|
|
321
399
|
machine.timeout(0.05, Cancel) do
|
|
322
400
|
machine.periodically(0.01) do
|
|
@@ -327,25 +405,45 @@ class PeriodicallyTest < UMBaseTest
|
|
|
327
405
|
rescue Cancel
|
|
328
406
|
cancel = 1
|
|
329
407
|
end
|
|
330
|
-
|
|
331
|
-
assert_equal 0, machine.pending_count
|
|
408
|
+
assert_equal 1, cancel
|
|
332
409
|
t1 = monotonic_clock
|
|
333
410
|
assert_in_range 0.05..0.08, t1 - t0
|
|
334
411
|
assert_in_range 4..6, count
|
|
335
|
-
assert_equal 1, cancel
|
|
336
412
|
|
|
337
413
|
end
|
|
338
414
|
end
|
|
339
415
|
|
|
416
|
+
class StatsTest < UMBaseTest
|
|
417
|
+
def test_op_counts
|
|
418
|
+
_r, w = IO.pipe
|
|
419
|
+
|
|
420
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
421
|
+
assert_equal 0, machine.metrics[:total_ops]
|
|
422
|
+
machine.write_async(w.fileno, 'foo')
|
|
423
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
424
|
+
assert_equal 1, machine.metrics[:total_ops]
|
|
425
|
+
machine.snooze
|
|
426
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
427
|
+
assert_equal 1, machine.metrics[:total_ops]
|
|
428
|
+
|
|
429
|
+
machine.write_async(w.fileno, 'foo')
|
|
430
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
431
|
+
assert_equal 2, machine.metrics[:total_ops]
|
|
432
|
+
machine.snooze
|
|
433
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
434
|
+
assert_equal 2, machine.metrics[:total_ops]
|
|
435
|
+
end
|
|
436
|
+
end
|
|
437
|
+
|
|
340
438
|
class ReadTest < UMBaseTest
|
|
341
439
|
def test_read
|
|
342
440
|
r, w = IO.pipe
|
|
343
441
|
w << 'foobar'
|
|
344
442
|
|
|
345
443
|
buf = +''
|
|
346
|
-
assert_equal 0, machine.
|
|
444
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
347
445
|
res = machine.read(r.fileno, buf, 3)
|
|
348
|
-
assert_equal 0, machine.
|
|
446
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
349
447
|
assert_equal 3, res
|
|
350
448
|
assert_equal 'foo', buf
|
|
351
449
|
|
|
@@ -367,7 +465,7 @@ class ReadTest < UMBaseTest
|
|
|
367
465
|
assert_raises(Errno::EBADF) do
|
|
368
466
|
machine.read(w.fileno, +'', 8192)
|
|
369
467
|
end
|
|
370
|
-
assert_equal 0, machine.
|
|
468
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
371
469
|
end
|
|
372
470
|
|
|
373
471
|
def test_read_with_buffer_offset
|
|
@@ -464,6 +562,20 @@ class ReadTest < UMBaseTest
|
|
|
464
562
|
machine.read(r, [])
|
|
465
563
|
}
|
|
466
564
|
end
|
|
565
|
+
|
|
566
|
+
def test_read_with_file_offset
|
|
567
|
+
fn = "/tmp/um_#{SecureRandom.hex}"
|
|
568
|
+
IO.write(fn, 'foobar')
|
|
569
|
+
|
|
570
|
+
fd = machine.open(fn, UM::O_RDONLY)
|
|
571
|
+
buffer = +''
|
|
572
|
+
result = machine.read(fd, buffer, 100, 0, 2)
|
|
573
|
+
assert_equal 4, result
|
|
574
|
+
assert_equal 'obar', buffer
|
|
575
|
+
ensure
|
|
576
|
+
machine.close(fd)
|
|
577
|
+
FileUtils.rm(fn) rescue nil
|
|
578
|
+
end
|
|
467
579
|
end
|
|
468
580
|
|
|
469
581
|
class ReadEachTest < UMBaseTest
|
|
@@ -483,7 +595,7 @@ class ReadEachTest < UMBaseTest
|
|
|
483
595
|
w << 'baz'
|
|
484
596
|
machine.sleep 0.02
|
|
485
597
|
w.close
|
|
486
|
-
machine.
|
|
598
|
+
machine.switch
|
|
487
599
|
end
|
|
488
600
|
|
|
489
601
|
machine.schedule(f, nil)
|
|
@@ -493,7 +605,7 @@ class ReadEachTest < UMBaseTest
|
|
|
493
605
|
end
|
|
494
606
|
|
|
495
607
|
assert_equal ['foo', 'bar', 'baz'], bufs
|
|
496
|
-
assert_equal 0, machine.
|
|
608
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
497
609
|
end
|
|
498
610
|
|
|
499
611
|
# send once and close write fd
|
|
@@ -517,7 +629,7 @@ class ReadEachTest < UMBaseTest
|
|
|
517
629
|
|
|
518
630
|
assert_kind_of RuntimeError, e
|
|
519
631
|
assert_equal 'hi', e.message
|
|
520
|
-
assert_equal 0, machine.
|
|
632
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
521
633
|
end
|
|
522
634
|
|
|
523
635
|
# send once and leave write fd open
|
|
@@ -542,7 +654,7 @@ class ReadEachTest < UMBaseTest
|
|
|
542
654
|
assert_equal 'hi', e.message
|
|
543
655
|
|
|
544
656
|
machine.snooze # in case the final CQE has not yet arrived
|
|
545
|
-
assert_equal 0, machine.
|
|
657
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
546
658
|
end
|
|
547
659
|
|
|
548
660
|
# send twice
|
|
@@ -568,7 +680,7 @@ class ReadEachTest < UMBaseTest
|
|
|
568
680
|
assert_equal 'hi', e.message
|
|
569
681
|
|
|
570
682
|
machine.snooze # in case the final CQE has not yet arrived
|
|
571
|
-
assert_equal 0, machine.
|
|
683
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
572
684
|
end
|
|
573
685
|
|
|
574
686
|
def test_read_each_break
|
|
@@ -592,7 +704,7 @@ class ReadEachTest < UMBaseTest
|
|
|
592
704
|
|
|
593
705
|
assert_equal ['foo'], bufs
|
|
594
706
|
machine.snooze # in case the final CQE has not yet arrived
|
|
595
|
-
assert_equal 0, machine.
|
|
707
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
596
708
|
ensure
|
|
597
709
|
t&.kill
|
|
598
710
|
end
|
|
@@ -613,23 +725,43 @@ class WriteTest < UMBaseTest
|
|
|
613
725
|
def test_write
|
|
614
726
|
r, w = IO.pipe
|
|
615
727
|
|
|
616
|
-
assert_equal 0, machine.
|
|
617
|
-
machine.write(w.fileno, 'foo')
|
|
618
|
-
assert_equal
|
|
728
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
729
|
+
res = machine.write(w.fileno, 'foo')
|
|
730
|
+
assert_equal 3, res
|
|
731
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
619
732
|
assert_equal 'foo', r.readpartial(3)
|
|
620
733
|
|
|
621
|
-
machine.write(w.fileno, 'bar', 2)
|
|
734
|
+
res = machine.write(w.fileno, 'bar', 2)
|
|
735
|
+
assert_equal 2, res
|
|
622
736
|
assert_equal 'ba', r.readpartial(3)
|
|
623
737
|
end
|
|
624
738
|
|
|
625
739
|
def test_write_bad_fd
|
|
626
740
|
r, _w = IO.pipe
|
|
627
741
|
|
|
628
|
-
assert_equal 0, machine.
|
|
742
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
629
743
|
assert_raises(Errno::EBADF) do
|
|
630
744
|
machine.write(r.fileno, 'foo')
|
|
631
745
|
end
|
|
632
|
-
assert_equal 0, machine.
|
|
746
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def test_write_zero_length
|
|
750
|
+
r, w = IO.pipe
|
|
751
|
+
|
|
752
|
+
res = machine.write(w.fileno, '')
|
|
753
|
+
assert_equal 0, res
|
|
754
|
+
|
|
755
|
+
res = machine.write(w.fileno, 'bar', 0)
|
|
756
|
+
assert_equal 0, res
|
|
757
|
+
|
|
758
|
+
buf = IO::Buffer.new(3)
|
|
759
|
+
buf.set_string('baz')
|
|
760
|
+
res = machine.write(w.fileno, buf, 0, 0)
|
|
761
|
+
assert_equal 0, res
|
|
762
|
+
|
|
763
|
+
w.close
|
|
764
|
+
assert_equal '', r.read
|
|
633
765
|
end
|
|
634
766
|
|
|
635
767
|
def test_write_io_buffer
|
|
@@ -679,45 +811,58 @@ class WriteTest < UMBaseTest
|
|
|
679
811
|
machine.write(w, [])
|
|
680
812
|
}
|
|
681
813
|
end
|
|
814
|
+
|
|
815
|
+
def test_write_with_file_offset
|
|
816
|
+
fn = "/tmp/um_#{SecureRandom.hex}"
|
|
817
|
+
IO.write(fn, 'foobar')
|
|
818
|
+
|
|
819
|
+
fd = machine.open(fn, UM::O_WRONLY)
|
|
820
|
+
result = machine.write(fd, 'baz', -1, 2)
|
|
821
|
+
assert_equal 3, result
|
|
822
|
+
assert_equal 'fobazr', IO.read(fn)
|
|
823
|
+
ensure
|
|
824
|
+
machine.close(fd)
|
|
825
|
+
FileUtils.rm(fn) rescue nil
|
|
826
|
+
end
|
|
682
827
|
end
|
|
683
828
|
|
|
684
829
|
class WriteAsyncTest < UMBaseTest
|
|
685
830
|
def test_write_async
|
|
686
831
|
r, w = IO.pipe
|
|
687
832
|
|
|
688
|
-
assert_equal 0, machine.
|
|
833
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
689
834
|
machine.write_async(w.fileno, 'foo')
|
|
690
|
-
assert_equal 1, machine.
|
|
835
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
691
836
|
|
|
692
|
-
machine.snooze
|
|
693
|
-
assert_equal 0, machine.
|
|
837
|
+
machine.snooze while machine.metrics[:ops_pending] > 0
|
|
838
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
694
839
|
assert_equal 'foo', r.readpartial(3)
|
|
695
840
|
end
|
|
696
841
|
|
|
697
842
|
def test_write_async_dynamic_string
|
|
698
843
|
r, w = IO.pipe
|
|
699
844
|
|
|
700
|
-
assert_equal 0, machine.
|
|
845
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
701
846
|
str = "foo#{123}#{'bar' * 48}"
|
|
702
847
|
len = str.bytesize
|
|
703
848
|
machine.write_async(w.fileno, str)
|
|
704
849
|
str = nil
|
|
705
|
-
GC.start
|
|
706
|
-
assert_equal 1, machine.
|
|
850
|
+
# GC.start
|
|
851
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
707
852
|
|
|
708
|
-
machine.snooze
|
|
709
|
-
assert_equal 0, machine.
|
|
853
|
+
machine.snooze while machine.metrics[:ops_pending] > 0
|
|
854
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
710
855
|
assert_equal "foo#{123}#{'bar' * 48}", r.readpartial(len)
|
|
711
856
|
end
|
|
712
857
|
|
|
713
858
|
def test_write_async_bad_fd
|
|
714
859
|
r, _w = IO.pipe
|
|
715
860
|
|
|
716
|
-
assert_equal 0, machine.
|
|
861
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
717
862
|
machine.write_async(r.fileno, 'foo')
|
|
718
|
-
assert_equal 1, machine.
|
|
863
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
719
864
|
machine.snooze
|
|
720
|
-
assert_equal 0, machine.
|
|
865
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
721
866
|
end
|
|
722
867
|
|
|
723
868
|
def test_write_async_io_buffer
|
|
@@ -728,7 +873,7 @@ class WriteAsyncTest < UMBaseTest
|
|
|
728
873
|
write_buffer.set_string(msg)
|
|
729
874
|
|
|
730
875
|
machine.write_async(w, write_buffer)
|
|
731
|
-
|
|
876
|
+
machine.snooze while machine.metrics[:ops_pending] > 0
|
|
732
877
|
machine.close(w)
|
|
733
878
|
|
|
734
879
|
str = +''
|
|
@@ -741,6 +886,33 @@ class WriteAsyncTest < UMBaseTest
|
|
|
741
886
|
|
|
742
887
|
assert_raises(UM::Error) { machine.write_async(w, []) }
|
|
743
888
|
end
|
|
889
|
+
|
|
890
|
+
def test_write_async_with_len
|
|
891
|
+
r, w = IO.pipe
|
|
892
|
+
|
|
893
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
894
|
+
machine.write_async(w.fileno, 'foobar', 4)
|
|
895
|
+
|
|
896
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
897
|
+
machine.snooze while machine.metrics[:ops_pending] > 0
|
|
898
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
899
|
+
assert_equal 'foob', r.readpartial(6)
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
def test_write_async_with_file_offset
|
|
903
|
+
fn = "/tmp/um_#{SecureRandom.hex}"
|
|
904
|
+
IO.write(fn, 'foobar')
|
|
905
|
+
|
|
906
|
+
fd = machine.open(fn, UM::O_WRONLY)
|
|
907
|
+
machine.write_async(fd, 'baz', -1, 2)
|
|
908
|
+
|
|
909
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
910
|
+
machine.snooze while machine.metrics[:ops_pending] > 0
|
|
911
|
+
assert_equal 'fobazr', IO.read(fn)
|
|
912
|
+
ensure
|
|
913
|
+
machine.close(fd)
|
|
914
|
+
FileUtils.rm(fn) rescue nil
|
|
915
|
+
end
|
|
744
916
|
end
|
|
745
917
|
|
|
746
918
|
class CloseTest < UMBaseTest
|
|
@@ -749,9 +921,9 @@ class CloseTest < UMBaseTest
|
|
|
749
921
|
machine.write(w.fileno, 'foo')
|
|
750
922
|
assert_equal 'foo', r.readpartial(3)
|
|
751
923
|
|
|
752
|
-
assert_equal 0, machine.
|
|
924
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
753
925
|
machine.close(w.fileno)
|
|
754
|
-
assert_equal 0, machine.
|
|
926
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
755
927
|
assert_equal '', r.read
|
|
756
928
|
|
|
757
929
|
assert_raises(Errno::EBADF) { machine.close(w.fileno) }
|
|
@@ -771,18 +943,18 @@ class CloseAsyncTest < UMBaseTest
|
|
|
771
943
|
machine.write(w.fileno, 'foo')
|
|
772
944
|
assert_equal 'foo', r.readpartial(3)
|
|
773
945
|
|
|
774
|
-
assert_equal 0, machine.
|
|
775
|
-
machine.close_async(w.fileno)
|
|
776
|
-
assert_equal 1, machine.
|
|
946
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
947
|
+
machine.close_async(w.fileno) # fire and forget
|
|
948
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
777
949
|
machine.snooze
|
|
778
|
-
assert_equal 0, machine.
|
|
950
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
779
951
|
assert_equal '', r.read
|
|
780
952
|
end
|
|
781
953
|
end
|
|
782
954
|
|
|
783
955
|
class ShutdownTest < UMBaseTest
|
|
784
956
|
def test_shutdown
|
|
785
|
-
c_fd, s_fd =
|
|
957
|
+
c_fd, s_fd = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
786
958
|
res = @machine.send(c_fd, 'abc', 3, 0)
|
|
787
959
|
assert_equal 3, res
|
|
788
960
|
|
|
@@ -814,7 +986,7 @@ end
|
|
|
814
986
|
|
|
815
987
|
class ShutdownAsyncTest < UMBaseTest
|
|
816
988
|
def test_shutdown_async
|
|
817
|
-
c_fd, s_fd =
|
|
989
|
+
c_fd, s_fd = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
818
990
|
res = @machine.send(c_fd, 'abc', 3, 0)
|
|
819
991
|
assert_equal 3, res
|
|
820
992
|
|
|
@@ -858,9 +1030,9 @@ class AcceptTest < UMBaseTest
|
|
|
858
1030
|
def test_accept
|
|
859
1031
|
conn = TCPSocket.new('127.0.0.1', @port)
|
|
860
1032
|
|
|
861
|
-
assert_equal 0, machine.
|
|
1033
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
862
1034
|
fd = machine.accept(@server.fileno)
|
|
863
|
-
assert_equal 0, machine.
|
|
1035
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
864
1036
|
assert_kind_of Integer, fd
|
|
865
1037
|
assert fd > 0
|
|
866
1038
|
|
|
@@ -897,7 +1069,7 @@ class AcceptEachTest < UMBaseTest
|
|
|
897
1069
|
end
|
|
898
1070
|
|
|
899
1071
|
assert_equal 3, count
|
|
900
|
-
assert_equal 0, machine.
|
|
1072
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
901
1073
|
ensure
|
|
902
1074
|
t&.kill
|
|
903
1075
|
end
|
|
@@ -932,9 +1104,9 @@ end
|
|
|
932
1104
|
|
|
933
1105
|
class SocketTest < UMBaseTest
|
|
934
1106
|
def test_socket
|
|
935
|
-
assert_equal 0, machine.
|
|
1107
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
936
1108
|
fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0);
|
|
937
|
-
assert_equal 0, machine.
|
|
1109
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
938
1110
|
assert_kind_of Integer, fd
|
|
939
1111
|
assert fd > 0
|
|
940
1112
|
|
|
@@ -962,9 +1134,9 @@ class ConnectTest < UMBaseTest
|
|
|
962
1134
|
end
|
|
963
1135
|
|
|
964
1136
|
fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
|
|
965
|
-
assert_equal 0, machine.
|
|
1137
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
966
1138
|
res = machine.connect(fd, '127.0.0.1', @port)
|
|
967
|
-
assert_equal 0, machine.
|
|
1139
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
968
1140
|
assert_equal 0, res
|
|
969
1141
|
|
|
970
1142
|
buf = +''
|
|
@@ -977,9 +1149,9 @@ class ConnectTest < UMBaseTest
|
|
|
977
1149
|
|
|
978
1150
|
def test_connect_with_bad_addr
|
|
979
1151
|
fd = machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0);
|
|
980
|
-
assert_equal 0, machine.
|
|
1152
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
981
1153
|
assert_raises(Errno::ENETUNREACH) { machine.connect(fd, 'a.b.c.d', @port) }
|
|
982
|
-
assert_equal 0, machine.
|
|
1154
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
983
1155
|
end
|
|
984
1156
|
end
|
|
985
1157
|
|
|
@@ -1195,11 +1367,11 @@ class BindTest < UMBaseTest
|
|
|
1195
1367
|
end
|
|
1196
1368
|
|
|
1197
1369
|
def test_bind
|
|
1198
|
-
assert_equal 0, machine.
|
|
1370
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1199
1371
|
fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
|
|
1200
1372
|
res = machine.bind(fd, '127.0.0.1', @port)
|
|
1201
1373
|
assert_equal 0, res
|
|
1202
|
-
assert_equal 0, machine.
|
|
1374
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1203
1375
|
|
|
1204
1376
|
peer = UDPSocket.new
|
|
1205
1377
|
peer.connect('127.0.0.1', @port)
|
|
@@ -1212,13 +1384,13 @@ class BindTest < UMBaseTest
|
|
|
1212
1384
|
end
|
|
1213
1385
|
|
|
1214
1386
|
def test_bind_invalid_args
|
|
1215
|
-
assert_equal 0, machine.
|
|
1387
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1216
1388
|
|
|
1217
1389
|
fd = machine.socket(UM::AF_INET, UM::SOCK_DGRAM, 0, 0)
|
|
1218
1390
|
assert_raises(Errno::EACCES) { machine.bind(fd, 'foo.bar.baz', 3) }
|
|
1219
1391
|
assert_raises(Errno::EBADF) { machine.bind(-3, '127.0.01', 1234) }
|
|
1220
1392
|
|
|
1221
|
-
assert_equal 0, machine.
|
|
1393
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1222
1394
|
end
|
|
1223
1395
|
end
|
|
1224
1396
|
|
|
@@ -1233,7 +1405,7 @@ class ListenTest < UMBaseTest
|
|
|
1233
1405
|
machine.bind(fd, '127.0.0.1', @port)
|
|
1234
1406
|
res = machine.listen(fd, 5)
|
|
1235
1407
|
assert_equal 0, res
|
|
1236
|
-
assert_equal 0, machine.
|
|
1408
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1237
1409
|
|
|
1238
1410
|
conn = nil
|
|
1239
1411
|
t = Thread.new do
|
|
@@ -1276,8 +1448,6 @@ end
|
|
|
1276
1448
|
|
|
1277
1449
|
class SynchronizeTest < UMBaseTest
|
|
1278
1450
|
def test_synchronize_single
|
|
1279
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1280
|
-
|
|
1281
1451
|
m = UM::Mutex.new
|
|
1282
1452
|
|
|
1283
1453
|
buf = []
|
|
@@ -1289,13 +1459,11 @@ class SynchronizeTest < UMBaseTest
|
|
|
1289
1459
|
end
|
|
1290
1460
|
|
|
1291
1461
|
assert_equal [1, 2], buf
|
|
1292
|
-
assert_equal 0, machine.
|
|
1462
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1293
1463
|
end
|
|
1294
1464
|
|
|
1295
1465
|
def test_synchronize_pair
|
|
1296
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1297
1466
|
m = UM::Mutex.new
|
|
1298
|
-
|
|
1299
1467
|
buf = []
|
|
1300
1468
|
|
|
1301
1469
|
f1 = Fiber.new do
|
|
@@ -1305,7 +1473,7 @@ class SynchronizeTest < UMBaseTest
|
|
|
1305
1473
|
buf << 12
|
|
1306
1474
|
end
|
|
1307
1475
|
buf << 13
|
|
1308
|
-
machine.
|
|
1476
|
+
machine.switch
|
|
1309
1477
|
end
|
|
1310
1478
|
|
|
1311
1479
|
f2 = Fiber.new do
|
|
@@ -1315,7 +1483,7 @@ class SynchronizeTest < UMBaseTest
|
|
|
1315
1483
|
buf << 22
|
|
1316
1484
|
end
|
|
1317
1485
|
buf << 23
|
|
1318
|
-
machine.
|
|
1486
|
+
machine.switch
|
|
1319
1487
|
end
|
|
1320
1488
|
|
|
1321
1489
|
machine.schedule(f1, nil)
|
|
@@ -1323,7 +1491,7 @@ class SynchronizeTest < UMBaseTest
|
|
|
1323
1491
|
|
|
1324
1492
|
machine.sleep(0.03)
|
|
1325
1493
|
assert_equal [11, 12, 13, 21, 22, 23], buf
|
|
1326
|
-
assert_equal 0, machine.
|
|
1494
|
+
assert_equal 0, machine.metrics[:ops_pending]
|
|
1327
1495
|
end
|
|
1328
1496
|
|
|
1329
1497
|
def test_synchronize_multi
|
|
@@ -1348,8 +1516,6 @@ end
|
|
|
1348
1516
|
|
|
1349
1517
|
class QueueTest < UMBaseTest
|
|
1350
1518
|
def test_push_pop_1
|
|
1351
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1352
|
-
|
|
1353
1519
|
q = UM::Queue.new
|
|
1354
1520
|
assert_equal 0, q.count
|
|
1355
1521
|
machine.push(q, :foo)
|
|
@@ -1363,8 +1529,6 @@ class QueueTest < UMBaseTest
|
|
|
1363
1529
|
end
|
|
1364
1530
|
|
|
1365
1531
|
def test_push_pop_2
|
|
1366
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1367
|
-
|
|
1368
1532
|
q = UM::Queue.new
|
|
1369
1533
|
buf = []
|
|
1370
1534
|
|
|
@@ -1378,12 +1542,12 @@ class QueueTest < UMBaseTest
|
|
|
1378
1542
|
|
|
1379
1543
|
machine.snooze
|
|
1380
1544
|
assert_equal [], buf
|
|
1381
|
-
assert_equal 2, machine.
|
|
1545
|
+
assert_equal 2, machine.metrics[:ops_pending]
|
|
1382
1546
|
|
|
1383
1547
|
machine.push(q, :foo)
|
|
1384
1548
|
assert_equal 1, q.count
|
|
1385
1549
|
machine.snooze
|
|
1386
|
-
assert_equal 1, machine.
|
|
1550
|
+
assert_equal 1, machine.metrics[:ops_pending]
|
|
1387
1551
|
assert_equal [[1, :foo]], buf
|
|
1388
1552
|
|
|
1389
1553
|
machine.push(q, :bar)
|
|
@@ -1395,8 +1559,6 @@ class QueueTest < UMBaseTest
|
|
|
1395
1559
|
end
|
|
1396
1560
|
|
|
1397
1561
|
def test_push_pop_3
|
|
1398
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1399
|
-
|
|
1400
1562
|
q = UM::Queue.new
|
|
1401
1563
|
buf = []
|
|
1402
1564
|
|
|
@@ -1406,13 +1568,13 @@ class QueueTest < UMBaseTest
|
|
|
1406
1568
|
|
|
1407
1569
|
f1 = Fiber.new do
|
|
1408
1570
|
buf << [1, machine.pop(q)]
|
|
1409
|
-
machine.
|
|
1571
|
+
machine.switch
|
|
1410
1572
|
end
|
|
1411
1573
|
machine.schedule(f1, nil)
|
|
1412
1574
|
|
|
1413
1575
|
f2 = Fiber.new do
|
|
1414
1576
|
buf << [2, machine.pop(q)]
|
|
1415
|
-
machine.
|
|
1577
|
+
machine.switch
|
|
1416
1578
|
end
|
|
1417
1579
|
machine.schedule(f2, nil)
|
|
1418
1580
|
|
|
@@ -1423,8 +1585,6 @@ class QueueTest < UMBaseTest
|
|
|
1423
1585
|
end
|
|
1424
1586
|
|
|
1425
1587
|
def test_push_pop_4
|
|
1426
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1427
|
-
|
|
1428
1588
|
q = UM::Queue.new
|
|
1429
1589
|
buf = []
|
|
1430
1590
|
|
|
@@ -1433,13 +1593,13 @@ class QueueTest < UMBaseTest
|
|
|
1433
1593
|
|
|
1434
1594
|
f1 = Fiber.new do
|
|
1435
1595
|
buf << [1, machine.pop(q)]
|
|
1436
|
-
machine.
|
|
1596
|
+
machine.switch
|
|
1437
1597
|
end
|
|
1438
1598
|
machine.schedule(f1, nil)
|
|
1439
1599
|
|
|
1440
1600
|
f2 = Fiber.new do
|
|
1441
1601
|
buf << [2, machine.pop(q)]
|
|
1442
|
-
machine.
|
|
1602
|
+
machine.switch
|
|
1443
1603
|
end
|
|
1444
1604
|
machine.schedule(f2, nil)
|
|
1445
1605
|
|
|
@@ -1452,8 +1612,6 @@ class QueueTest < UMBaseTest
|
|
|
1452
1612
|
end
|
|
1453
1613
|
|
|
1454
1614
|
def test_push_shift_1
|
|
1455
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1456
|
-
|
|
1457
1615
|
q = UM::Queue.new
|
|
1458
1616
|
|
|
1459
1617
|
machine.push(q, :foo)
|
|
@@ -1466,8 +1624,6 @@ class QueueTest < UMBaseTest
|
|
|
1466
1624
|
end
|
|
1467
1625
|
|
|
1468
1626
|
def test_shift_shift_1
|
|
1469
|
-
skip if !machine.respond_to?(:synchronize)
|
|
1470
|
-
|
|
1471
1627
|
q = UM::Queue.new
|
|
1472
1628
|
|
|
1473
1629
|
machine.unshift(q, :foo)
|
|
@@ -1479,6 +1635,15 @@ class QueueTest < UMBaseTest
|
|
|
1479
1635
|
assert_equal :foo, machine.shift(q)
|
|
1480
1636
|
end
|
|
1481
1637
|
|
|
1638
|
+
def test_shift_exception_value
|
|
1639
|
+
q = UM::Queue.new
|
|
1640
|
+
machine.unshift(q, Exception.new("foo"))
|
|
1641
|
+
|
|
1642
|
+
e = machine.shift(q)
|
|
1643
|
+
assert_kind_of Exception, e
|
|
1644
|
+
assert_equal "foo", e.message
|
|
1645
|
+
end
|
|
1646
|
+
|
|
1482
1647
|
def test_cross_thread_push_shift
|
|
1483
1648
|
q = UM::Queue.new
|
|
1484
1649
|
|
|
@@ -1502,41 +1667,79 @@ class QueueTest < UMBaseTest
|
|
|
1502
1667
|
|
|
1503
1668
|
assert_equal [0, 1, 2], items
|
|
1504
1669
|
end
|
|
1670
|
+
|
|
1671
|
+
def test_cross_thread_cross_queue_comms
|
|
1672
|
+
worker_queue = UM::Queue.new
|
|
1673
|
+
|
|
1674
|
+
buf = []
|
|
1675
|
+
t1 = Thread.new {
|
|
1676
|
+
m = UM.new
|
|
1677
|
+
(1..10).each {
|
|
1678
|
+
q = UM::Queue.new
|
|
1679
|
+
m.push(worker_queue, [q, it])
|
|
1680
|
+
res = m.shift(q)
|
|
1681
|
+
buf << res
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
t2 = Thread.new {
|
|
1686
|
+
m = UM.new
|
|
1687
|
+
loop do
|
|
1688
|
+
q, v = m.shift(worker_queue)
|
|
1689
|
+
break if q == :STOP
|
|
1690
|
+
|
|
1691
|
+
res = v * 10
|
|
1692
|
+
m.push(q, res)
|
|
1693
|
+
end
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
t1.join
|
|
1697
|
+
q = UM::Queue.new
|
|
1698
|
+
machine.push(worker_queue, :STOP)
|
|
1699
|
+
t2.join
|
|
1700
|
+
|
|
1701
|
+
assert_equal (1..10).map { it * 10 }, buf
|
|
1702
|
+
ensure
|
|
1703
|
+
t1.kill rescue nil
|
|
1704
|
+
t2.kill rescue nil
|
|
1705
|
+
end
|
|
1505
1706
|
end
|
|
1506
1707
|
|
|
1507
1708
|
class OpenTest < UMBaseTest
|
|
1508
|
-
PATH = '/tmp/um_open_test'
|
|
1509
|
-
|
|
1510
1709
|
def setup
|
|
1511
1710
|
super
|
|
1512
|
-
|
|
1711
|
+
@fn = "/tmp/um_#{SecureRandom.hex}"
|
|
1712
|
+
end
|
|
1713
|
+
|
|
1714
|
+
def teardown
|
|
1715
|
+
FileUtils.rm(@fn) rescue nil
|
|
1513
1716
|
end
|
|
1514
1717
|
|
|
1515
1718
|
def test_open
|
|
1516
|
-
fd = machine.open(
|
|
1719
|
+
fd = machine.open(@fn, UM::O_CREAT | UM::O_WRONLY)
|
|
1517
1720
|
assert_kind_of Integer, fd
|
|
1518
|
-
assert File.file?(
|
|
1721
|
+
assert File.file?(@fn)
|
|
1519
1722
|
|
|
1520
1723
|
machine.write(fd, 'foo')
|
|
1521
1724
|
machine.close(fd)
|
|
1522
1725
|
|
|
1523
|
-
assert_equal 'foo', IO.read(
|
|
1726
|
+
assert_equal 'foo', IO.read(@fn)
|
|
1524
1727
|
end
|
|
1525
1728
|
|
|
1526
1729
|
def test_open_with_block
|
|
1527
|
-
res = machine.open(
|
|
1730
|
+
res = machine.open(@fn, UM::O_CREAT | UM::O_WRONLY) do |fd|
|
|
1528
1731
|
machine.write(fd, 'bar')
|
|
1529
1732
|
fd
|
|
1530
1733
|
end
|
|
1531
1734
|
|
|
1532
1735
|
assert_kind_of Integer, res
|
|
1533
1736
|
assert_raises(Errno::EBADF) { machine.close(res) }
|
|
1534
|
-
assert_equal 'bar', IO.read(
|
|
1737
|
+
assert_equal 'bar', IO.read(@fn)
|
|
1535
1738
|
end
|
|
1536
1739
|
|
|
1537
1740
|
def test_open_bad_arg
|
|
1538
|
-
assert_raises(Errno::ENOENT) { machine.open(
|
|
1539
|
-
assert_raises(Errno::ENOENT) { machine.open(
|
|
1741
|
+
assert_raises(Errno::ENOENT) { machine.open(@fn, UM::O_RDONLY) }
|
|
1742
|
+
assert_raises(Errno::ENOENT) { machine.open(@fn, UM::O_RDONLY) {} }
|
|
1540
1743
|
end
|
|
1541
1744
|
end
|
|
1542
1745
|
|
|
@@ -1560,6 +1763,26 @@ class PipeTest < UMBaseTest
|
|
|
1560
1763
|
end
|
|
1561
1764
|
end
|
|
1562
1765
|
|
|
1766
|
+
class SocketpairTest < UMBaseTest
|
|
1767
|
+
def test_socketpair
|
|
1768
|
+
rfd, wfd = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
1769
|
+
ret = machine.write(wfd, 'foo')
|
|
1770
|
+
assert_equal 3, ret
|
|
1771
|
+
|
|
1772
|
+
ret = machine.close(wfd)
|
|
1773
|
+
assert_equal wfd, ret
|
|
1774
|
+
|
|
1775
|
+
buf = +''
|
|
1776
|
+
ret = machine.read(rfd, buf, 8192)
|
|
1777
|
+
|
|
1778
|
+
assert_equal 3, ret
|
|
1779
|
+
assert_equal 'foo', buf
|
|
1780
|
+
|
|
1781
|
+
ret = machine.close(rfd)
|
|
1782
|
+
assert_equal rfd, ret
|
|
1783
|
+
end
|
|
1784
|
+
end
|
|
1785
|
+
|
|
1563
1786
|
class PidfdTest < UMBaseTest
|
|
1564
1787
|
def test_pidfd_open
|
|
1565
1788
|
pid = fork { exit 13 }
|
|
@@ -1646,6 +1869,85 @@ class PollTest < UMBaseTest
|
|
|
1646
1869
|
end
|
|
1647
1870
|
end
|
|
1648
1871
|
|
|
1872
|
+
class SelectTest < UMBaseTest
|
|
1873
|
+
def test_select
|
|
1874
|
+
rfd1, wfd1 = UM.pipe
|
|
1875
|
+
rfd2, wfd2 = UM.pipe
|
|
1876
|
+
|
|
1877
|
+
events = []
|
|
1878
|
+
machine.spin do
|
|
1879
|
+
events << 1
|
|
1880
|
+
events << machine.select([rfd1, rfd2], [], [])
|
|
1881
|
+
events << 2
|
|
1882
|
+
events << machine.select([rfd1, rfd2], [], [])
|
|
1883
|
+
events << 3
|
|
1884
|
+
machine.snooze
|
|
1885
|
+
events << machine.select([], [wfd1, wfd2], [])
|
|
1886
|
+
events << 4
|
|
1887
|
+
end
|
|
1888
|
+
|
|
1889
|
+
machine.snooze
|
|
1890
|
+
assert_equal [1], events
|
|
1891
|
+
|
|
1892
|
+
machine.write(wfd1, 'foo')
|
|
1893
|
+
machine.snooze
|
|
1894
|
+
assert_equal [1, [[rfd1], [], []], 2], events
|
|
1895
|
+
|
|
1896
|
+
machine.write(wfd2, 'foo')
|
|
1897
|
+
|
|
1898
|
+
machine.snooze
|
|
1899
|
+
assert_equal [1, [[rfd1], [], []], 2, [[rfd1, rfd2], [], []], 3], events
|
|
1900
|
+
|
|
1901
|
+
machine.snooze
|
|
1902
|
+
|
|
1903
|
+
assert_equal [
|
|
1904
|
+
1, [[rfd1], [], []],
|
|
1905
|
+
2, [[rfd1, rfd2], [], []],
|
|
1906
|
+
3, [[], [wfd1, wfd2], []],
|
|
1907
|
+
4
|
|
1908
|
+
], events
|
|
1909
|
+
|
|
1910
|
+
machine.close(rfd1)
|
|
1911
|
+
machine.close(rfd2)
|
|
1912
|
+
end
|
|
1913
|
+
|
|
1914
|
+
def test_select_single
|
|
1915
|
+
rfd1, wfd1 = UM.pipe
|
|
1916
|
+
|
|
1917
|
+
events = []
|
|
1918
|
+
machine.spin do
|
|
1919
|
+
events << 1
|
|
1920
|
+
events << machine.select([rfd1], [], [])
|
|
1921
|
+
events << 2
|
|
1922
|
+
machine.snooze
|
|
1923
|
+
events << machine.select([], [wfd1], [])
|
|
1924
|
+
events << 3
|
|
1925
|
+
end
|
|
1926
|
+
|
|
1927
|
+
machine.snooze
|
|
1928
|
+
assert_equal [1], events
|
|
1929
|
+
|
|
1930
|
+
machine.write(wfd1, 'foo')
|
|
1931
|
+
machine.snooze
|
|
1932
|
+
assert_equal [1, [[rfd1], [], []], 2], events
|
|
1933
|
+
|
|
1934
|
+
3.times { machine.snooze }
|
|
1935
|
+
assert_equal [1, [[rfd1], [], []], 2, [[], [wfd1], []], 3], events
|
|
1936
|
+
|
|
1937
|
+
machine.close(rfd1)
|
|
1938
|
+
machine.close(wfd1)
|
|
1939
|
+
end
|
|
1940
|
+
|
|
1941
|
+
def test_select_empty
|
|
1942
|
+
ret = machine.select([], [], [])
|
|
1943
|
+
assert_equal [[], [], []], ret
|
|
1944
|
+
end
|
|
1945
|
+
|
|
1946
|
+
def test_select_bad_fd
|
|
1947
|
+
assert_raises(Errno::EBADF) { machine.select([9876, 9877], [], []) }
|
|
1948
|
+
end
|
|
1949
|
+
end
|
|
1950
|
+
|
|
1649
1951
|
class WaitidTest < UMBaseTest
|
|
1650
1952
|
def test_waitid
|
|
1651
1953
|
msg = 'hello from child'
|
|
@@ -1892,7 +2194,7 @@ end
|
|
|
1892
2194
|
class SendBundleTest < UMBaseTest
|
|
1893
2195
|
def setup
|
|
1894
2196
|
super
|
|
1895
|
-
@client_fd, @server_fd =
|
|
2197
|
+
@client_fd, @server_fd = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
1896
2198
|
end
|
|
1897
2199
|
|
|
1898
2200
|
def test_send_bundle_splat
|
|
@@ -1966,3 +2268,153 @@ class NonBlockTest < UMBaseTest
|
|
|
1966
2268
|
assert_equal true, UM.io_nonblock?(r)
|
|
1967
2269
|
end
|
|
1968
2270
|
end
|
|
2271
|
+
|
|
2272
|
+
class MetricsTest < UMBaseTest
|
|
2273
|
+
def test_metrics_empty
|
|
2274
|
+
assert_equal({
|
|
2275
|
+
size: 4096,
|
|
2276
|
+
total_ops: 0,
|
|
2277
|
+
total_switches: 0,
|
|
2278
|
+
total_waits: 0,
|
|
2279
|
+
ops_pending: 0,
|
|
2280
|
+
ops_unsubmitted: 0,
|
|
2281
|
+
ops_runqueue: 0,
|
|
2282
|
+
ops_free: 0,
|
|
2283
|
+
ops_transient: 0
|
|
2284
|
+
}, machine.metrics)
|
|
2285
|
+
end
|
|
2286
|
+
|
|
2287
|
+
def test_metrics_size
|
|
2288
|
+
m = UM.new(13)
|
|
2289
|
+
assert_equal 13, m.metrics[:size]
|
|
2290
|
+
end
|
|
2291
|
+
|
|
2292
|
+
def test_metrics_total_counters
|
|
2293
|
+
r, w = UM.pipe
|
|
2294
|
+
machine.write(w, 'foo')
|
|
2295
|
+
assert_equal 1, machine.metrics[:total_ops]
|
|
2296
|
+
assert_equal 1, machine.metrics[:total_switches]
|
|
2297
|
+
assert_equal 1, machine.metrics[:total_waits]
|
|
2298
|
+
machine.write_async(w, 'bar')
|
|
2299
|
+
assert_equal 2, machine.metrics[:total_ops]
|
|
2300
|
+
assert_equal 1, machine.metrics[:total_switches]
|
|
2301
|
+
assert_equal 1, machine.metrics[:total_waits]
|
|
2302
|
+
machine.snooze
|
|
2303
|
+
assert_equal 2, machine.metrics[:total_ops]
|
|
2304
|
+
assert_equal 2, machine.metrics[:total_switches]
|
|
2305
|
+
assert_equal 2, machine.metrics[:total_waits]
|
|
2306
|
+
machine.close(w)
|
|
2307
|
+
assert_equal 3, machine.metrics[:total_ops]
|
|
2308
|
+
assert_equal 3, machine.metrics[:total_switches]
|
|
2309
|
+
assert_equal 3, machine.metrics[:total_waits]
|
|
2310
|
+
ensure
|
|
2311
|
+
machine.close(r) rescue nil
|
|
2312
|
+
machine.close(w) rescue nil
|
|
2313
|
+
end
|
|
2314
|
+
|
|
2315
|
+
def test_metrics_total_switches
|
|
2316
|
+
f1 = machine.spin { 3.times { machine.snooze } }
|
|
2317
|
+
f2 = machine.spin { machine.sleep(0.01) }
|
|
2318
|
+
assert_equal 0, machine.metrics[:total_switches]
|
|
2319
|
+
machine.snooze
|
|
2320
|
+
assert_equal 3, machine.metrics[:total_switches]
|
|
2321
|
+
machine.snooze
|
|
2322
|
+
assert_equal 5, machine.metrics[:total_switches]
|
|
2323
|
+
machine.join(f2)
|
|
2324
|
+
assert_equal 9, machine.metrics[:total_switches]
|
|
2325
|
+
ensure
|
|
2326
|
+
machine.join(f1, f2)
|
|
2327
|
+
end
|
|
2328
|
+
|
|
2329
|
+
def test_metrics_total_waits
|
|
2330
|
+
r, w = UM.pipe
|
|
2331
|
+
|
|
2332
|
+
machine.sleep(0.001)
|
|
2333
|
+
assert_equal 1, machine.metrics[:total_waits]
|
|
2334
|
+
|
|
2335
|
+
machine.write_async(w, 'foo')
|
|
2336
|
+
assert_equal 1, machine.metrics[:total_waits]
|
|
2337
|
+
|
|
2338
|
+
res = machine.read(r, +'', 3)
|
|
2339
|
+
assert_equal 2, machine.metrics[:total_waits]
|
|
2340
|
+
assert_equal 3, res
|
|
2341
|
+
|
|
2342
|
+
machine.close_async(w)
|
|
2343
|
+
assert_equal 2, machine.metrics[:total_waits]
|
|
2344
|
+
|
|
2345
|
+
machine.snooze
|
|
2346
|
+
assert_equal 3, machine.metrics[:total_waits]
|
|
2347
|
+
ensure
|
|
2348
|
+
machine.close(r) rescue nil
|
|
2349
|
+
machine.close(w) rescue nil
|
|
2350
|
+
end
|
|
2351
|
+
|
|
2352
|
+
def ops_metrics
|
|
2353
|
+
machine.metrics.values_at(
|
|
2354
|
+
:ops_pending,
|
|
2355
|
+
:ops_unsubmitted,
|
|
2356
|
+
:ops_runqueue,
|
|
2357
|
+
:ops_free,
|
|
2358
|
+
:ops_transient
|
|
2359
|
+
)
|
|
2360
|
+
end
|
|
2361
|
+
|
|
2362
|
+
def test_metrics_ops
|
|
2363
|
+
r, w = UM.pipe
|
|
2364
|
+
|
|
2365
|
+
f = machine.spin { machine.sleep(0.001) }
|
|
2366
|
+
assert_equal [0, 0, 1, 0, 0], ops_metrics
|
|
2367
|
+
machine.snooze
|
|
2368
|
+
assert_equal [1, 1, 0, 2, 0], ops_metrics
|
|
2369
|
+
machine.submit
|
|
2370
|
+
assert_equal [1, 0, 0, 2, 0], ops_metrics
|
|
2371
|
+
machine.join(f)
|
|
2372
|
+
assert_equal [0, 0, 0, 2, 0], ops_metrics
|
|
2373
|
+
|
|
2374
|
+
machine.write_async(w, 'foo')
|
|
2375
|
+
assert_equal [1, 1, 0, 1, 1], ops_metrics
|
|
2376
|
+
machine.submit
|
|
2377
|
+
assert_equal [1, 0, 0, 1, 1], ops_metrics
|
|
2378
|
+
machine.snooze
|
|
2379
|
+
assert_equal [0, 0, 0, 2, 0], ops_metrics
|
|
2380
|
+
|
|
2381
|
+
machine.write_async(w, 'foo')
|
|
2382
|
+
assert_equal [1, 1, 0, 1, 1], ops_metrics
|
|
2383
|
+
machine.snooze
|
|
2384
|
+
assert_equal [0, 0, 0, 2, 0], ops_metrics
|
|
2385
|
+
ensure
|
|
2386
|
+
machine.join(f)
|
|
2387
|
+
end
|
|
2388
|
+
end
|
|
2389
|
+
|
|
2390
|
+
class ProfileModeTest < UMBaseTest
|
|
2391
|
+
def test_profile_mode_empty
|
|
2392
|
+
assert_equal false, machine.profile?
|
|
2393
|
+
assert_equal([
|
|
2394
|
+
:size, :total_ops, :total_switches, :total_waits, :ops_pending,
|
|
2395
|
+
:ops_unsubmitted, :ops_runqueue, :ops_free, :ops_transient
|
|
2396
|
+
], machine.metrics.keys)
|
|
2397
|
+
|
|
2398
|
+
machine.profile(true)
|
|
2399
|
+
assert_equal true, machine.profile?
|
|
2400
|
+
assert_equal([
|
|
2401
|
+
:size, :total_ops, :total_switches, :total_waits, :ops_pending,
|
|
2402
|
+
:ops_unsubmitted, :ops_runqueue, :ops_free, :ops_transient,
|
|
2403
|
+
:time_total_cpu, :time_total_wait,
|
|
2404
|
+
], machine.metrics.keys)
|
|
2405
|
+
|
|
2406
|
+
machine.profile(false)
|
|
2407
|
+
assert_equal false, machine.profile?
|
|
2408
|
+
assert_equal([
|
|
2409
|
+
:size, :total_ops, :total_switches, :total_waits, :ops_pending,
|
|
2410
|
+
:ops_unsubmitted, :ops_runqueue, :ops_free, :ops_transient
|
|
2411
|
+
], machine.metrics.keys)
|
|
2412
|
+
end
|
|
2413
|
+
|
|
2414
|
+
def test_profile_mode_total_times
|
|
2415
|
+
machine.profile(true)
|
|
2416
|
+
machine.sleep(0.01)
|
|
2417
|
+
assert_in_range 0.0..0.0005, machine.metrics[:time_total_cpu]
|
|
2418
|
+
assert_in_range 0.01..0.015, machine.metrics[:time_total_wait]
|
|
2419
|
+
end
|
|
2420
|
+
end
|