summaryrefslogtreecommitdiff
path: root/test/fiber/test_thread.rb
blob: 5e3cc6d0e134f5435f7d79b78a45542f5737dd32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# frozen_string_literal: true
require "test/unit"
require_relative 'scheduler'

class TestFiberThread < Test::Unit::TestCase
  def test_thread_join
    thread = Thread.new do
      scheduler = Scheduler.new
      Fiber.set_scheduler scheduler

      result = nil
      Fiber.schedule do
        result = Thread.new{:done}.value
      end

      scheduler.run
      result
    end

    assert_equal :done, thread.value
  end

  def test_thread_join_timeout
    sleeper = nil

    thread = Thread.new do
      scheduler = Scheduler.new
      Fiber.set_scheduler scheduler

      Fiber.schedule do
        sleeper = Thread.new{sleep}
        sleeper.join(0.1)
      end

      scheduler.run
    end

    thread.join

    assert_predicate sleeper, :alive?
  ensure
    sleeper&.kill&.join
  end

  def test_thread_join_implicit
    sleeping = false
    finished = false

    thread = Thread.new do
      scheduler = Scheduler.new
      Fiber.set_scheduler scheduler

      Fiber.schedule do
        sleeping = true
        sleep(0.1)
        finished = true
      end

      :done
    end

    Thread.pass until sleeping

    thread.join

    assert_equal :done, thread.value
    assert finished, "Scheduler thread's task should be finished!"
  end

  def test_thread_join_blocking
    thread = Thread.new do
      scheduler = Scheduler.new
      Fiber.set_scheduler scheduler

      result = nil
      Fiber.schedule do
        Fiber.new(blocking: true) do
          # This can deadlock if the blocking state is not taken into account:
          Thread.new do
            sleep(0)
            result = :done
          end.join
        end.resume
      end

      scheduler.run
      result
    end

    assert_equal :done, thread.value
  end

  def test_broken_unblock
    thread = Thread.new do
      Thread.current.report_on_exception = false

      scheduler = BrokenUnblockScheduler.new

      Fiber.set_scheduler scheduler

      Fiber.schedule do
        Thread.new{
          Thread.current.report_on_exception = false
        }.join
      end

      scheduler.run
    ensure
      scheduler.close
    end

    assert_raise(RuntimeError) do
      thread.join
    end
  end

  def test_thread_join_hang
    thread = Thread.new do
      scheduler = SleepingUnblockScheduler.new

      Fiber.set_scheduler scheduler

      Fiber.schedule do
        Thread.new{sleep(0.01)}.value
      end
    end

    thread.join
  end
end