diff options
author | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-12-31 15:02:22 +0000 |
---|---|---|
committer | ko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-12-31 15:02:22 +0000 |
commit | a3e1b1ce7ed7e7ffac23015fc2fde56511b30681 (patch) | |
tree | 7b725552a9a4ded93849ca2faab1b257f7761790 /lib | |
parent | 3e7566d8fb5138bb9cd647e5fdefc54fc9803509 (diff) | |
download | ruby-a3e1b1ce7ed7e7ffac23015fc2fde56511b30681.tar.gz |
* Merge YARV
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11439 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r-- | lib/.document | 3 | ||||
-rw-r--r-- | lib/drb/drb.rb | 10 | ||||
-rw-r--r-- | lib/drb/extservm.rb | 20 | ||||
-rw-r--r-- | lib/generator.rb | 2 | ||||
-rw-r--r-- | lib/getoptlong.rb | 4 | ||||
-rw-r--r-- | lib/mkmf.rb | 39 | ||||
-rw-r--r-- | lib/monitor.rb | 136 | ||||
-rw-r--r-- | lib/mutex_m.rb | 78 | ||||
-rw-r--r-- | lib/rss/0.9.rb | 2 | ||||
-rw-r--r-- | lib/rss/dublincore.rb | 2 | ||||
-rw-r--r-- | lib/rss/parser.rb | 2 | ||||
-rw-r--r-- | lib/singleton.rb | 125 | ||||
-rw-r--r-- | lib/tempfile.rb | 36 | ||||
-rw-r--r-- | lib/thread.rb | 263 | ||||
-rw-r--r-- | lib/timeout.rb | 53 | ||||
-rw-r--r-- | lib/weakref.rb | 57 | ||||
-rw-r--r-- | lib/webrick/utils.rb | 2 |
17 files changed, 300 insertions, 534 deletions
diff --git a/lib/.document b/lib/.document index a3ce8989fc..3979748e3c 100644 --- a/lib/.document +++ b/lib/.document @@ -77,7 +77,8 @@ set.rb shell shell.rb shellwords.rb -singleton.rb +# TODO: YARV cause error. why ...? +# singleton.rb soap sync.rb tempfile.rb diff --git a/lib/drb/drb.rb b/lib/drb/drb.rb index 9690469e0c..d62fead596 100644 --- a/lib/drb/drb.rb +++ b/lib/drb/drb.rb @@ -578,7 +578,8 @@ module DRb end raise(DRbConnError, 'connection closed') if str.nil? raise(DRbConnError, 'premature marshal format(can\'t read)') if str.size < sz - Thread.exclusive do + # TODO: YARV doesn't have Thread.exclusive + #Thread.exclusive do begin save = Thread.current[:drb_untaint] Thread.current[:drb_untaint] = [] @@ -591,7 +592,7 @@ module DRb end Thread.current[:drb_untaint] = save end - end + #end end def send_request(stream, ref, msg_id, arg, b) # :nodoc: @@ -1741,9 +1742,10 @@ module DRb @server = {} def regist_server(server) @server[server.uri] = server - Thread.exclusive do + # TODO: YARV doesn't have Thread.exclusive + #Thread.exclusive do @primary_server = server unless @primary_server - end + #end end module_function :regist_server diff --git a/lib/drb/extservm.rb b/lib/drb/extservm.rb index 2715c5e9fe..1ede7d6d16 100644 --- a/lib/drb/extservm.rb +++ b/lib/drb/extservm.rb @@ -32,9 +32,10 @@ module DRb def service(name) while true server = nil - Thread.exclusive do + # TODO: YARV doesn't have Thread.exclusive + #Thread.exclusive do server = @servers[name] if @servers[name] - end + #end return server if server && server.alive? invoke_service(name) end @@ -42,11 +43,12 @@ module DRb def regist(name, ro) ary = nil - Thread.exclusive do + # TODO: YARV doesn't have Thread.exclusive + #Thread.exclusive do @servers[name] = ro ary = @waiting @waiting = [] - end + #end ary.each do |th| begin th.run @@ -57,9 +59,10 @@ module DRb end def unregist(name) - Thread.exclusive do + # TODO: YARV doesn't have Thread.exclusive + #Thread.exclusive do @servers.delete(name) - end + #end end private @@ -81,10 +84,11 @@ module DRb def invoke_service_command(name, command) raise "invalid command. name: #{name}" unless command - Thread.exclusive do + # TODO: YARV doesn't have Thread.exclusive + #Thread.exclusive do return if @servers.include?(name) @servers[name] = false - end + #end uri = @uri || DRb.uri Process.detach(Process.spawn("#{command} #{uri} #{name}")) true diff --git a/lib/generator.rb b/lib/generator.rb index c5282785b3..9924ce3b0c 100644 --- a/lib/generator.rb +++ b/lib/generator.rb @@ -246,6 +246,8 @@ end __END__ +__END__ + require 'test/unit' class TC_Generator < Test::Unit::TestCase diff --git a/lib/getoptlong.rb b/lib/getoptlong.rb index 880883a981..92c37610df 100644 --- a/lib/getoptlong.rb +++ b/lib/getoptlong.rb @@ -76,7 +76,7 @@ # end # # dir = ARGV.shift -# +# # Dir.chdir(dir) # for i in (1..repetitions) # print "Hello" @@ -290,6 +290,7 @@ class GetoptLong @argument_flags.clear arguments.each do |*arg| + arg = arg.first # TODO: YARV Hack # # Find an argument flag and it set to `argument_flag'. # @@ -302,6 +303,7 @@ class GetoptLong argument_flag = i end end + raise ArgumentError, "no argument-flag" if argument_flag == nil canonical_name = nil diff --git a/lib/mkmf.rb b/lib/mkmf.rb index acd51419cf..4e00332096 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -268,14 +268,14 @@ end def link_command(ldflags, opt="", libpath=$LIBPATH) RbConfig::expand(TRY_LINK.dup, CONFIG.merge('hdrdir' => $hdrdir.quote, - 'src' => CONFTEST_C, - 'INCFLAGS' => $INCFLAGS, - 'CPPFLAGS' => $CPPFLAGS, - 'CFLAGS' => "#$CFLAGS", - 'ARCH_FLAG' => "#$ARCH_FLAG", - 'LDFLAGS' => "#$LDFLAGS #{ldflags}", - 'LIBPATH' => libpathflag(libpath), - 'LOCAL_LIBS' => "#$LOCAL_LIBS #$libs", + 'src' => CONFTEST_C, + 'INCFLAGS' => $INCFLAGS, + 'CPPFLAGS' => $CPPFLAGS, + 'CFLAGS' => "#$CFLAGS", + 'ARCH_FLAG' => "#$ARCH_FLAG", + 'LDFLAGS' => "#$LDFLAGS #{ldflags}", + 'LIBPATH' => libpathflag(libpath), + 'LOCAL_LIBS' => "#$LOCAL_LIBS #$libs", 'LIBS' => "#$LIBRUBYARG_STATIC #{opt} #$LIBS")) end @@ -536,7 +536,7 @@ def message(*s) end def checking_for(m, fmt = nil) - f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim + f = caller[0][/in `(.*)'$/, 1] and f << ": " #` for vim #' m = "checking #{/\Acheck/ =~ f ? '' : 'for '}#{m}... " message "%s", m a = r = nil @@ -924,16 +924,16 @@ end def create_header(header = "extconf.h") message "creating %s\n", header - sym = header.tr("a-z./\055", "A-Z___") + sym = header.tr("a-z./\055", "A-Z___") hdr = ["#ifndef #{sym}\n#define #{sym}\n"] - for line in $defs - case line - when /^-D([^=]+)(?:=(.*))?/ + for line in $defs + case line + when /^-D([^=]+)(?:=(.*))?/ hdr << "#define #$1 #{$2 ? Shellwords.shellwords($2)[0] : 1}\n" - when /^-U(.*)/ + when /^-U(.*)/ hdr << "#undef #$1\n" - end - end + end + end hdr << "#endif\n" hdr = hdr.join unless (IO.read(header) == hdr rescue false) @@ -1236,8 +1236,9 @@ DLLIB = #{dllib} EXTSTATIC = #{$static || ""} STATIC_LIB = #{staticlib unless $static.nil?} #{!$extout && defined?($installed_list) ? "INSTALLED_LIST = #{$installed_list}\n" : ""} -" - install_dirs.each {|*d| mfile.print("%-14s= %s\n" % d) if /^[[:upper:]]/ =~ d[0]} +" #" + # TODO: fixme + install_dirs.each {|d| mfile.print("%-14s= %s\n" % d) if /^[[:upper:]]/ =~ d[0]} n = ($extout ? '$(RUBYARCHDIR)/' : '') + '$(TARGET).' mfile.print " TARGET_SO = #{($extout ? '$(RUBYARCHDIR)/' : '')}$(DLLIB) @@ -1378,7 +1379,7 @@ site-install-rb: install-rb end end if m = /\A\.(\w+)\.(\w+)(?:\s*:)/.match(line) - suffixes << m[1] << m[2] + suffixes << m[1] << m[2] implicit = [[m[1], m[2]], [m.post_match]] next elsif RULE_SUBST and /\A(?!\s*\w+\s*=)[$\w][^#]*:/ =~ line diff --git a/lib/monitor.rb b/lib/monitor.rb index f0e79d8fc8..fdc6ade69e 100644 --- a/lib/monitor.rb +++ b/lib/monitor.rb @@ -41,13 +41,14 @@ reads a line from ARGF and push it to buf, then call empty_cond.signal. =end - + +require 'thread' # # Adds monitor functionality to an arbitrary object by mixing the module with # +include+. For example: # -# require 'monitor.rb' +# require 'monitor' # # buf = [] # buf.extend(MonitorMixin) @@ -86,70 +87,63 @@ module MonitorMixin class ConditionVariable class Timeout < Exception; end - # Create a new timer with the argument timeout, and add the - # current thread to the list of waiters. Then the thread is - # stopped. It will be resumed when a corresponding #signal - # occurs. def wait(timeout = nil) @monitor.funcall(:mon_check_owner) timer = create_timer(timeout) - - Thread.critical = true - count = @monitor.funcall(:mon_exit_for_cond) - @waiters.push(Thread.current) + count = nil - begin - Thread.stop - return true - rescue Timeout - return false - ensure - Thread.critical = true - if timer && timer.alive? - Thread.kill(timer) - end - if @waiters.include?(Thread.current) # interrupted? - @waiters.delete(Thread.current) - end + @mutex.synchronize{ + count = @monitor.funcall(:mon_exit_for_cond) + @waiters.push(Thread.current) + + begin + @mutex.sleep + return true + rescue Timeout + return false + end + } + ensure + @mutex.synchronize { + if timer && timer.alive? + Thread.kill(timer) + end + if @waiters.include?(Thread.current) # interrupted? + @waiters.delete(Thread.current) + end @monitor.funcall(:mon_enter_for_cond, count) - Thread.critical = false - end + } end - - # call #wait while the supplied block returns +true+. def wait_while while yield wait end end - # call #wait until the supplied block returns +true+. def wait_until until yield wait end end - # Wake up and run the next waiter def signal @monitor.funcall(:mon_check_owner) - Thread.critical = true - t = @waiters.shift - t.wakeup if t - Thread.critical = false + @mutex.synchronize { + t = @waiters.shift + t.wakeup if t + } Thread.pass end - # Wake up all the waiters. def broadcast @monitor.funcall(:mon_check_owner) - Thread.critical = true - for t in @waiters - t.wakeup - end - @waiters.clear - Thread.critical = false + @mutex.synchronize { + for t in @waiters + t.wakeup + end + @waiters.clear + } Thread.pass end @@ -162,6 +156,7 @@ module MonitorMixin def initialize(monitor) @monitor = monitor @waiters = [] + @mutex = Mutex.new end def create_timer(timeout) @@ -170,7 +165,6 @@ module MonitorMixin return Thread.start { Thread.pass sleep(timeout) - Thread.critical = true waiter.raise(Timeout.new) } else @@ -189,15 +183,15 @@ module MonitorMixin # def mon_try_enter result = false - Thread.critical = true - if @mon_owner.nil? - @mon_owner = Thread.current - end - if @mon_owner == Thread.current - @mon_count += 1 - result = true - end - Thread.critical = false + @mon_mutex.synchronize { + if @mon_owner.nil? + @mon_owner = Thread.current + end + if @mon_owner == Thread.current + @mon_count += 1 + result = true + end + } return result end # For backward compatibility @@ -207,10 +201,10 @@ module MonitorMixin # Enters exclusive section. # def mon_enter - Thread.critical = true - mon_acquire(@mon_entering_queue) - @mon_count += 1 - Thread.critical = false + @mon_mutex.synchronize { + mon_acquire(@mon_entering_queue) + @mon_count += 1 + } end # @@ -218,12 +212,12 @@ module MonitorMixin # def mon_exit mon_check_owner - Thread.critical = true - @mon_count -= 1 - if @mon_count == 0 - mon_release - end - Thread.critical = false + @mon_mutex.synchronize { + @mon_count -= 1 + if @mon_count == 0 + mon_release + end + } Thread.pass end @@ -244,9 +238,6 @@ module MonitorMixin # # FIXME: This isn't documented in Nutshell. - # - # Create a new condition variable for this monitor. - # This facilitates control of the monitor with #signal and #wait. # def new_cond return ConditionVariable.new(self) @@ -259,16 +250,14 @@ module MonitorMixin mon_initialize end - # called by initialize method to set defaults for instance variables. def mon_initialize @mon_owner = nil @mon_count = 0 @mon_entering_queue = [] @mon_waiting_queue = [] + @mon_mutex = Mutex.new end - # Throw a ThreadError exception if the current thread - # does't own the monitor def mon_check_owner if @mon_owner != Thread.current raise ThreadError, "current thread not owner" @@ -278,8 +267,8 @@ module MonitorMixin def mon_acquire(queue) while @mon_owner && @mon_owner != Thread.current queue.push(Thread.current) - Thread.stop - Thread.critical = true + @mutex.unlock_and_stop + @mutex.lock end @mon_owner = Thread.current end @@ -304,17 +293,6 @@ module MonitorMixin end end -# Monitors provide means of mutual exclusion for Thread programming. -# A critical region is created by means of the synchronize method, -# which takes a block. -# The condition variables (created with #new_cond) may be used -# to control the execution of a monitor with #signal and #wait. -# -# the Monitor class wraps MonitorMixin, and provides aliases -# alias try_enter try_mon_enter -# alias enter mon_enter -# alias exit mon_exit -# to access its methods more concisely. class Monitor include MonitorMixin alias try_enter try_mon_enter diff --git a/lib/mutex_m.rb b/lib/mutex_m.rb index 8e0d42bc8d..f776767324 100644 --- a/lib/mutex_m.rb +++ b/lib/mutex_m.rb @@ -1,4 +1,4 @@ -#-- +# # mutex_m.rb - # $Release Version: 3.0$ # $Revision: 1.7 $ @@ -7,26 +7,24 @@ # by Keiju ISHITSUKA(keiju@ishitsuka.com) # modified by matz # patched by akira yamada -#++ -# -# == Usage -# -# Extend an object and use it like a Mutex object: # -# require "mutex_m.rb" -# obj = Object.new -# obj.extend Mutex_m -# # ... +# -- +# Usage: +# require "mutex_m.rb" +# obj = Object.new +# obj.extend Mutex_m +# ... +# extended object can be handled like Mutex +# or +# class Foo +# include Mutex_m +# ... +# end +# obj = Foo.new +# this obj can be handled like Mutex # -# Or, include Mutex_m in a class to have its instances behave like a Mutex -# object: -# -# class Foo -# include Mutex_m -# # ... -# end -# -# obj = Foo.new + +require 'thread' module Mutex_m def Mutex_m.define_aliases(cl) @@ -61,58 +59,30 @@ module Mutex_m end # locking - def mu_synchronize - begin - mu_lock - yield - ensure - mu_unlock - end + def mu_synchronize(&block) + @_mutex.synchronize(&block) end def mu_locked? - @mu_locked + @_mutex.locked? end def mu_try_lock - result = false - Thread.critical = true - unless @mu_locked - @mu_locked = true - result = true - end - Thread.critical = false - result + @_mutex.try_lock end def mu_lock - while (Thread.critical = true; @mu_locked) - @mu_waiting.push Thread.current - Thread.stop - end - @mu_locked = true - Thread.critical = false - self + @_mutex.lock end def mu_unlock - return unless @mu_locked - Thread.critical = true - wait = @mu_waiting - @mu_waiting = [] - @mu_locked = false - Thread.critical = false - for w in wait - w.run - end - self + @_mutex.unlock end private def mu_initialize - @mu_waiting = [] - @mu_locked = false; + @_mutex = Mutex.new end def initialize(*args) diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb index f0060cbad5..900536869d 100644 --- a/lib/rss/0.9.rb +++ b/lib/rss/0.9.rb @@ -17,7 +17,7 @@ module RSS include RSS09 include RootElementMixin - include XMLStyleSheetMixin + # include XMLStyleSheetMixin [ ["channel", nil], diff --git a/lib/rss/dublincore.rb b/lib/rss/dublincore.rb index 5571640bf2..af64d19183 100644 --- a/lib/rss/dublincore.rb +++ b/lib/rss/dublincore.rb @@ -69,7 +69,7 @@ module RSS } ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a - DublinCoreModel::DATE_ELEMENTS.each do |name, | + DublinCoreModel::DATE_ELEMENTS.each do |name, _| ELEMENT_NAME_INFOS << [name, nil] end diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb index e63e06e20d..e272978992 100644 --- a/lib/rss/parser.rb +++ b/lib/rss/parser.rb @@ -247,7 +247,7 @@ module RSS end end EOT - __send__("private", "start_#{name}") + __send!("private", "start_#{name}") end end diff --git a/lib/singleton.rb b/lib/singleton.rb index 0ab8517275..2c08f35e37 100644 --- a/lib/singleton.rb +++ b/lib/singleton.rb @@ -60,7 +60,7 @@ # and _dump(depth) hooks allows the (partially) resurrections of # a previous state of ``the instance''. - +require 'thread' module Singleton # disable build-in copying methods @@ -72,65 +72,19 @@ module Singleton end private + # default marshalling strategy - def _dump(depth=-1) + def _dump(depth = -1) '' end -end - -class << Singleton - # Method body of first instance call. - FirstInstanceCall = proc do - # @__instance__ takes on one of the following values - # * nil - before and after a failed creation - # * false - during creation - # * sub_class instance - after a successful creation - # the form makes up for the lack of returns in progs - Thread.critical = true - if @__instance__.nil? - @__instance__ = false - Thread.critical = false - begin - @__instance__ = new - ensure - if @__instance__ - class <<self - remove_method :instance - def instance; @__instance__ end - end - else - @__instance__ = nil # failed instance creation - end - end - elsif _instantiate?() - Thread.critical = false - else - @__instance__ = false - Thread.critical = false - begin - @__instance__ = new - ensure - if @__instance__ - class <<self - remove_method :instance - def instance; @__instance__ end - end - else - @__instance__ = nil - end - end - end - @__instance__ - end - module SingletonClassMethods # properly clone the Singleton pattern - did you know # that duping doesn't copy class methods? def clone Singleton.__init__(super) end - + private # ensure that the Singleton pattern is properly inherited @@ -142,46 +96,47 @@ class << Singleton def _load(str) instance end - - # waiting-loop hook - def _instantiate?() - while false.equal?(@__instance__) - Thread.critical = false - sleep(0.08) # timeout - Thread.critical = true + end + + class << Singleton + def __init__(klass) + klass.instance_eval { + @__instance__ = nil + @__mutex__ = Mutex.new + } + def klass.instance + return @__instance__ if @__instance__ + @__mutex__.synchronize { + return @__instance__ if @__instance__ + @__instance__ = new() + } + @__instance__ end - @__instance__ + klass end - end - - def __init__(klass) - klass.instance_eval { @__instance__ = nil } - class << klass - define_method(:instance,FirstInstanceCall) + + private + + # extending an object with Singleton is a bad idea + undef_method :extend_object + + def append_features(mod) + # help out people counting on transitive mixins + unless mod.instance_of?(Class) + raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}" + end + super end - klass - end - - private - # extending an object with Singleton is a bad idea - undef_method :extend_object - - def append_features(mod) - # help out people counting on transitive mixins - unless mod.instance_of?(Class) - raise TypeError, "Inclusion of the OO-Singleton module in module #{mod}" + + def included(klass) + super + klass.private_class_method :new, :allocate + klass.extend SingletonClassMethods + Singleton.__init__(klass) end - super end - def included(klass) - super - klass.private_class_method :new, :allocate - klass.extend SingletonClassMethods - Singleton.__init__(klass) - end end - if __FILE__ == $0 @@ -223,9 +178,9 @@ class << Ups def _instantiate? @enter.push Thread.current[:i] while false.equal?(@__instance__) - Thread.critical = false + @__mutex__.unlock sleep 0.08 - Thread.critical = true + @__mutex__.lock end @leave.push Thread.current[:i] @__instance__ diff --git a/lib/tempfile.rb b/lib/tempfile.rb index a033a5b29e..6a2d560b54 100644 --- a/lib/tempfile.rb +++ b/lib/tempfile.rb @@ -6,12 +6,14 @@ require 'delegate' require 'tmpdir' +require 'thread' # A class for managing temporary files. This library is written to be # thread safe. class Tempfile < DelegateClass(File) MAX_TRY = 10 @@cleanlist = [] + @@lock = Mutex.new # Creates a temporary file of mode 0600 in the temporary directory # whose name is basename.pid.n and opens with mode "w+". A Tempfile @@ -26,27 +28,23 @@ class Tempfile < DelegateClass(File) tmpdir = '/tmp' end - lock = nil + lock = tmpname = nil n = failure = 0 - - begin - Thread.critical = true - + @@lock.synchronize { begin - tmpname = File.join(tmpdir, make_tmpname(basename, n)) - lock = tmpname + '.lock' - n += 1 - end while @@cleanlist.include?(tmpname) or - File.exist?(lock) or File.exist?(tmpname) - - Dir.mkdir(lock) - rescue - failure += 1 - retry if failure < MAX_TRY - raise "cannot generate tempfile `%s'" % tmpname - ensure - Thread.critical = false - end + begin + tmpname = File.join(tmpdir, make_tmpname(basename, n)) + lock = tmpname + '.lock' + n += 1 + end while @@cleanlist.include?(tmpname) or + File.exist?(lock) or File.exist?(tmpname) + Dir.mkdir(lock) + rescue + failure += 1 + retry if failure < MAX_TRY + raise "cannot generate tempfile `%s'" % tmpname + end + } @data = [tmpname] @clean_proc = Tempfile.callback(@data) diff --git a/lib/thread.rb b/lib/thread.rb index 5d4fedc73c..11c9d5a1cc 100644 --- a/lib/thread.rb +++ b/lib/thread.rb @@ -13,7 +13,7 @@ unless defined? Thread end unless defined? ThreadError - class ThreadError<StandardError + class ThreadError < StandardError end end @@ -21,143 +21,12 @@ if $DEBUG Thread.abort_on_exception = true end -class Thread - # - # Wraps a block in Thread.critical, restoring the original value upon exit - # from the critical section. - # - def Thread.exclusive - _old = Thread.critical - begin - Thread.critical = true - return yield - ensure - Thread.critical = _old - end - end -end - -# -# Mutex implements a simple semaphore that can be used to coordinate access to -# shared data from multiple concurrent threads. -# -# Example: -# -# require 'thread' -# semaphore = Mutex.new -# -# a = Thread.new { -# semaphore.synchronize { -# # access shared resource -# } -# } -# -# b = Thread.new { -# semaphore.synchronize { -# # access shared resource -# } -# } -# class Mutex - # - # Creates a new Mutex - # - def initialize - @waiting = [] - @locked = false; - @waiting.taint # enable tainted comunication - self.taint - end - - # - # Returns +true+ if this lock is currently held by some thread. - # - def locked? - @locked && true - end - - # - # Attempts to obtain the lock and returns immediately. Returns +true+ if the - # lock was granted. - # - def try_lock - result = false - Thread.critical = true - unless @locked - @locked = Thread.current - result = true - end - Thread.critical = false - result - end - - # - # Attempts to grab the lock and waits if it isn't available. - # - def lock - while (Thread.critical = true; @locked) - if @locked == Thread.current - raise ThreadError, "deadlock; recursive locking" - end - @waiting.push Thread.current - Thread.stop - end - @locked = Thread.current - Thread.critical = false - self - end - - # - # Releases the lock. Returns +nil+ if ref wasn't locked. - # - def unlock - return unless @locked - Thread.critical = true - @locked = false - begin - t = @waiting.shift - t.wakeup if t - rescue ThreadError - retry - end - Thread.critical = false - begin - t.run if t - rescue ThreadError - end - self - end - - # - # Obtains a lock, runs the block, and releases the lock when the block - # completes. See the example under Mutex. - # def synchronize - lock - begin - yield - ensure - unlock - end - end - - # - # If the mutex is locked, unlocks the mutex, wakes one waiting thread, and - # yields in a critical section. - # - def exclusive_unlock - return unless @locked - Thread.exclusive do - @locked = false - begin - t = @waiting.shift - t.wakeup if t - rescue ThreadError - retry - end - yield - end - self + self.lock + yield + ensure + self.unlock end end @@ -201,12 +70,9 @@ class ConditionVariable # def wait(mutex) begin - mutex.exclusive_unlock do - @waiters.push(Thread.current) - Thread.stop - end - ensure - mutex.lock + # TODO: mutex should not be used + @waiters.push(Thread.current) + mutex.sleep end end @@ -226,6 +92,7 @@ class ConditionVariable # Wakes up all threads waiting for this lock. # def broadcast + # TODO: imcomplete waiters0 = nil Thread.exclusive do waiters0 = @waiters.dup @@ -277,22 +144,23 @@ class Queue @que.taint # enable tainted comunication @waiting.taint self.taint + @mutex = Mutex.new end # # Pushes +obj+ to the queue. # def push(obj) - Thread.critical = true - @que.push obj - begin - t = @waiting.shift - t.wakeup if t - rescue ThreadError - retry - ensure - Thread.critical = false - end + t = nil + @mutex.synchronize{ + @que.push obj + begin + t = @waiting.shift + t.wakeup if t + rescue ThreadError + retry + end + } begin t.run if t rescue ThreadError @@ -315,14 +183,17 @@ class Queue # thread isn't suspended, and an exception is raised. # def pop(non_block=false) - while (Thread.critical = true; @que.empty?) - raise ThreadError, "queue empty" if non_block - @waiting.push Thread.current - Thread.stop + while true + @mutex.synchronize{ + if @que.empty? + raise ThreadError, "queue empty" if non_block + @waiting.push Thread.current + @mutex.sleep + else + return @que.shift + end + } end - @que.shift - ensure - Thread.critical = false end # @@ -336,7 +207,7 @@ class Queue alias deq pop # - # Returns +true+ is the queue is empty. + # Returns +true+ if the queue is empty. # def empty? @que.empty? @@ -375,7 +246,7 @@ end # # See Queue for an example of how a SizedQueue works. # -class SizedQueue<Queue +class SizedQueue < Queue # # Creates a fixed-length queue with a maximum size of +max+. # @@ -398,14 +269,16 @@ class SizedQueue<Queue # Sets the maximum size of the queue. # def max=(max) - Thread.critical = true - if max <= @max - @max = max - Thread.critical = false - else - diff = max - @max - @max = max - Thread.critical = false + diff = nil + @mutex.synchronize { + if max <= @max + @max = max + else + diff = max - @max + @max = max + end + } + if diff diff.times do begin t = @queue_wait.shift @@ -423,13 +296,27 @@ class SizedQueue<Queue # until space becomes available. # def push(obj) - Thread.critical = true - while @que.length >= @max - @queue_wait.push Thread.current - Thread.stop - Thread.critical = true + t = nil + @mutex.synchronize{ + while true + break if @que.length <= @max + @queue_wait.push Thread.current + @mutex.sleep + end + + @que.push obj + begin + t = @waiting.shift + t.wakeup if t + rescue ThreadError + retry + end + } + + begin + t.run if t + rescue ThreadError end - super end # @@ -447,20 +334,20 @@ class SizedQueue<Queue # def pop(*args) retval = super - Thread.critical = true - if @que.length < @max - begin - t = @queue_wait.shift - t.wakeup if t - rescue ThreadError - retry - ensure - Thread.critical = false - end - begin - t.run if t - rescue ThreadError + t = nil + @mutex.synchronize { + if @que.length < @max + begin + t = @queue_wait.shift + t.wakeup if t + rescue ThreadError + retry + end end + } + begin + t.run if t + rescue ThreadError end retval end diff --git a/lib/timeout.rb b/lib/timeout.rb index dc92964c0b..af201c8ee7 100644 --- a/lib/timeout.rb +++ b/lib/timeout.rb @@ -1,52 +1,41 @@ -#-- # = timeout.rb # # execution timeout # -# = Copyright -# -# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc. -# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan +# = Synopsis # -#++ +# require 'timeout' +# status = Timeout::timeout(5) { +# # Something that should be interrupted if it takes too much time... +# } # # = Description # -# A way of performing a potentially long-running operation in a thread, and -# terminating it's execution if it hasn't finished within fixed amount of -# time. +# A way of performing a potentially long-running operation in a thread, and terminating +# it's execution if it hasn't finished by a fixed amount of time. # -# Previous versions of timeout didn't use a module for namespace. This version +# Previous versions of timeout didn't provide use a module for namespace. This version # provides both Timeout.timeout, and a backwards-compatible #timeout. # -# = Synopsis -# -# require 'timeout' -# status = Timeout::timeout(5) { -# # Something that should be interrupted if it takes too much time... -# } +# = Copyright # +# Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc. +# Copyright:: (C) 2000 Information-technology Promotion Agency, Japan module Timeout - - ## # Raised by Timeout#timeout when the block times out. - - class Error<Interrupt + class Error < Interrupt end - ## # Executes the method's block. If the block execution terminates before +sec+ # seconds has passed, it returns true. If not, it terminates the execution # and raises +exception+ (which defaults to Timeout::Error). # - # Note that this is both a method of module Timeout, so you can 'include - # Timeout' into your classes so they have a #timeout method, as well as a - # module method, so you can call it directly as Timeout.timeout(). - + # Note that this is both a method of module Timeout, so you can 'include Timeout' + # into your classes so they have a #timeout method, as well as a module method, + # so you can call it directly as Timeout.timeout(). def timeout(sec, exception=Error) return yield if sec == nil or sec.zero? - raise ThreadError, "timeout within critical session" if Thread.critical begin x = Thread.current y = Thread.start { @@ -54,33 +43,28 @@ module Timeout x.raise exception, "execution expired" if x.alive? } yield sec - # return true + return true ensure y.kill if y and y.alive? end end module_function :timeout - end -## # Identical to: # # Timeout::timeout(n, e, &block). # # Defined for backwards compatibility with earlier versions of timeout.rb, see # Timeout#timeout. - -def timeout(n, e=Timeout::Error, &block) # :nodoc: +def timeout(n, e = Timeout::Error, &block) Timeout::timeout(n, e, &block) end -## # Another name for Timeout::Error, defined for backwards compatibility with # earlier versions of timeout.rb. - -TimeoutError = Timeout::Error # :nodoc: +TimeoutError = Timeout::Error if __FILE__ == $0 p timeout(5) { @@ -102,4 +86,3 @@ if __FILE__ == $0 } } end - diff --git a/lib/weakref.rb b/lib/weakref.rb index 048f06f459..20e6a1b4d4 100644 --- a/lib/weakref.rb +++ b/lib/weakref.rb @@ -1,13 +1,6 @@ -require "delegate" - -# WeakRef is a class to represent a reference to an object that is not seen by -# the tracing phase of the garbage collector. This allows the referenced -# object to be garbage collected as if nothing is referring to it. Because -# WeakRef delegates method calls to the referenced object, it may be used in -# place of that object, i.e. it is of the same duck type. +# Weak Reference class that does not bother GCing. # # Usage: -# # foo = Object.new # foo = Object.new # p foo.to_s # original's class @@ -15,18 +8,21 @@ require "delegate" # p foo.to_s # should be same class # ObjectSpace.garbage_collect # p foo.to_s # should raise exception (recycled) -class WeakRef<Delegator - # RefError is raised if an object cannot be referenced by a WeakRef. - class RefError<StandardError +require "delegate" +require 'thread' + +class WeakRef < Delegator + + class RefError < StandardError end @@id_map = {} # obj -> [ref,...] @@id_rev_map = {} # ref -> obj + @@mutex = Mutex.new @@final = lambda {|id| - __old_status = Thread.critical - Thread.critical = true - begin + printf "final: %p\n", id + @@mutex.synchronize { rids = @@id_map[id] if rids for rid in rids @@ -40,20 +36,22 @@ class WeakRef<Delegator @@id_map[rid].delete(id) @@id_map.delete(rid) if @@id_map[rid].empty? end - ensure - Thread.critical = __old_status - end + } } - # Create a new WeakRef from +orig+. def initialize(orig) - __setobj__(orig) + @__id = orig.object_id + printf "orig: %p\n", @__id + ObjectSpace.define_finalizer orig, @@final + ObjectSpace.define_finalizer self, @@final + @@mutex.synchronize { + @@id_map[@__id] = [] unless @@id_map[@__id] + } + @@id_map[@__id].push self.object_id + @@id_rev_map[self.object_id] = @__id super end - # Return the object this WeakRef references. Raises RefError if the object - # has been garbage collected. The object returned is the object to which - # method calls are delegated (see Delegator). def __getobj__ unless @@id_rev_map[self.object_id] == @__id Kernel::raise RefError, "Illegal Reference - probably recycled", Kernel::caller(2) @@ -64,24 +62,9 @@ class WeakRef<Delegator Kernel::raise RefError, "Illegal Reference - probably recycled", Kernel::caller(2) end end - def __setobj__(obj) - @__id = obj.object_id - ObjectSpace.define_finalizer obj, @@final - ObjectSpace.define_finalizer self, @@final - __old_status = Thread.critical - begin - Thread.critical = true - @@id_map[@__id] = [] unless @@id_map[@__id] - ensure - Thread.critical = __old_status - end - @@id_map[@__id].push self.object_id - @@id_rev_map[self.object_id] = @__id end - # Returns true if the referenced object still exists, and false if it has - # been garbage collected. def weakref_alive? @@id_rev_map[self.object_id] == @__id end diff --git a/lib/webrick/utils.rb b/lib/webrick/utils.rb index 4a447aaf85..3b250886db 100644 --- a/lib/webrick/utils.rb +++ b/lib/webrick/utils.rb @@ -162,7 +162,7 @@ module WEBrick def timeout(seconds, exception=Timeout::Error) return yield if seconds.nil? or seconds.zero? - raise ThreadError, "timeout within critical session" if Thread.critical + # raise ThreadError, "timeout within critical session" if Thread.critical id = TimeoutHandler.register(seconds, exception) begin yield(seconds) |