ruby-changes:36132
From: knu <ko1@a...>
Date: Fri, 31 Oct 2014 22:22:08 +0900 (JST)
Subject: [ruby-changes:36132] knu:r48213 (trunk): Make Digest() thread-safe.
knu 2014-10-31 22:21:51 +0900 (Fri, 31 Oct 2014) New Revision: 48213 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=48213 Log: 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 Added directories: trunk/test/digest/digest/ Added files: trunk/test/digest/digest/foo.rb Modified files: trunk/ChangeLog trunk/NEWS trunk/ext/digest/lib/digest.rb trunk/test/digest/test_digest.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 48212) +++ ChangeLog (revision 48213) @@ -1,3 +1,12 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Oct 31 22:19:30 2014 Akinori MUSHA <knu@i...> + + * 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@i...> * test/digest/test_digest.rb: Drop #!. This no longer runs Index: ext/digest/lib/digest.rb =================================================================== --- ext/digest/lib/digest.rb (revision 48212) +++ ext/digest/lib/digest.rb (revision 48213) @@ -1,6 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ext/digest/lib/digest.rb#L1 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 https://github.com/ruby/ruby/blob/trunk/ext/digest/lib/digest.rb#L79 # 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 Index: NEWS =================================================================== --- NEWS (revision 48212) +++ NEWS (revision 48213) @@ -128,6 +128,11 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L128 === 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 Index: test/digest/digest/foo.rb =================================================================== --- test/digest/digest/foo.rb (revision 0) +++ test/digest/digest/foo.rb (revision 48213) @@ -0,0 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/test/digest/digest/foo.rb#L1 +module Digest + Foo = nil + + sleep 0.2 + + remove_const(:Foo) + + class Foo < Class + end +end Property changes on: test/digest/digest/foo.rb ___________________________________________________________________ Added: svn:eol-style + LF Index: test/digest/test_digest.rb =================================================================== --- test/digest/test_digest.rb (revision 48212) +++ test/digest/test_digest.rb (revision 48213) @@ -208,4 +208,65 @@ module TestDigest https://github.com/ruby/ruby/blob/trunk/test/digest/test_digest.rb#L208 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 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/