mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Make Digest() thread-safe.
* ext/digest/lib/digest.rb (Digest()): This function should now be thread-safe. If you have a problem with regard to on-demand loading under a multi-threaded environment, preload "digest/*" modules on boot or use this method instead of directly referencing Digest::*. [Bug #9494] cf. https://github.com/aws/aws-sdk-ruby/issues/525 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48213 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2172b44898
commit
c02fa39463
5 changed files with 106 additions and 3 deletions
|
@ -1,3 +1,12 @@
|
|||
Fri Oct 31 22:19:30 2014 Akinori MUSHA <knu@iDaemons.org>
|
||||
|
||||
* ext/digest/lib/digest.rb (Digest()): This function should now be
|
||||
thread-safe. If you have a problem with regard to on-demand
|
||||
loading under a multi-threaded environment, preload "digest/*"
|
||||
modules on boot or use this method instead of directly
|
||||
referencing Digest::*. [Bug #9494]
|
||||
cf. https://github.com/aws/aws-sdk-ruby/issues/525
|
||||
|
||||
Fri Oct 31 21:33:17 2014 Akinori MUSHA <knu@iDaemons.org>
|
||||
|
||||
* test/digest/test_digest.rb: Drop #!. This no longer runs
|
||||
|
|
5
NEWS
5
NEWS
|
@ -128,6 +128,11 @@ with all sufficient information, see the ChangeLog file.
|
|||
=== Stdlib updates (outstanding ones only)
|
||||
|
||||
* Digest
|
||||
|
||||
* Digest() should now be thread-safe. If you have a problem with
|
||||
regard to on-demand loading under a multi-threaded environment,
|
||||
preload "digest/*" modules on boot or use this method instead of
|
||||
directly referencing Digest::*.
|
||||
* Digest::HMAC has been removed just as previously noticed.
|
||||
|
||||
* Etc
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
require 'digest.so'
|
||||
|
||||
module Digest
|
||||
# A mutex for Digest().
|
||||
REQUIRE_MUTEX = Mutex.new
|
||||
|
||||
def self.const_missing(name) # :nodoc:
|
||||
case name
|
||||
when :SHA256, :SHA384, :SHA512
|
||||
|
@ -76,15 +79,30 @@ end
|
|||
# call-seq:
|
||||
# Digest(name) -> digest_subclass
|
||||
#
|
||||
# Returns a Digest subclass by +name+.
|
||||
# Returns a Digest subclass by +name+ in a thread-safe manner even
|
||||
# when on-demand loading is involved.
|
||||
#
|
||||
# require 'digest'
|
||||
#
|
||||
# Digest("MD5")
|
||||
# # => Digest::MD5
|
||||
#
|
||||
# Digest("Foo")
|
||||
# Digest(:SHA256)
|
||||
# # => Digest::SHA256
|
||||
#
|
||||
# Digest(:Foo)
|
||||
# # => LoadError: library not found for class Digest::Foo -- digest/foo
|
||||
def Digest(name)
|
||||
Digest.const_get(name)
|
||||
const = name.to_sym
|
||||
Digest::REQUIRE_MUTEX.synchronize {
|
||||
# Ignore autoload's because it is void when we have #const_missing
|
||||
Digest.const_missing(const)
|
||||
}
|
||||
rescue LoadError
|
||||
# Constants do not necessarily rely on digest/*.
|
||||
if Digest.const_defined?(const)
|
||||
Digest.const_get(const)
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
|
10
test/digest/digest/foo.rb
Normal file
10
test/digest/digest/foo.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
module Digest
|
||||
Foo = nil
|
||||
|
||||
sleep 0.2
|
||||
|
||||
remove_const(:Foo)
|
||||
|
||||
class Foo < Class
|
||||
end
|
||||
end
|
|
@ -208,4 +208,65 @@ module TestDigest
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TestDigestParen < Test::Unit::TestCase
|
||||
def test_sha2
|
||||
assert_separately(%w[-rdigest], <<-'end;')
|
||||
assert_nothing_raised {
|
||||
Digest(:SHA256).new
|
||||
Digest(:SHA384).new
|
||||
Digest(:SHA512).new
|
||||
}
|
||||
end;
|
||||
end
|
||||
|
||||
def test_no_lib
|
||||
assert_separately(%w[-rdigest], <<-'end;')
|
||||
class Digest::Nolib < Digest::Class
|
||||
end
|
||||
|
||||
assert_nothing_raised {
|
||||
Digest(:Nolib).new
|
||||
}
|
||||
end;
|
||||
end
|
||||
|
||||
def test_no_lib_no_def
|
||||
assert_separately(%w[-rdigest], <<-'end;')
|
||||
assert_raise(LoadError) {
|
||||
Digest(:Nodef).new
|
||||
}
|
||||
end;
|
||||
end
|
||||
|
||||
def test_race
|
||||
assert_separately(['-rdigest', "-I#{File.dirname(__FILE__)}"], <<-'end;')
|
||||
assert_nothing_raised {
|
||||
t = Thread.start {
|
||||
sleep 0.1
|
||||
Digest(:Foo).new
|
||||
}
|
||||
Digest(:Foo).new
|
||||
t.join
|
||||
}
|
||||
end;
|
||||
end
|
||||
|
||||
def test_race_mixed
|
||||
assert_separately(['-rdigest', "-I#{File.dirname(__FILE__)}"], <<-'end;')
|
||||
assert_nothing_raised {
|
||||
t = Thread.start {
|
||||
sleep 0.1
|
||||
Digest::Foo.new
|
||||
}
|
||||
Digest(:Foo).new
|
||||
begin
|
||||
t.join
|
||||
rescue NoMethodError, NameError
|
||||
# NoMethodError is highly likely; NameError is listed just in case
|
||||
end
|
||||
}
|
||||
end;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Reference in a new issue