aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-12-31 15:02:22 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-12-31 15:02:22 +0000
commita3e1b1ce7ed7e7ffac23015fc2fde56511b30681 (patch)
tree7b725552a9a4ded93849ca2faab1b257f7761790 /lib
parent3e7566d8fb5138bb9cd647e5fdefc54fc9803509 (diff)
downloadruby-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/.document3
-rw-r--r--lib/drb/drb.rb10
-rw-r--r--lib/drb/extservm.rb20
-rw-r--r--lib/generator.rb2
-rw-r--r--lib/getoptlong.rb4
-rw-r--r--lib/mkmf.rb39
-rw-r--r--lib/monitor.rb136
-rw-r--r--lib/mutex_m.rb78
-rw-r--r--lib/rss/0.9.rb2
-rw-r--r--lib/rss/dublincore.rb2
-rw-r--r--lib/rss/parser.rb2
-rw-r--r--lib/singleton.rb125
-rw-r--r--lib/tempfile.rb36
-rw-r--r--lib/thread.rb263
-rw-r--r--lib/timeout.rb53
-rw-r--r--lib/weakref.rb57
-rw-r--r--lib/webrick/utils.rb2
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)