summaryrefslogtreecommitdiff
path: root/lib/monitor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/monitor.rb')
-rw-r--r--lib/monitor.rb370
1 files changed, 137 insertions, 233 deletions
diff --git a/lib/monitor.rb b/lib/monitor.rb
index 81fe8f2b22..75d9c35821 100644
--- a/lib/monitor.rb
+++ b/lib/monitor.rb
@@ -1,184 +1,162 @@
-## monitor.rb
+=begin
-# Author: Shugo Maeda <shugo@po.aianet.ne.jp>
-# Version: $Revision: 0.1 $
+monitor.rb
+Author: Shugo Maeda <shugo@netlab.co.jp>
+Version: 1.2.1
-# USAGE:
-#
-# foo = Foo.new
-# foo.extend(MonitorMixin)
-# cond = foo.new_cond
-#
-# thread1:
-# foo.synchronize {
-# ...
-# cond.wait_until { foo.done? }
-# ...
-# }
-#
-# thread2:
-# foo.synchronize {
-# foo.do_something
-# cond.signal
-# }
+USAGE:
-# ATTENTION:
-#
-# If you include MonitorMixin and override `initialize', you should
-# call `super'.
-# If you include MonitorMixin to built-in classes, you should override
-# `new' to call `mon_initialize'.
+ foo = Foo.new
+ foo.extend(MonitorMixin)
+ cond = foo.new_cond
-## Code:
-
-require "final"
+ thread1:
+ foo.synchronize {
+ ...
+ cond.wait_until { foo.done? }
+ ...
+ }
-module MonitorMixin
-
- RCS_ID = %q$Id: monitor.rb,v 0.1 1998/03/01 08:40:18 shugo Exp shugo $
+ thread2:
+ foo.synchronize {
+ foo.do_something
+ cond.signal
+ }
+
+=end
- module Primitive
-
- include MonitorMixin
-
- MON_OWNER_TABLE = {}
- MON_COUNT_TABLE = {}
- MON_ENTERING_QUEUE_TABLE = {}
- MON_WAITING_QUEUE_TABLE = {}
-
- FINALIZER = Proc.new { |id|
- MON_OWNER_TABLE.delete(id)
- MON_COUNT_TABLE.delete(id)
- MON_ENTERING_QUEUE_TABLE.delete(id)
- MON_WAITING_QUEUE_TABLE.delete(id)
- }
+module MonitorMixin
+ module Accessible
+ protected
+ attr_accessor :mon_owner, :mon_count
+ attr_reader :mon_entering_queue, :mon_waiting_queue
+ end
- def self.extend_object(obj)
- super(obj)
- obj.mon_initialize
- end
-
+ module Initializable
+ protected
def mon_initialize
- MON_OWNER_TABLE[id] = nil
- MON_COUNT_TABLE[id] = 0
- MON_ENTERING_QUEUE_TABLE[id] = []
- MON_WAITING_QUEUE_TABLE[id] = []
- ObjectSpace.define_finalizer(self, FINALIZER)
- end
-
- def mon_owner
- return MON_OWNER_TABLE[id]
+ @mon_owner = nil
+ @mon_count = 0
+ @mon_entering_queue = []
+ @mon_waiting_queue = []
end
+ end
+
+ class ConditionVariable
+ class Timeout < Exception; end
- def mon_count
- return MON_COUNT_TABLE[id]
- end
+ include Accessible
- def mon_entering_queue
- return MON_ENTERING_QUEUE_TABLE[id]
+ def wait(timeout = nil)
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+
+ Thread.critical = true
+ count = @monitor.mon_count
+ @monitor.mon_count = 0
+ @monitor.mon_owner = nil
+ if @monitor.mon_waiting_queue.empty?
+ t = @monitor.mon_entering_queue.shift
+ else
+ t = @monitor.mon_waiting_queue.shift
+ end
+ t.wakeup if t
+ @waiters.push(Thread.current)
+
+ if timeout
+ t = Thread.current
+ timeout_thread = Thread.start {
+ sleep(timeout)
+ t.raise(Timeout.new)
+ }
+ end
+ begin
+ Thread.stop
+ rescue Timeout
+ @waiters.delete(Thread.current)
+ ensure
+ if timeout && timeout_thread.alive?
+ Thread.kill(timeout_thread)
+ end
+ end
+
+ Thread.critical = true
+ while @monitor.mon_owner &&
+ @monitor.mon_owner != Thread.current
+ @monitor.mon_waiting_queue.push(Thread.current)
+ Thread.stop
+ Thread.critical = true
+ end
+ @monitor.mon_owner = Thread.current
+ @monitor.mon_count = count
+ Thread.critical = false
end
- def mon_waiting_queue
- return MON_WAITING_QUEUE_TABLE[id]
+ def wait_while
+ while yield
+ wait
+ end
end
- def set_mon_owner(val)
- return MON_OWNER_TABLE[id] = val
+ def wait_until
+ until yield
+ wait
+ end
end
- def set_mon_count(val)
- return MON_COUNT_TABLE[id] = val
+ def signal
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+ Thread.critical = true
+ t = @waiters.shift
+ t.wakeup if t
+ Thread.critical = false
+ Thread.pass
end
- private :mon_count, :mon_entering_queue, :mon_waiting_queue,
- :set_mon_owner, :set_mon_count
- end
-
- module NonPrimitive
-
- include MonitorMixin
-
- attr_reader :mon_owner, :mon_count,
- :mon_entering_queue, :mon_waiting_queue
-
- def self.extend_object(obj)
- super(obj)
- obj.mon_initialize
- end
-
- def mon_initialize
- @mon_owner = nil
- @mon_count = 0
- @mon_entering_queue = []
- @mon_waiting_queue = []
+ def broadcast
+ if @monitor.mon_owner != Thread.current
+ raise ThreadError, "current thread not owner"
+ end
+ Thread.critical = true
+ for t in @waiters
+ t.wakeup
+ end
+ @waiters.clear
+ Thread.critical = false
+ Thread.pass
end
- def set_mon_owner(val)
- @mon_owner = val
+ def count_waiters
+ return @waiters.length
end
- def set_mon_count(val)
- @mon_count = val
+ private
+ def initialize(monitor)
+ @monitor = monitor
+ @waiters = []
end
-
- private :mon_count, :mon_entering_queue, :mon_waiting_queue,
- :set_mon_owner, :set_mon_count
end
- def self.extendable_module(obj)
- if Fixnum === obj or TrueClass === obj or FalseClass === obj or
- NilClass === obj
- raise TypeError, "MonitorMixin can't extend #{obj.type}"
- else
- begin
- obj.instance_eval("@mon_owner")
- return NonPrimitive
- rescue TypeError
- return Primitive
- end
- end
- end
+ include Accessible
+ include Initializable
+ extend Initializable
def self.extend_object(obj)
- obj.extend(extendable_module(obj))
- end
-
- def self.includable_module(klass)
- if klass.instance_of?(Module)
- return NonPrimitive
- end
- begin
- dummy = klass.new
- return extendable_module(dummy)
- rescue ArgumentError
- if klass.singleton_methods.include?("new")
- return Primitive
- else
- return NonPrimitive
- end
- rescue NameError
- raise TypeError, "#{klass} can't include MonitorMixin"
- end
- end
-
- def self.append_features(klass)
- mod = includable_module(klass)
- klass.module_eval("include mod")
- end
-
- def initialize(*args)
- super
- mon_initialize
+ super(obj)
+ obj.mon_initialize
end
def try_mon_enter
result = false
Thread.critical = true
if mon_owner.nil?
- set_mon_owner(Thread.current)
+ self.mon_owner = Thread.current
end
if mon_owner == Thread.current
- set_mon_count(mon_count + 1)
+ self.mon_count += 1
result = true
end
Thread.critical = false
@@ -192,8 +170,8 @@ module MonitorMixin
Thread.stop
Thread.critical = true
end
- set_mon_owner(Thread.current)
- set_mon_count(mon_count + 1)
+ self.mon_owner = Thread.current
+ self.mon_count += 1
Thread.critical = false
end
@@ -202,9 +180,9 @@ module MonitorMixin
raise ThreadError, "current thread not owner"
end
Thread.critical = true
- set_mon_count(mon_count - 1)
+ self.mon_count -= 1
if mon_count == 0
- set_mon_owner(nil)
+ self.mon_owner = nil
if mon_waiting_queue.empty?
t = mon_entering_queue.shift
else
@@ -225,93 +203,16 @@ module MonitorMixin
end
end
alias synchronize mon_synchronize
-
- class ConditionVariable
- def initialize(monitor)
- @monitor = monitor
- @waiters = []
- end
-
- def wait
- if @monitor.mon_owner != Thread.current
- raise ThreadError, "current thread not owner"
- end
-
- @monitor.instance_eval(<<MON_EXIT)
- Thread.critical = true
- _count = mon_count
- set_mon_count(0)
- set_mon_owner(nil)
- if mon_waiting_queue.empty?
- t = mon_entering_queue.shift
- else
- t = mon_waiting_queue.shift
- end
- t.wakeup if t
- Thread.critical = false
-MON_EXIT
-
- Thread.critical = true
- @waiters.push(Thread.current)
- Thread.stop
-
- @monitor.instance_eval(<<MON_ENTER)
- Thread.critical = true
- while mon_owner != nil && mon_owner != Thread.current
- mon_waiting_queue.push(Thread.current)
- Thread.stop
- Thread.critical = true
- end
- set_mon_owner(Thread.current)
- set_mon_count(_count)
- Thread.critical = false
-MON_ENTER
- end
-
- def wait_while
- while yield
- wait
- end
- end
-
- def wait_until
- until yield
- wait
- end
- end
-
- def signal
- if @monitor.mon_owner != Thread.current
- raise ThreadError, "current thread not owner"
- end
- Thread.critical = true
- t = @waiters.shift
- t.wakeup if t
- Thread.critical = false
- Thread.pass
- end
-
- def broadcast
- if @monitor.mon_owner != Thread.current
- raise ThreadError, "current thread not owner"
- end
- Thread.critical = true
- for t in @waiters
- t.wakeup
- end
- @waiters.clear
- Thread.critical = false
- Thread.pass
- end
-
- def count_waiters
- return @waiters.length
- end
- end
def new_cond
return ConditionVariable.new(self)
end
+
+private
+ def initialize(*args)
+ super
+ mon_initialize
+ end
end
class Monitor
@@ -322,4 +223,7 @@ class Monitor
alias owner mon_owner
end
-## monitor.rb ends here
+# Local variables:
+# mode: Ruby
+# tab-width: 8
+# End: