summaryrefslogtreecommitdiff
path: root/spec/ruby/library/conditionvariable/wait_spec.rb
blob: f57ab4c7789544f046b89771b0563582a96c3ee0 (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
131
132
require_relative '../../spec_helper'
require 'thread'

describe "ConditionVariable#wait" do
  it "calls #sleep on the given object" do
    o = Object.new
    o.should_receive(:sleep).with(1234)

    cv = ConditionVariable.new

    cv.wait(o, 1234)
  end

  it "returns self" do
    m = Mutex.new
    cv = ConditionVariable.new
    in_synchronize = false

    th = Thread.new do
      m.synchronize do
        in_synchronize = true
        cv.wait(m).should == cv
      end
    end

    # wait for m to acquire the mutex
    Thread.pass until in_synchronize
    # wait until th is sleeping (ie waiting)
    Thread.pass while th.status and th.status != "sleep"

    m.synchronize { cv.signal }
    th.join
  end

  it "reacquires the lock even if the thread is killed" do
    m = Mutex.new
    cv = ConditionVariable.new
    in_synchronize = false
    owned = nil

    th = Thread.new do
      m.synchronize do
        in_synchronize = true
        begin
          cv.wait(m)
        ensure
          owned = m.owned?
          $stderr.puts "\nThe Thread doesn't own the Mutex!" unless owned
        end
      end
    end

    # wait for m to acquire the mutex
    Thread.pass until in_synchronize
    # wait until th is sleeping (ie waiting)
    Thread.pass while th.status and th.status != "sleep"

    th.kill
    th.join

    owned.should == true
  end

  ruby_bug '#14999', ''...'2.5' do
    it "reacquires the lock even if the thread is killed after being signaled" do
      m = Mutex.new
      cv = ConditionVariable.new
      in_synchronize = false
      owned = nil

      th = Thread.new do
        m.synchronize do
          in_synchronize = true
          begin
            cv.wait(m)
          ensure
            owned = m.owned?
            $stderr.puts "\nThe Thread doesn't own the Mutex!" unless owned
          end
        end
      end

      # wait for m to acquire the mutex
      Thread.pass until in_synchronize
      # wait until th is sleeping (ie waiting)
      Thread.pass while th.status and th.status != "sleep"

      m.synchronize {
        cv.signal
        # Wait that the thread is blocked on acquiring the Mutex
        sleep 0.001
        # Kill the thread, yet the thread should first acquire the Mutex before going on
        th.kill
      }

      th.join
      owned.should == true
    end
  end

  it "supports multiple Threads waiting on the same ConditionVariable and Mutex" do
    m = Mutex.new
    cv = ConditionVariable.new
    n_threads = 4
    events = []

    threads = n_threads.times.map {
      Thread.new {
        m.synchronize {
          events << :t_in_synchronize
          cv.wait(m)
        }
      }
    }

    Thread.pass until m.synchronize { events.size } == n_threads
    Thread.pass while threads.any? { |th| th.status and th.status != "sleep" }
    m.synchronize do
      threads.each { |t|
        # Cause interactions with the waiting threads.
        # On TruffleRuby, this causes a safepoint which has interesting
        # interactions with the ConditionVariable.
        bt = t.backtrace
        bt.should be_kind_of(Array)
        bt.size.should >= 2
      }
    end

    cv.broadcast
    threads.each(&:join)
  end
end