2020-05-14 06:10:55 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
require 'test/unit'
|
|
|
|
require_relative 'scheduler'
|
|
|
|
|
2020-05-23 03:43:58 -04:00
|
|
|
class TestFiberMutex < Test::Unit::TestCase
|
2020-05-14 06:10:55 -04:00
|
|
|
def test_mutex_synchronize
|
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
2020-08-20 08:52:36 -04:00
|
|
|
Fiber.schedule do
|
2020-10-01 00:48:15 -04:00
|
|
|
assert_not_predicate Thread.current, :blocking?
|
2020-05-14 06:10:55 -04:00
|
|
|
|
|
|
|
mutex.synchronize do
|
2020-10-01 00:48:15 -04:00
|
|
|
assert_not_predicate Thread.current, :blocking?
|
2020-05-14 06:10:55 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
end
|
|
|
|
|
2020-09-05 00:26:24 -04:00
|
|
|
def test_mutex_interleaved_locking
|
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
|
|
|
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 09:15:43 -04:00
|
|
|
def test_mutex_thread
|
|
|
|
mutex = Mutex.new
|
|
|
|
mutex.lock
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
|
|
|
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 07:29:24 -04:00
|
|
|
def test_mutex_fiber_raise
|
|
|
|
mutex = Mutex.new
|
|
|
|
ran = false
|
|
|
|
|
|
|
|
main = Thread.new do
|
|
|
|
mutex.lock
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
|
|
|
f = Fiber.schedule do
|
|
|
|
assert_raise_with_message(RuntimeError, "bye") do
|
|
|
|
mutex.lock
|
|
|
|
end
|
2020-09-30 20:44:23 -04:00
|
|
|
|
2020-09-20 07:29:24 -04: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 04:47:25 -04:00
|
|
|
def test_condition_variable
|
|
|
|
mutex = Mutex.new
|
|
|
|
condition = ConditionVariable.new
|
|
|
|
|
|
|
|
signalled = 0
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
|
|
|
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
|
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
|
|
|
|
2020-10-01 00:48:15 -04:00
|
|
|
assert_operator signalled, :>, 1
|
2020-09-11 04:47:25 -04:00
|
|
|
end
|
|
|
|
|
2020-09-13 19:10:02 -04:00
|
|
|
def test_queue
|
|
|
|
queue = Queue.new
|
|
|
|
processed = 0
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
|
|
|
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 00:48:15 -04:00
|
|
|
assert_equal 3, processed
|
2020-09-13 19:10:02 -04:00
|
|
|
end
|
|
|
|
|
2020-09-17 08:45:44 -04:00
|
|
|
def test_queue_pop_waits
|
|
|
|
queue = Queue.new
|
|
|
|
running = false
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
|
|
|
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 06:10:55 -04:00
|
|
|
def test_mutex_deadlock
|
2020-09-30 20:44:23 -04: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 00:26:24 -04:00
|
|
|
require 'scheduler'
|
2020-05-14 06:10:55 -04:00
|
|
|
mutex = Mutex.new
|
|
|
|
|
|
|
|
thread = Thread.new do
|
|
|
|
scheduler = Scheduler.new
|
|
|
|
Thread.current.scheduler = scheduler
|
|
|
|
|
2020-08-20 08:52:36 -04:00
|
|
|
Fiber.schedule do
|
2020-05-14 06:10:55 -04:00
|
|
|
mutex.synchronize do
|
2020-09-05 00:26:24 -04:00
|
|
|
puts 'in synchronize'
|
2020-05-14 06:10:55 -04:00
|
|
|
Fiber.yield
|
|
|
|
end
|
|
|
|
end
|
2020-05-14 06:57:39 -04:00
|
|
|
|
2020-09-05 00:26:24 -04:00
|
|
|
mutex.lock
|
2020-05-14 06:10:55 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
thread.join
|
2020-09-05 00:26:24 -04:00
|
|
|
RUBY
|
2020-05-14 06:10:55 -04:00
|
|
|
end
|
|
|
|
end
|