2020-05-14 22:10:55 +12:00
|
|
|
# frozen_string_literal: true
|
|
|
|
require 'test/unit'
|
|
|
|
require_relative 'scheduler'
|
|
|
|
|
2020-05-23 16:43:58 +09:00
|
|
|
class TestFiberMutex < Test::Unit::TestCase
|
2020-05-14 22:10:55 +12:00
|
|
|
def test_mutex_synchronize
|
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-05-14 22:10:55 +12:00
|
|
|
|
2020-08-21 00:52:36 +12:00
|
|
|
Fiber.schedule do
|
2020-10-16 14:25:58 +13:00
|
|
|
assert_not_predicate Fiber, :blocking?
|
2020-05-14 22:10:55 +12:00
|
|
|
|
|
|
|
mutex.synchronize do
|
2020-10-16 14:25:58 +13:00
|
|
|
assert_not_predicate Fiber, :blocking?
|
2020-05-14 22:10:55 +12:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
end
|
|
|
|
|
2020-09-05 16:26:24 +12:00
|
|
|
def test_mutex_interleaved_locking
|
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-09-05 16:26:24 +12:00
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
mutex.lock
|
|
|
|
sleep 0.1
|
|
|
|
mutex.unlock
|
|
|
|
end
|
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
mutex.lock
|
|
|
|
sleep 0.1
|
|
|
|
mutex.unlock
|
|
|
|
end
|
|
|
|
|
|
|
|
scheduler.run
|
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
end
|
|
|
|
|
2020-09-17 15:15:43 +02:00
|
|
|
def test_mutex_thread
|
|
|
|
mutex = Mutex.new
|
|
|
|
mutex.lock
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-09-17 15:15:43 +02:00
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
mutex.lock
|
|
|
|
sleep 0.1
|
|
|
|
mutex.unlock
|
|
|
|
end
|
|
|
|
|
|
|
|
scheduler.run
|
|
|
|
end
|
|
|
|
|
|
|
|
sleep 0.1
|
|
|
|
mutex.unlock
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
end
|
|
|
|
|
2020-09-20 13:29:24 +02:00
|
|
|
def test_mutex_fiber_raise
|
|
|
|
mutex = Mutex.new
|
|
|
|
ran = false
|
|
|
|
|
|
|
|
main = Thread.new do
|
|
|
|
mutex.lock
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-09-20 13:29:24 +02:00
|
|
|
|
|
|
|
f = Fiber.schedule do
|
|
|
|
assert_raise_with_message(RuntimeError, "bye") do
|
|
|
|
mutex.lock
|
|
|
|
end
|
2020-10-01 13:44:23 +13:00
|
|
|
|
2020-09-20 13:29:24 +02:00
|
|
|
ran = true
|
|
|
|
end
|
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
f.raise "bye"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
end
|
|
|
|
|
|
|
|
main.join # causes mutex to be released
|
|
|
|
assert_equal false, mutex.locked?
|
|
|
|
assert_equal true, ran
|
|
|
|
end
|
|
|
|
|
2020-09-11 20:47:25 +12:00
|
|
|
def test_condition_variable
|
|
|
|
mutex = Mutex.new
|
|
|
|
condition = ConditionVariable.new
|
|
|
|
|
|
|
|
signalled = 0
|
|
|
|
|
2020-11-08 16:49:03 +01:00
|
|
|
Thread.new do
|
2020-09-11 20:47:25 +12:00
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-09-11 20:47:25 +12:00
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
mutex.synchronize do
|
|
|
|
3.times do
|
|
|
|
condition.wait(mutex)
|
|
|
|
signalled += 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
3.times do
|
|
|
|
mutex.synchronize do
|
|
|
|
condition.signal
|
|
|
|
end
|
|
|
|
|
|
|
|
sleep 0.1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
scheduler.run
|
2020-11-08 16:49:03 +01:00
|
|
|
end.join
|
2020-09-11 20:47:25 +12:00
|
|
|
|
2020-11-08 16:49:03 +01:00
|
|
|
assert_equal 3, signalled
|
2020-09-11 20:47:25 +12:00
|
|
|
end
|
|
|
|
|
2020-09-14 11:10:02 +12:00
|
|
|
def test_queue
|
|
|
|
queue = Queue.new
|
|
|
|
processed = 0
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-09-14 11:10:02 +12:00
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
3.times do |i|
|
|
|
|
queue << i
|
|
|
|
sleep 0.1
|
|
|
|
end
|
|
|
|
|
|
|
|
queue.close
|
|
|
|
end
|
|
|
|
|
|
|
|
Fiber.schedule do
|
|
|
|
while item = queue.pop
|
|
|
|
processed += 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
scheduler.run
|
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
|
2020-10-01 13:48:15 +09:00
|
|
|
assert_equal 3, processed
|
2020-09-14 11:10:02 +12:00
|
|
|
end
|
|
|
|
|
2020-09-17 14:45:44 +02:00
|
|
|
def test_queue_pop_waits
|
|
|
|
queue = Queue.new
|
|
|
|
running = false
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-09-17 14:45:44 +02:00
|
|
|
|
|
|
|
result = nil
|
|
|
|
Fiber.schedule do
|
|
|
|
result = queue.pop
|
|
|
|
end
|
|
|
|
|
|
|
|
running = true
|
|
|
|
scheduler.run
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
Thread.pass until running
|
|
|
|
sleep 0.1
|
|
|
|
|
|
|
|
queue << :done
|
|
|
|
assert_equal :done, thread.value
|
|
|
|
end
|
|
|
|
|
2020-05-14 22:10:55 +12:00
|
|
|
def test_mutex_deadlock
|
2020-10-01 13:44:23 +13:00
|
|
|
error_pattern = /No live threads left. Deadlock\?/
|
|
|
|
|
|
|
|
assert_in_out_err %W[-I#{__dir__} -], <<-RUBY, ['in synchronize'], error_pattern, success: false
|
2020-09-05 16:26:24 +12:00
|
|
|
require 'scheduler'
|
2020-05-14 22:10:55 +12:00
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
2020-10-16 14:25:58 +13:00
|
|
|
Fiber.set_scheduler scheduler
|
2020-05-14 22:10:55 +12:00
|
|
|
|
2020-08-21 00:52:36 +12:00
|
|
|
Fiber.schedule do
|
2020-05-14 22:10:55 +12:00
|
|
|
mutex.synchronize do
|
2020-09-05 16:26:24 +12:00
|
|
|
puts 'in synchronize'
|
2020-05-14 22:10:55 +12:00
|
|
|
Fiber.yield
|
|
|
|
end
|
|
|
|
end
|
2020-05-14 19:57:39 +09:00
|
|
|
|
2020-09-05 16:26:24 +12:00
|
|
|
mutex.lock
|
2020-05-14 22:10:55 +12:00
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
2020-09-05 16:26:24 +12:00
|
|
|
RUBY
|
2020-05-14 22:10:55 +12:00
|
|
|
end
|
|
|
|
end
|