1require "monitor"
2require "thread"
3
4require "test/unit"
5
6class TestMonitor < Test::Unit::TestCase
7  def setup
8    @monitor = Monitor.new
9  end
10
11  def test_enter
12    ary = []
13    queue = Queue.new
14    th = Thread.start {
15      queue.pop
16      @monitor.enter
17      for i in 6 .. 10
18        ary.push(i)
19        Thread.pass
20      end
21      @monitor.exit
22    }
23    @monitor.enter
24    queue.enq(nil)
25    for i in 1 .. 5
26      ary.push(i)
27      Thread.pass
28    end
29    @monitor.exit
30    th.join
31    assert_equal((1..10).to_a, ary)
32  end
33
34  def test_synchronize
35    ary = []
36    queue = Queue.new
37    th = Thread.start {
38      queue.pop
39      @monitor.synchronize do
40        for i in 6 .. 10
41          ary.push(i)
42          Thread.pass
43        end
44      end
45    }
46    @monitor.synchronize do
47      queue.enq(nil)
48      for i in 1 .. 5
49        ary.push(i)
50        Thread.pass
51      end
52    end
53    th.join
54    assert_equal((1..10).to_a, ary)
55  end
56
57  def test_killed_thread_in_synchronize
58    ary = []
59    queue = Queue.new
60    t1 = Thread.start {
61      queue.pop
62      @monitor.synchronize {
63        ary << :t1
64      }
65    }
66    t2 = Thread.start {
67      queue.pop
68      @monitor.synchronize {
69        ary << :t2
70      }
71    }
72    @monitor.synchronize do
73      queue.enq(nil)
74      queue.enq(nil)
75      assert_equal([], ary)
76      t1.kill
77      t2.kill
78      ary << :main
79    end
80    assert_equal([:main], ary)
81  end
82
83  def test_try_enter
84    queue1 = Queue.new
85    queue2 = Queue.new
86    th = Thread.start {
87      queue1.deq
88      @monitor.enter
89      queue2.enq(nil)
90      queue1.deq
91      @monitor.exit
92      queue2.enq(nil)
93    }
94    assert_equal(true, @monitor.try_enter)
95    @monitor.exit
96    queue1.enq(nil)
97    queue2.deq
98    assert_equal(false, @monitor.try_enter)
99    queue1.enq(nil)
100    queue2.deq
101    assert_equal(true, @monitor.try_enter)
102  end
103
104  def test_cond
105    cond = @monitor.new_cond
106
107    a = "foo"
108    queue1 = Queue.new
109    Thread.start do
110      queue1.deq
111      @monitor.synchronize do
112        a = "bar"
113        cond.signal
114      end
115    end
116    @monitor.synchronize do
117      queue1.enq(nil)
118      assert_equal("foo", a)
119      result1 = cond.wait
120      assert_equal(true, result1)
121      assert_equal("bar", a)
122    end
123  end
124
125  def test_timedwait
126    cond = @monitor.new_cond
127    b = "foo"
128    queue2 = Queue.new
129    Thread.start do
130      queue2.deq
131      @monitor.synchronize do
132        b = "bar"
133        cond.signal
134      end
135    end
136    @monitor.synchronize do
137      queue2.enq(nil)
138      assert_equal("foo", b)
139      result2 = cond.wait(0.1)
140      assert_equal(true, result2)
141      assert_equal("bar", b)
142    end
143
144    c = "foo"
145    queue3 = Queue.new
146    Thread.start do
147      queue3.deq
148      @monitor.synchronize do
149        c = "bar"
150        cond.signal
151      end
152    end
153    @monitor.synchronize do
154      assert_equal("foo", c)
155      result3 = cond.wait(0.1)
156      assert_equal(true, result3) # wait always returns true in Ruby 1.9
157      assert_equal("foo", c)
158      queue3.enq(nil)
159      result4 = cond.wait
160      assert_equal(true, result4)
161      assert_equal("bar", c)
162    end
163
164#     d = "foo"
165#     cumber_thread = Thread.start {
166#       loop do
167#         @monitor.synchronize do
168#           d = "foo"
169#         end
170#       end
171#     }
172#     queue3 = Queue.new
173#     Thread.start do
174#       queue3.pop
175#       @monitor.synchronize do
176#         d = "bar"
177#         cond.signal
178#       end
179#     end
180#     @monitor.synchronize do
181#       queue3.enq(nil)
182#       assert_equal("foo", d)
183#       result5 = cond.wait
184#       assert_equal(true, result5)
185#       # this thread has priority over cumber_thread
186#       assert_equal("bar", d)
187#     end
188#     cumber_thread.kill
189  end
190end
191