1998-01-16 07:13:05 -05:00
|
|
|
#
|
|
|
|
# thread.rb - thread support classes
|
|
|
|
# $Date$
|
2000-05-01 05:42:38 -04:00
|
|
|
# by Yukihiro Matsumoto <matz@netlab.co.jp>
|
|
|
|
#
|
|
|
|
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
2000-05-09 00:53:16 -04:00
|
|
|
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
1998-01-16 07:13:05 -05:00
|
|
|
#
|
|
|
|
|
|
|
|
unless defined? Thread
|
|
|
|
fail "Thread not available for this ruby interpreter"
|
|
|
|
end
|
|
|
|
|
|
|
|
unless defined? ThreadError
|
1999-01-19 23:59:39 -05:00
|
|
|
class ThreadError<StandardError
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
if $DEBUG
|
|
|
|
Thread.abort_on_exception = true
|
|
|
|
end
|
|
|
|
|
1999-08-13 01:45:20 -04:00
|
|
|
def Thread.exclusive
|
2000-08-07 01:05:04 -04:00
|
|
|
_old = Thread.critical
|
1999-08-13 01:45:20 -04:00
|
|
|
begin
|
|
|
|
Thread.critical = true
|
2000-08-07 01:05:04 -04:00
|
|
|
return yield
|
1999-08-13 01:45:20 -04:00
|
|
|
ensure
|
2000-08-07 01:05:04 -04:00
|
|
|
Thread.critical = _old
|
1999-08-13 01:45:20 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
class Mutex
|
|
|
|
def initialize
|
|
|
|
@waiting = []
|
1999-01-19 23:59:39 -05:00
|
|
|
@locked = false;
|
|
|
|
@waiting.taint # enable tainted comunication
|
|
|
|
self.taint
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def locked?
|
|
|
|
@locked
|
|
|
|
end
|
|
|
|
|
|
|
|
def try_lock
|
1999-01-19 23:59:39 -05:00
|
|
|
result = false
|
|
|
|
Thread.critical = true
|
1998-01-16 07:13:05 -05:00
|
|
|
unless @locked
|
1999-01-19 23:59:39 -05:00
|
|
|
@locked = true
|
|
|
|
result = true
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
Thread.critical = false
|
1998-01-16 07:13:05 -05:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def lock
|
1999-01-19 23:59:39 -05:00
|
|
|
while (Thread.critical = true; @locked)
|
1998-01-16 07:13:05 -05:00
|
|
|
@waiting.push Thread.current
|
|
|
|
Thread.stop
|
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
@locked = true
|
|
|
|
Thread.critical = false
|
1998-01-16 07:13:05 -05:00
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def unlock
|
|
|
|
return unless @locked
|
1999-08-13 01:45:20 -04:00
|
|
|
Thread.critical = true
|
|
|
|
@locked = false
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t = @waiting.shift
|
|
|
|
t.wakeup if t
|
|
|
|
rescue ThreadError
|
|
|
|
retry
|
|
|
|
end
|
1999-08-13 01:45:20 -04:00
|
|
|
Thread.critical = false
|
2000-05-01 05:42:38 -04:00
|
|
|
t.run if t
|
1998-01-16 07:13:05 -05:00
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
def synchronize
|
1999-01-19 23:59:39 -05:00
|
|
|
lock
|
1998-01-16 07:13:05 -05:00
|
|
|
begin
|
|
|
|
yield
|
|
|
|
ensure
|
|
|
|
unlock
|
|
|
|
end
|
|
|
|
end
|
1999-08-13 01:45:20 -04:00
|
|
|
|
|
|
|
def exclusive_unlock
|
|
|
|
return unless @locked
|
|
|
|
Thread.exclusive do
|
|
|
|
@locked = false
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t = @waiting.shift
|
|
|
|
t.wakeup if t
|
|
|
|
rescue ThreadError
|
|
|
|
retry
|
|
|
|
end
|
1999-08-13 01:45:20 -04:00
|
|
|
yield
|
|
|
|
end
|
|
|
|
self
|
|
|
|
end
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
class ConditionVariable
|
|
|
|
def initialize
|
|
|
|
@waiters = []
|
|
|
|
end
|
|
|
|
|
|
|
|
def wait(mutex)
|
1999-08-13 01:45:20 -04:00
|
|
|
mutex.exclusive_unlock do
|
1999-01-19 23:59:39 -05:00
|
|
|
@waiters.push(Thread.current)
|
1999-08-13 01:45:20 -04:00
|
|
|
Thread.stop
|
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
mutex.lock
|
|
|
|
end
|
|
|
|
|
|
|
|
def signal
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t = @waiters.shift
|
|
|
|
t.run if t
|
|
|
|
rescue ThreadError
|
|
|
|
retry
|
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def broadcast
|
1999-08-13 01:45:20 -04:00
|
|
|
waiters0 = nil
|
|
|
|
Thread.exclusive do
|
|
|
|
waiters0 = @waiters.dup
|
1999-01-19 23:59:39 -05:00
|
|
|
@waiters.clear
|
1999-08-13 01:45:20 -04:00
|
|
|
end
|
|
|
|
for t in waiters0
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t.run
|
|
|
|
rescue ThreadError
|
|
|
|
end
|
1999-08-13 01:45:20 -04:00
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
class Queue
|
|
|
|
def initialize
|
|
|
|
@que = []
|
|
|
|
@waiting = []
|
1999-01-19 23:59:39 -05:00
|
|
|
@que.taint # enable tainted comunication
|
|
|
|
@waiting.taint
|
|
|
|
self.taint
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def push(obj)
|
1999-01-19 23:59:39 -05:00
|
|
|
Thread.critical = true
|
1998-01-16 07:13:05 -05:00
|
|
|
@que.push obj
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t = @waiting.shift
|
|
|
|
t.wakeup if t
|
|
|
|
rescue ThreadError
|
|
|
|
retry
|
2000-05-12 05:07:57 -04:00
|
|
|
ensure
|
|
|
|
Thread.critical = false
|
2000-03-17 03:58:21 -05:00
|
|
|
end
|
2000-05-12 05:07:57 -04:00
|
|
|
t.run if t
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
2000-05-30 00:24:17 -04:00
|
|
|
def enq(obj)
|
|
|
|
push(obj)
|
|
|
|
end
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2000-05-30 00:24:17 -04:00
|
|
|
def pop(non_block=false)
|
1999-01-19 23:59:39 -05:00
|
|
|
Thread.critical = true
|
|
|
|
begin
|
|
|
|
loop do
|
|
|
|
if @que.length == 0
|
|
|
|
if non_block
|
|
|
|
raise ThreadError, "queue empty"
|
|
|
|
end
|
|
|
|
@waiting.push Thread.current
|
|
|
|
Thread.stop
|
|
|
|
else
|
|
|
|
return @que.shift
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
ensure
|
|
|
|
Thread.critical = false
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|
|
|
|
end
|
2000-05-30 00:24:17 -04:00
|
|
|
def shift(non_block=false)
|
|
|
|
pop(non_block=false)
|
|
|
|
end
|
|
|
|
alias deq shift
|
1998-01-16 07:13:05 -05:00
|
|
|
|
|
|
|
def empty?
|
|
|
|
@que.length == 0
|
|
|
|
end
|
|
|
|
|
1999-08-13 01:45:20 -04:00
|
|
|
def clear
|
|
|
|
@que.replace([])
|
|
|
|
end
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
def length
|
|
|
|
@que.length
|
|
|
|
end
|
2000-05-30 00:24:17 -04:00
|
|
|
def size
|
|
|
|
length
|
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
|
|
|
|
def num_waiting
|
|
|
|
@waiting.size
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class SizedQueue<Queue
|
|
|
|
def initialize(max)
|
|
|
|
@max = max
|
|
|
|
@queue_wait = []
|
|
|
|
@queue_wait.taint # enable tainted comunication
|
|
|
|
super()
|
|
|
|
end
|
|
|
|
|
|
|
|
def max
|
|
|
|
@max
|
|
|
|
end
|
|
|
|
|
|
|
|
def max=(max)
|
1999-08-13 01:45:20 -04:00
|
|
|
Thread.critical = true
|
1999-01-19 23:59:39 -05:00
|
|
|
if @max >= max
|
|
|
|
@max = max
|
1999-08-13 01:45:20 -04:00
|
|
|
Thread.critical = false
|
1999-01-19 23:59:39 -05:00
|
|
|
else
|
|
|
|
diff = max - @max
|
|
|
|
@max = max
|
1999-08-13 01:45:20 -04:00
|
|
|
Thread.critical = false
|
1999-01-19 23:59:39 -05:00
|
|
|
diff.times do
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t = @queue_wait.shift
|
|
|
|
t.run if t
|
|
|
|
rescue ThreadError
|
|
|
|
retry
|
|
|
|
end
|
1999-01-19 23:59:39 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
max
|
|
|
|
end
|
|
|
|
|
|
|
|
def push(obj)
|
|
|
|
Thread.critical = true
|
|
|
|
while @que.length >= @max
|
|
|
|
@queue_wait.push Thread.current
|
|
|
|
Thread.stop
|
|
|
|
Thread.critical = true
|
|
|
|
end
|
|
|
|
super
|
|
|
|
end
|
|
|
|
|
|
|
|
def pop(*args)
|
|
|
|
Thread.critical = true
|
|
|
|
if @que.length < @max
|
2000-03-17 03:58:21 -05:00
|
|
|
begin
|
|
|
|
t = @queue_wait.shift
|
2000-05-12 05:07:57 -04:00
|
|
|
t.wakeup if t
|
2000-03-17 03:58:21 -05:00
|
|
|
rescue ThreadError
|
|
|
|
retry
|
2000-05-12 05:07:57 -04:00
|
|
|
ensure
|
|
|
|
Thread.critical = false
|
2000-03-17 03:58:21 -05:00
|
|
|
end
|
2000-05-12 05:07:57 -04:00
|
|
|
t.run if t
|
1999-01-19 23:59:39 -05:00
|
|
|
end
|
|
|
|
super
|
|
|
|
end
|
|
|
|
|
|
|
|
def num_waiting
|
|
|
|
@waiting.size + @queue_wait.size
|
|
|
|
end
|
1998-01-16 07:13:05 -05:00
|
|
|
end
|