summaryrefslogtreecommitdiff
path: root/lib/thread.rb
blob: c3347b60b47c85d228b5ec19f0379953baf61b85 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#
#		thread.rb - thread support classes
#			$Date: 1996/05/21 09:29:21 $
#			by Yukihiro Matsumoto <matz@caelum.co.jp>
#

unless defined? Thread
  fail "Thread not available for this ruby interpreter"
end

unless defined? ThreadError
  class ThreadError<Exception
  end
end

class Mutex
  def initialize
    @waiting = []
    @locked = FALSE;
  end

  def locked?
    @locked
  end

  def try_lock
    Thread.exclusive do
      if not @locked
	@locked=TRUE
	return TRUE
      end
    end
    FALSE
  end

  def lock
    while not try_lock
      @waiting.push Thread.current
      Thread.stop
    end
  end

  def unlock
    @locked = FALSE
    if w = @waiting.shift
      w.run
    end
  end

  def synchronize
    begin
      lock
      yield
    ensure
      unlock
    end
  end
end

class SharedMutex<Mutex
  def initialize
    @locking = nil
    @num_locks = 0;
    super
  end
  def try_lock
    if @locking == Thread.current
      @num_locks += 1
      return TRUE
    end
    if super
      @num_locks = 1
      @locking = Thread.current
      TRUE
    else
      FALSE
    end
  end
  def unlock
    unless @locking == Thread.current
      raise ThreadError, "cannot release shared mutex"
    end
    @num_locks -= 1
    if @num_locks == 0
      @locking = nil
      super
    end
  end
end

class Queue
  def initialize
    @que = []
    @waiting = []
  end

  def push(obj)
    @que.push obj
    if t = @waiting.shift
      t.run
    end
  end

  def pop non_block=FALSE
    if @que.length == 0
      raise ThreadError, "queue empty" if non_block
      @waiting.push Thread.current
      Thread.stop
    end
    @que.shift
  end

  def empty?
    @que.length == 0
  end

  def length
    @que.length
  end
end

class Condition
  def initialize
    @waiting = []
  end

  def wait(mut)
    Thread.exclusive do
      mut.unlock
      @waiting.push Thread.current
    end
    Thread.sleep
    mut.lock
  end

  def signal
    th = nil
    Thread.exclusive do
      th = @waiting.pop
    end
    th.run
  end

  def broadcast
    w = @waiting
    Thread.exclusive do
      th = []
    end
    for th in w
      th.run
    end
  end
end