From 76f813785b4c9ae425cc9ed231c34f9e4a09da5d Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 7 Jun 2010 22:09:49 -0400 Subject: [PATCH 001/104] First rev of Atomic for MRI and JRuby. --- lib/atomic.rb | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 lib/atomic.rb diff --git a/lib/atomic.rb b/lib/atomic.rb new file mode 100644 index 000000000..57b460818 --- /dev/null +++ b/lib/atomic.rb @@ -0,0 +1,67 @@ + + + +base_atomic = Class.new do + class ConcurrentUpdateError < ThreadError + end + + def initialize(value=nil) + @ref = InternalReference.new(value) + end + + def value + @ref.get + end + + def value=(new_value) + @ref.set(new_value) + new_value + end + + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + begin + try_update { |v| yield v } + rescue ConcurrentUpdateError + retry + end + end + + def try_update + old_value = @ref.get + new_value = yield old_value + unless @ref.compare_and_set(old_value, new_value) + raise ConcurrentUpdateError, "Update failed" + end + old_value + end +end + + +if MRI + Atomic = Class.new(base_atomic) do + class InternalReference + attr_accessor :value + alias_method :get, :value + alias_method :set, :value= + + def initialize(value) + @value = value + end + + def compare_and_set(old_value, new_value) + Thread.exclusive do + return false unless @value.equal? old_value + @value = new_value + end + true + end + end + end +elsif JRuby + Atomic = Class.new(base_atomic) do + InternalReference = java.util.concurrent.atomic.AtomicReference + end +end \ No newline at end of file From d94363f8ec73b7eaf2dc9658fdf2cb1b50958494 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 8 Jun 2010 00:01:57 -0400 Subject: [PATCH 002/104] Yak-shaving for release, plus impl fixes to work properly on 1.8 or 1.9 (Thread.exclusive is 1.9-only) --- README.txt | 33 +++++++++++++++++++++++++++++++++ Rakefile | 10 ++++++++++ atomic.gemspec | 15 +++++++++++++++ examples/atomic_example.rb | 12 ++++++++++++ lib/atomic.rb | 32 ++++++++++++++++++++++---------- test/test_atomic.rb | 35 +++++++++++++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 README.txt create mode 100644 Rakefile create mode 100644 atomic.gemspec create mode 100644 examples/atomic_example.rb create mode 100644 test/test_atomic.rb diff --git a/README.txt b/README.txt new file mode 100644 index 000000000..45e7c70f8 --- /dev/null +++ b/README.txt @@ -0,0 +1,33 @@ +atomic: An atomic reference implementation for JRuby and green or GIL-threaded +Ruby implementations (MRI 1.8/1.9, Rubinius) + +== Summary == + +This library provides: + +* an Atomic class that guarantees atomic updates to its contained value + +The Atomic class provides accessors for the contained "value" plus two update +methods: + +* update will run the provided block, passing the current value and replacing + it with the block result iff the value has not been changed in the mean time. + It may run the block repeatedly if there are other concurrent updates in + progress. +* try_update will run the provided block, passing the current value and + replacing it with the block result. If the value changes before the update + can happen, it will throw Atomic::ConcurrentUpdateError. + +The atomic repository is at http://github.com/headius/ruby-atomic. + +== Usage == + +require 'atomic' + +my_atomic = Atomic.new(0) +my_atomic.update {|v| v + 1} +begin + my_atomic.try_update {|v| v + 1} +rescue Atomic::ConcurrentUpdateError => cue + # deal with it (retry, propagate, etc) +end \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 000000000..8b2e6f8ba --- /dev/null +++ b/Rakefile @@ -0,0 +1,10 @@ +require 'rake' +require 'rake/testtask' + +task :default => :test + +desc "Run tests" +Rake::TestTask.new :test do |t| + t.libs << "lib" + t.test_files = FileList["test/**/*.rb"] +end diff --git a/atomic.gemspec b/atomic.gemspec new file mode 100644 index 000000000..b2aea9817 --- /dev/null +++ b/atomic.gemspec @@ -0,0 +1,15 @@ +# -*- encoding: utf-8 -*- + +Gem::Specification.new do |s| + s.name = %q{atomic} + s.version = "0.0.1" + s.authors = ["Charles Oliver Nutter", "MenTaLguY"] + s.date = Time.now.strftime('YYYY-MM-DD') + s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" + s.email = ["headius@headius.com", "mental@rydia.net"] + s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] + s.homepage = "http://github.com/headius/ruby-atomic" + s.require_paths = ["lib"] + s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls" + s.test_files = Dir["test/test*.rb"] +end diff --git a/examples/atomic_example.rb b/examples/atomic_example.rb new file mode 100644 index 000000000..cfeee63d1 --- /dev/null +++ b/examples/atomic_example.rb @@ -0,0 +1,12 @@ +require 'atomic' + +my_atomic = Atomic.new(0) +my_atomic.update {|v| v + 1} +puts "new value: #{my_atomic.value}" + +begin + my_atomic.try_update {|v| v + 1} +rescue Atomic::ConcurrentUpdateError => cue + # deal with it (retry, propagate, etc) +end +puts "new value: #{my_atomic.value}" diff --git a/lib/atomic.rb b/lib/atomic.rb index 57b460818..8bd75e266 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -1,6 +1,3 @@ - - - base_atomic = Class.new do class ConcurrentUpdateError < ThreadError end @@ -39,8 +36,12 @@ def try_update end end - -if MRI +if defined? RUBY_ENGINE && RUBY_ENGINE == "jruby" + require 'java' + Atomic = Class.new(base_atomic) do + InternalReference = java.util.concurrent.atomic.AtomicReference + end +else Atomic = Class.new(base_atomic) do class InternalReference attr_accessor :value @@ -52,16 +53,27 @@ def initialize(value) end def compare_and_set(old_value, new_value) - Thread.exclusive do + _exclusive do return false unless @value.equal? old_value @value = new_value end true end + + HAS_EXCLUSIVE = defined? Thread.exclusive + def _exclusive + if HAS_EXCLUSIVE + Thread.exclusive {yield} + else + begin + Thread.critical = true + yield + ensure + Thread.critical = false + end + end + end + private :_exclusive end end -elsif JRuby - Atomic = Class.new(base_atomic) do - InternalReference = java.util.concurrent.atomic.AtomicReference - end end \ No newline at end of file diff --git a/test/test_atomic.rb b/test/test_atomic.rb new file mode 100644 index 000000000..33e029ec2 --- /dev/null +++ b/test/test_atomic.rb @@ -0,0 +1,35 @@ +require 'test/unit' +require 'atomic' + +class TestAtomic < Test::Unit::TestCase + def test_construct + atomic = Atomic.new + assert_equal nil, atomic.value + + atomic = Atomic.new(0) + assert_equal 0, atomic.value + end + + def test_value + atomic = Atomic.new(0) + atomic.value = 1 + + assert_equal 1, atomic.value + end + + def test_update + atomic = Atomic.new(0) + atomic.update {|v| v + 1} + + assert_equal 1, atomic.value + end + + def test_try_update + atomic = Atomic.new(0) + atomic.try_update {|v| v + 1} + + assert_equal 1, atomic.value + end + + # TODO: Test the ConcurrentUpdateError cases +end \ No newline at end of file From 87091a419bf09ee6d20d07ce869fe2b60360926e Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 00:13:38 -0400 Subject: [PATCH 003/104] simplify (yay for late binding) --- lib/atomic.rb | 51 +++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index 8bd75e266..24d268864 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -1,4 +1,4 @@ -base_atomic = Class.new do +class Atomic class ConcurrentUpdateError < ThreadError end @@ -38,42 +38,25 @@ def try_update if defined? RUBY_ENGINE && RUBY_ENGINE == "jruby" require 'java' - Atomic = Class.new(base_atomic) do - InternalReference = java.util.concurrent.atomic.AtomicReference - end + Atomic::InternalReference = java.util.concurrent.atomic.AtomicReference else - Atomic = Class.new(base_atomic) do - class InternalReference - attr_accessor :value - alias_method :get, :value - alias_method :set, :value= + require 'thread' - def initialize(value) - @value = value - end + class Atomic::InternalReference + attr_accessor :value + alias_method :get, :value + alias_method :set, :value= - def compare_and_set(old_value, new_value) - _exclusive do - return false unless @value.equal? old_value - @value = new_value - end - true - end - - HAS_EXCLUSIVE = defined? Thread.exclusive - def _exclusive - if HAS_EXCLUSIVE - Thread.exclusive {yield} - else - begin - Thread.critical = true - yield - ensure - Thread.critical = false - end - end + def initialize(value) + @value = value + end + + def compare_and_set(old_value, new_value) + Thread.exclusive do + return false unless @value.equal? old_value + @value = new_value end - private :_exclusive + true end end -end \ No newline at end of file +end From 0e439ec7795317b53b0df7e6eeee7410ee381704 Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 00:18:32 -0400 Subject: [PATCH 004/104] expand tests a bit --- test/test_atomic.rb | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/test/test_atomic.rb b/test/test_atomic.rb index 33e029ec2..2aa0c17db 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -19,17 +19,33 @@ def test_value def test_update atomic = Atomic.new(0) - atomic.update {|v| v + 1} + res = atomic.update {|v| v + 1} assert_equal 1, atomic.value + assert_equal 0, res end def test_try_update atomic = Atomic.new(0) - atomic.try_update {|v| v + 1} + res = atomic.try_update {|v| v + 1} assert_equal 1, atomic.value + assert_equal 0, res end - # TODO: Test the ConcurrentUpdateError cases -end \ No newline at end of file + def test_try_update_fails + atomic = Atomic.new(0) + assert_raise Atomic::ConcurrentUpdateError do + # assigning within block exploits implementation detail for test + atomic.try_update{|v| atomic.value = 1 ; v + 1} + end + end + + def test_update_retries + tries = 0 + atomic = Atomic.new(0) + # assigning within block exploits implementation detail for test + atomic.update{|v| tries += 1 ; atomic.value = 1 ; v + 1} + assert_equal 2, tries + end +end From ac08f56ffc721a77001c6d973b46424c7627c561 Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 00:53:46 -0400 Subject: [PATCH 005/104] move thread require to top --- lib/atomic.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index 24d268864..5bb23b579 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -1,3 +1,5 @@ +require 'thread' + class Atomic class ConcurrentUpdateError < ThreadError end @@ -40,8 +42,6 @@ def try_update require 'java' Atomic::InternalReference = java.util.concurrent.atomic.AtomicReference else - require 'thread' - class Atomic::InternalReference attr_accessor :value alias_method :get, :value From 5de52edd74f150cc23910e2dcb4950f340d6b32e Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 00:54:21 -0400 Subject: [PATCH 006/104] return the new value from update, rather than the old one --- lib/atomic.rb | 2 +- test/test_atomic.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index 5bb23b579..0199808ac 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -34,7 +34,7 @@ def try_update unless @ref.compare_and_set(old_value, new_value) raise ConcurrentUpdateError, "Update failed" end - old_value + new_value end end diff --git a/test/test_atomic.rb b/test/test_atomic.rb index 2aa0c17db..ae8332aa9 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -22,7 +22,7 @@ def test_update res = atomic.update {|v| v + 1} assert_equal 1, atomic.value - assert_equal 0, res + assert_equal 1, res end def test_try_update @@ -30,7 +30,7 @@ def test_try_update res = atomic.try_update {|v| v + 1} assert_equal 1, atomic.value - assert_equal 0, res + assert_equal 1, res end def test_try_update_fails From 0f1b4b63d70bc4e2d1c9a213af1a73f7f2d9290c Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 01:07:45 -0400 Subject: [PATCH 007/104] add Atomic#swap --- lib/atomic.rb | 12 ++++++++++++ test/test_atomic.rb | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/atomic.rb b/lib/atomic.rb index 0199808ac..d7b244f8b 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -17,6 +17,10 @@ def value=(new_value) new_value end + def swap(new_value) + @ref.get_and_set(new_value) + end + # Pass the current value to the given block, replacing it # with the block's result. May retry if the value changes # during the block's execution. @@ -51,6 +55,14 @@ def initialize(value) @value = value end + def get_and_set(new_value) + Thread.exclusive do + old_value = @value + @value = new_value + old_value + end + end + def compare_and_set(old_value, new_value) Thread.exclusive do return false unless @value.equal? old_value diff --git a/test/test_atomic.rb b/test/test_atomic.rb index ae8332aa9..bc7ffbbfe 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -32,6 +32,14 @@ def test_try_update assert_equal 1, atomic.value assert_equal 1, res end + + def test_swap + atomic = Atomic.new(0) + res = atomic.swap(1) + + assert_equal 1, atomic.value + assert_equal 0, res + end def test_try_update_fails atomic = Atomic.new(0) From 6446bf013bd179e3d7ea0ddbeaabc8bf52bb8a3e Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 8 Jun 2010 00:27:55 -0400 Subject: [PATCH 008/104] Additional minor tweak: require 'thread' regardless of impl. Update to 0.0.2. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index b2aea9817..a263b42b8 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.1" + s.version = "0.0.2" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('YYYY-MM-DD') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" From 186fb3cecfbeae4bb9f7cd3b218770a3e5443ab1 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 8 Jun 2010 08:01:53 -0400 Subject: [PATCH 009/104] New version for JRuby that uses a real extension for its InternalReference to avoid problems with JI re-coercing the object and breaking identity. --- Rakefile | 26 ++++++ atomic.gemspec | 2 +- ext/AtomicReferenceService.java | 12 +++ .../ext/atomic/AtomicReferenceLibrary.java | 81 +++++++++++++++++++ lib/atomic.rb | 3 +- test/test_atomic.rb | 32 ++++---- 6 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 ext/AtomicReferenceService.java create mode 100644 ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java diff --git a/Rakefile b/Rakefile index 8b2e6f8ba..ddad149e5 100644 --- a/Rakefile +++ b/Rakefile @@ -8,3 +8,29 @@ Rake::TestTask.new :test do |t| t.libs << "lib" t.test_files = FileList["test/**/*.rb"] end + +if defined?(JRUBY_VERSION) + require 'ant' + + directory "pkg/classes" + + desc "Clean up build artifacts" + task :clean do + rm_rf "pkg/classes" + rm_rf "lib/refqueue.jar" + end + + desc "Compile the extension" + task :compile => "pkg/classes" do |t| + ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, + :source => "1.5", :target => "1.5", :debug => true, + :classpath => "${java.class.path}:${sun.boot.class.path}" + end + + desc "Build the jar" + task :jar => :compile do + ant.jar :basedir => "pkg/classes", :destfile => "lib/atomic_reference.jar", :includes => "**/*.class" + end + + task :package => :jar +end diff --git a/atomic.gemspec b/atomic.gemspec index a263b42b8..bebca44ca 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.2" + s.version = "0.0.3" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('YYYY-MM-DD') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" diff --git a/ext/AtomicReferenceService.java b/ext/AtomicReferenceService.java new file mode 100644 index 000000000..8423a6cbc --- /dev/null +++ b/ext/AtomicReferenceService.java @@ -0,0 +1,12 @@ +import java.io.IOException; + +import org.jruby.Ruby; +import org.jruby.runtime.load.BasicLibraryService; + +public class AtomicReferenceService implements BasicLibraryService { + public boolean basicLoad(final Ruby runtime) throws IOException { + new org.jruby.ext.atomic.AtomicReferenceLibrary().load(runtime, false); + return true; + } +} + diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java new file mode 100644 index 000000000..57ccc2fc6 --- /dev/null +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -0,0 +1,81 @@ +package org.jruby.ext.atomic; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; +import org.jruby.Ruby; +import org.jruby.RubyClass; +import org.jruby.RubyModule; +import org.jruby.RubyObject; +import org.jruby.anno.JRubyClass; +import org.jruby.anno.JRubyMethod; +import org.jruby.runtime.ObjectAllocator; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.jruby.runtime.load.Library; + +/** + * This library adds an atomic reference type to JRuby for use in the atomic + * library. We do a native version to avoid the implicit value coercion that + * normally happens through JI. + * + * @author headius + */ +public class AtomicReferenceLibrary implements Library { + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule atomicCls = runtime.getClass("Atomic"); + RubyClass jrubyRefClass = runtime.defineClassUnder("InternalReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR, atomicCls); + jrubyRefClass.setAllocator(JRUBYREFERENCE_ALLOCATOR); + jrubyRefClass.defineAnnotatedMethods(JRubyReference.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyReference(runtime, klazz); + } + }; + + @JRubyClass(name="JRubyReference", parent="Object") + public static class JRubyReference extends RubyObject { + private final AtomicReference reference; + + public JRubyReference(Ruby runtime, RubyClass klass) { + super(runtime, klass); + reference = new AtomicReference(runtime.getNil()); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + Ruby runtime = context.getRuntime(); + reference.set(runtime.getNil()); + return runtime.getNil(); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + Ruby runtime = context.getRuntime(); + reference.set(value); + return runtime.getNil(); + } + + @JRubyMethod(name = {"get", "value"}) + public IRubyObject get() { + return reference.get(); + } + + @JRubyMethod(name = {"set", "value="}) + public IRubyObject set(IRubyObject newValue) { + reference.set(newValue); + return newValue; + } + + @JRubyMethod + public IRubyObject compare_and_set(ThreadContext context, IRubyObject oldValue, IRubyObject newValue) { + return context.getRuntime().newBoolean(reference.compareAndSet(oldValue, newValue)); + } + + @JRubyMethod + public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { + return reference.getAndSet(newValue); + } + } +} diff --git a/lib/atomic.rb b/lib/atomic.rb index d7b244f8b..fa73e2a19 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -43,8 +43,7 @@ def try_update end if defined? RUBY_ENGINE && RUBY_ENGINE == "jruby" - require 'java' - Atomic::InternalReference = java.util.concurrent.atomic.AtomicReference + require 'atomic_reference' else class Atomic::InternalReference attr_accessor :value diff --git a/test/test_atomic.rb b/test/test_atomic.rb index bc7ffbbfe..4bc3d5203 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -18,42 +18,46 @@ def test_value end def test_update - atomic = Atomic.new(0) + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) res = atomic.update {|v| v + 1} - assert_equal 1, atomic.value - assert_equal 1, res + assert_equal 1001, atomic.value + assert_equal 1001, res end def test_try_update - atomic = Atomic.new(0) + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) res = atomic.try_update {|v| v + 1} - assert_equal 1, atomic.value - assert_equal 1, res + assert_equal 1001, atomic.value + assert_equal 1001, res end def test_swap - atomic = Atomic.new(0) - res = atomic.swap(1) + atomic = Atomic.new(1000) + res = atomic.swap(1001) - assert_equal 1, atomic.value - assert_equal 0, res + assert_equal 1001, atomic.value + assert_equal 1000, res end def test_try_update_fails - atomic = Atomic.new(0) + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) assert_raise Atomic::ConcurrentUpdateError do # assigning within block exploits implementation detail for test - atomic.try_update{|v| atomic.value = 1 ; v + 1} + atomic.try_update{|v| atomic.value = 1001 ; v + 1} end end def test_update_retries tries = 0 - atomic = Atomic.new(0) + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) # assigning within block exploits implementation detail for test - atomic.update{|v| tries += 1 ; atomic.value = 1 ; v + 1} + atomic.update{|v| tries += 1 ; atomic.value = 1001 ; v + 1} assert_equal 2, tries end end From ef59b6cb62719c868e3fbcde27f332a2ff575a1d Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 20:20:57 -0400 Subject: [PATCH 010/104] full portability --- lib/atomic.rb | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index fa73e2a19..85fdc236c 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -42,20 +42,26 @@ def try_update end end -if defined? RUBY_ENGINE && RUBY_ENGINE == "jruby" +begin require 'atomic_reference' -else +rescue LoadError + # Portable/generic (but not very memory or scheduling-efficient) fallback class Atomic::InternalReference - attr_accessor :value - alias_method :get, :value - alias_method :set, :value= - def initialize(value) + @mutex = Mutex.new @value = value end + def get + @mutex.synchronize { @value } + end + + def set(new_value) + @mutex.synchronize { @value = new_value } + end + def get_and_set(new_value) - Thread.exclusive do + @mutex.synchronize do old_value = @value @value = new_value old_value @@ -63,7 +69,7 @@ def get_and_set(new_value) end def compare_and_set(old_value, new_value) - Thread.exclusive do + @mutex.synchronize do return false unless @value.equal? old_value @value = new_value end From 44df3ce6506cfab80fe00a4e692e7bc0665370f8 Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Tue, 8 Jun 2010 20:21:22 -0400 Subject: [PATCH 011/104] C extension for MRI/1.9 --- ext/atomic_reference.c | 56 ++++++++++++++++++++++++++++++++++++++++++ ext/extconf.rb | 4 +++ 2 files changed, 60 insertions(+) create mode 100644 ext/atomic_reference.c create mode 100644 ext/extconf.rb diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c new file mode 100644 index 000000000..41cf5ddbe --- /dev/null +++ b/ext/atomic_reference.c @@ -0,0 +1,56 @@ +#include + +static void ir_mark(void *value) { + rb_mark((VALUE)value); +} + +static VALUE ir_alloc(VALUE klass) { + return rb_data_object_alloc(klass, (void *)Qnil, ir_mark, NULL); +} + +static VALUE ir_initialize(VALUE self, VALUE value) { + DATA_PTR(self) = (void *)value; + return Qnil; +} + +static VALUE ir_get(VALUE self) { + return (VALUE)DATA_PTR(self); +} + +static VALUE ir_set(VALUE self, VALUE new_value) { + DATA_PTR(self) = (void *)new_value; + return new_value; +} + +static VALUE ir_get_and_set(VALUE self, VALUE new_value) { + VALUE old_value; + old_value = (VALUE)DATA_PTR(self); + DATA_PTR(self) = (void *)new_value; + return old_value; +} + +static VALUE ir_compare_and_set(VALUE self, VALUE expect_value, VALUE new_value) { + VALUE old_value; + old_value = (VALUE)DATA_PTR(self); + if (old_value == expect_value) { + DATA_PTR(self) = (void *)new_value; + return Qtrue; + } else { + return Qfalse; + } +} + +void Init_atomic_reference() { + VALUE cAtomic; + VALUE cInternalReference; + + cAtomic = rb_const_get(rb_cObject, rb_intern("Atomic")); + rb_define_class_under(cAtomic, "InternalReference", rb_cObject); + rb_define_alloc_func(cAtomic, ir_alloc); + + rb_define_method(cInternalReference, "initialize", ir_initialize, 1); + rb_define_method(cInternalReference, "get", ir_get, 0); + rb_define_method(cInternalReference, "set", ir_set, 1); + rb_define_method(cInternalReference, "get_and_set", ir_get_and_set, 1); + rb_define_method(cInternalReference, "compare_and_set", ir_compare_and_set, 2); +} diff --git a/ext/extconf.rb b/ext/extconf.rb new file mode 100644 index 000000000..b08e71a71 --- /dev/null +++ b/ext/extconf.rb @@ -0,0 +1,4 @@ +require 'mkmf' +extension_name = 'atomic_reference' +dir_config(extension_name) +create_makefile(extension_name) From f53b928014867775f0d51732307c38546392c2de Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 8 Jun 2010 22:40:43 -0400 Subject: [PATCH 012/104] Add ext dir for Java stuff. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index bebca44ca..8ef0d8d33 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -7,7 +7,7 @@ Gem::Specification.new do |s| s.date = Time.now.strftime('YYYY-MM-DD') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" s.email = ["headius@headius.com", "mental@rydia.net"] - s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] + s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] s.homepage = "http://github.com/headius/ruby-atomic" s.require_paths = ["lib"] s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls" From ecb44fedf3fb9940ef415359738097538aacbdda Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 8 Jun 2010 22:57:03 -0400 Subject: [PATCH 013/104] Make try_update nonblocking using Mutex#try_lock in the default InternalReference#compare_and_set. --- lib/atomic.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index 85fdc236c..06df5c049 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -69,9 +69,12 @@ def get_and_set(new_value) end def compare_and_set(old_value, new_value) - @mutex.synchronize do + return false unless @mutex.try_lock + begin return false unless @value.equal? old_value @value = new_value + ensure + @mutex.unlock end true end From a9e1a03d141925627fd63319b99a38663a6367d6 Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Wed, 26 Jan 2011 04:40:09 -0800 Subject: [PATCH 014/104] initialize cInternalReference --- ext/atomic_reference.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 41cf5ddbe..e97fac842 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -45,7 +45,8 @@ void Init_atomic_reference() { VALUE cInternalReference; cAtomic = rb_const_get(rb_cObject, rb_intern("Atomic")); - rb_define_class_under(cAtomic, "InternalReference", rb_cObject); + cInternalReference = rb_define_class_under(cAtomic, "InternalReference", + rb_cObject); rb_define_alloc_func(cAtomic, ir_alloc); rb_define_method(cInternalReference, "initialize", ir_initialize, 1); From 617c37823fa68fc24f6e474fd126c4575ad398bf Mon Sep 17 00:00:00 2001 From: MenTaLguY Date: Wed, 26 Jan 2011 04:41:10 -0800 Subject: [PATCH 015/104] nodoc InternalReference --- lib/atomic.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index 06df5c049..a8b126307 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -46,7 +46,7 @@ def try_update require 'atomic_reference' rescue LoadError # Portable/generic (but not very memory or scheduling-efficient) fallback - class Atomic::InternalReference + class Atomic::InternalReference #:nodoc: all def initialize(value) @mutex = Mutex.new @value = value From 93975d8091205fecba74fd3f511114e74911ed71 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 10 Mar 2011 17:57:44 -0600 Subject: [PATCH 016/104] Bump to 0.0.4 for release. Fixes #2. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 8ef0d8d33..d7795a13c 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.3" + s.version = "0.0.4" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('YYYY-MM-DD') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" From 6cb32225314ef7ca85ec9fff9ef2e5885511a930 Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Fri, 1 Jul 2011 09:01:11 +0200 Subject: [PATCH 017/104] Corrections to gemspec --- atomic.gemspec | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index d7795a13c..c647f4583 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} s.version = "0.0.4" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] - s.date = Time.now.strftime('YYYY-MM-DD') + s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" s.email = ["headius@headius.com", "mental@rydia.net"] s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] @@ -12,4 +12,5 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls" s.test_files = Dir["test/test*.rb"] + s.extensions = 'ext/extconf.rb' end From 2198442f487a3f34b6d17df5e0ecdb49832fe07e Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Fri, 1 Jul 2011 09:03:06 +0200 Subject: [PATCH 018/104] Fix rb_mark => rb_gc_mark --- ext/atomic_reference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index e97fac842..3b9f8f61f 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -1,7 +1,7 @@ #include static void ir_mark(void *value) { - rb_mark((VALUE)value); + rb_gc_mark((VALUE)value); } static VALUE ir_alloc(VALUE klass) { From 606cacd011e14a5ea8e7cc0c51121a6bdad3408b Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Fri, 1 Jul 2011 09:03:57 +0200 Subject: [PATCH 019/104] Experiment with system CAS operations to make ir_compare_and_set really atomic --- ext/atomic_reference.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 3b9f8f61f..13a8b5b0e 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -29,15 +29,19 @@ static VALUE ir_get_and_set(VALUE self, VALUE new_value) { return old_value; } -static VALUE ir_compare_and_set(VALUE self, VALUE expect_value, VALUE new_value) { - VALUE old_value; - old_value = (VALUE)DATA_PTR(self); - if (old_value == expect_value) { - DATA_PTR(self) = (void *)new_value; +static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) { +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 + if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { + return Qtrue; + } +#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 + if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; - } else { - return Qfalse; } +#else +# error No CAS operation available for this platform +#endif + return Qfalse; } void Init_atomic_reference() { From 0c7896b4192e23fd174da2c656d5bba79fdef4df Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 5 Jul 2011 13:06:08 -0500 Subject: [PATCH 020/104] Bump version. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index c647f4583..e9608b8fa 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.4" + s.version = "0.0.5" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" From 18bb1ba1d1dc2cd0c10bff2ea7d4eb91451d3d37 Mon Sep 17 00:00:00 2001 From: Jonas Pfenniger Date: Mon, 15 Aug 2011 16:29:27 +0100 Subject: [PATCH 021/104] Added simple benchmarks --- Rakefile | 5 +++++ test/bench_atomic.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/bench_atomic.rb diff --git a/Rakefile b/Rakefile index ddad149e5..c26a3eac3 100644 --- a/Rakefile +++ b/Rakefile @@ -9,6 +9,11 @@ Rake::TestTask.new :test do |t| t.test_files = FileList["test/**/*.rb"] end +desc "Run benchmarks" +task :bench do + exec "ruby -Ilib -Iext test/bench_atomic.rb" +end + if defined?(JRUBY_VERSION) require 'ant' diff --git a/test/bench_atomic.rb b/test/bench_atomic.rb new file mode 100644 index 000000000..9f5ed3aa7 --- /dev/null +++ b/test/bench_atomic.rb @@ -0,0 +1,29 @@ +require 'benchmark' +require 'atomic' +require 'thread' + +N = 100_000 +@lock = Mutex.new +@atom = Atomic.new(0) + +Benchmark.bm(10) do |x| + x.report "simple" do + value = 0 + N.times do + value += 1 + end + end + x.report "mutex" do + value = 0 + N.times do + @lock.synchronize do + value += 1 + end + end + end + x.report "atomic" do + N.times do + @atom.update{|x| x += 1} + end + end +end From 755065a9ec082a97571f13a4fb9348489b049c1d Mon Sep 17 00:00:00 2001 From: Jonas Pfenniger Date: Tue, 6 Sep 2011 15:54:14 +0100 Subject: [PATCH 022/104] Parallel benchmark added it may need a little bit of tweaking but the base is there --- test/bench_atomic.rb | 90 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/test/bench_atomic.rb b/test/bench_atomic.rb index 9f5ed3aa7..9813fd177 100644 --- a/test/bench_atomic.rb +++ b/test/bench_atomic.rb @@ -1,18 +1,25 @@ require 'benchmark' require 'atomic' require 'thread' +Thread.abort_on_exception = true -N = 100_000 -@lock = Mutex.new -@atom = Atomic.new(0) +# number of updates on the value +N = ARGV[1] ? ARGV[1].to_i : 100_000 +# number of threads for parallel test +M = ARGV[0] ? ARGV[0].to_i : 100 + + +puts "*** Sequencial updates ***" Benchmark.bm(10) do |x| - x.report "simple" do - value = 0 + value = 0 + x.report "no lock" do N.times do value += 1 end end + + @lock = Mutex.new x.report "mutex" do value = 0 N.times do @@ -21,9 +28,82 @@ end end end + + @atom = Atomic.new(0) x.report "atomic" do N.times do @atom.update{|x| x += 1} end end end + +def para_setup(num_threads, count, &block) + if num_threads % 2 > 0 + raise ArgumentError, "num_threads must be a multiple of two" + end + raise ArgumentError, "need block" unless block_given? + + # Keep those threads together + tg = ThreadGroup.new + + num_threads.times do |i| + diff = (i % 2 == 0) ? 1 : -1 + + t = Thread.new do + Thread.stop # don't run until we get the go + count.times do + yield diff + end + end + + tg.add(t) + end + + # Make sure all threads are paused + while tg.list.find{|t| t.status != "sleep"} + Thread.pass + end + + # For good measure + GC.start + + tg +end + +def para_run(tg) + Thread.exclusive do + tg.list.each{|t| t.run } + end + tg.list.each{|t| t.join} +end + + +puts "*** Parallel updates ***" +Benchmark.bm(10) do |x| + # This is not secure + value = 0 + tg = para_setup(M, N/M) do |diff| + value += diff + end + x.report("no lock"){ para_run(tg) } + + + value = 0 + @lock = Mutex.new + tg = para_setup(M, N/M) do |diff| + @lock.synchronize do + value += diff + end + end + x.report("mutex"){ para_run(tg) } + raise unless value == 0 + + + @atom = Atomic.new(0) + tg = para_setup(M, N/M) do |diff| + @atom.update{|x| x + diff} + end + x.report("atomic"){ para_run(tg) } + raise unless @atom.value == 0 + +end From 66b2310bc5146e0fa19d66ec156df5894d4b1e1b Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 6 Sep 2011 11:15:31 -0500 Subject: [PATCH 023/104] Perf improvements for CAS operations. * Add compare_and_swap (plus aliases get, set, get_and_set, and compare_and_set) for an exception-free CAS * Customize update to use @ref.compare_and_set rather than try_update, to avoid exception overhead * Make try_update use a pre-allocated backtrace for its ConcurrentUpdateError to reduce exception overhead Also tweaks to benchmark: * Use a global boolean to start all threads; remaining indeterminism is up to OS thread scheduler. This is better than starting each thread in turn, since first thread may run for some time in isolation. * Fix block variable scoping bug --- lib/atomic.rb | 24 ++++++++++++++++++------ test/bench_atomic.rb | 24 ++++++++++++------------ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index a8b126307..f69b5f908 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -11,32 +11,44 @@ def initialize(value=nil) def value @ref.get end + alias get value def value=(new_value) @ref.set(new_value) new_value end + alias set value= def swap(new_value) @ref.get_and_set(new_value) end + alias get_and_set swap + + def compare_and_swap(old_value, new_value) + @ref.compare_and_set(old_value, new_value) + end + alias compare_and_set compare_and_swap # Pass the current value to the given block, replacing it # with the block's result. May retry if the value changes # during the block's execution. def update - begin - try_update { |v| yield v } - rescue ConcurrentUpdateError - retry - end + true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) + new_value end + + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze def try_update old_value = @ref.get new_value = yield old_value unless @ref.compare_and_set(old_value, new_value) - raise ConcurrentUpdateError, "Update failed" + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE + end end new_value end diff --git a/test/bench_atomic.rb b/test/bench_atomic.rb index 9813fd177..1dd808b5d 100644 --- a/test/bench_atomic.rb +++ b/test/bench_atomic.rb @@ -3,6 +3,8 @@ require 'thread' Thread.abort_on_exception = true +$go = false # for synchronizing parallel threads + # number of updates on the value N = ARGV[1] ? ARGV[1].to_i : 100_000 @@ -10,7 +12,7 @@ M = ARGV[0] ? ARGV[0].to_i : 100 -puts "*** Sequencial updates ***" +puts "*** Sequential updates ***" Benchmark.bm(10) do |x| value = 0 x.report "no lock" do @@ -50,7 +52,7 @@ def para_setup(num_threads, count, &block) diff = (i % 2 == 0) ? 1 : -1 t = Thread.new do - Thread.stop # don't run until we get the go + nil until $go count.times do yield diff end @@ -59,8 +61,8 @@ def para_setup(num_threads, count, &block) tg.add(t) end - # Make sure all threads are paused - while tg.list.find{|t| t.status != "sleep"} + # Make sure all threads are started + while tg.list.find{|t| t.status != "run"} Thread.pass end @@ -71,21 +73,19 @@ def para_setup(num_threads, count, &block) end def para_run(tg) - Thread.exclusive do - tg.list.each{|t| t.run } - end + $go = true tg.list.each{|t| t.join} + $go = false end - puts "*** Parallel updates ***" -Benchmark.bm(10) do |x| +Benchmark.bm(10) do |bm| # This is not secure value = 0 tg = para_setup(M, N/M) do |diff| value += diff end - x.report("no lock"){ para_run(tg) } + bm.report("no lock"){ para_run(tg) } value = 0 @@ -95,7 +95,7 @@ def para_run(tg) value += diff end end - x.report("mutex"){ para_run(tg) } + bm.report("mutex"){ para_run(tg) } raise unless value == 0 @@ -103,7 +103,7 @@ def para_run(tg) tg = para_setup(M, N/M) do |diff| @atom.update{|x| x + diff} end - x.report("atomic"){ para_run(tg) } + bm.report("atomic"){ para_run(tg) } raise unless @atom.value == 0 end From c609f3597cbff136e293a2cef3d4908427371ac9 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 6 Sep 2011 11:19:58 -0500 Subject: [PATCH 024/104] Move benchmark to examples/ --- {test => examples}/bench_atomic.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {test => examples}/bench_atomic.rb (100%) diff --git a/test/bench_atomic.rb b/examples/bench_atomic.rb similarity index 100% rename from test/bench_atomic.rb rename to examples/bench_atomic.rb From 4d76b323d2be0df5860d527f5a89020b69369742 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 6 Sep 2011 11:21:41 -0500 Subject: [PATCH 025/104] Update to version 0.0.6. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index e9608b8fa..afe3b05d8 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.5" + s.version = "0.0.6" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" From 8171865f27aa1fecb27641b0580d5342077a26c7 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 6 Sep 2011 11:27:38 -0500 Subject: [PATCH 026/104] Split gem into -java and normal versions, so JRuby doesn't attempt to build native ext it will never use. --- atomic.gemspec | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index afe3b05d8..9ba3d50f7 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -7,10 +7,15 @@ Gem::Specification.new do |s| s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" s.email = ["headius@headius.com", "mental@rydia.net"] - s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] s.homepage = "http://github.com/headius/ruby-atomic" s.require_paths = ["lib"] s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls" s.test_files = Dir["test/test*.rb"] - s.extensions = 'ext/extconf.rb' + if defined?(JRUBY_VERSION) + s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] + s.platform = 'java' + else + s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] + s.extensions = 'ext/extconf.rb' + end end From 3477f0794201062661265211fc236df139d1611e Mon Sep 17 00:00:00 2001 From: Jonas Pfenniger Date: Fri, 9 Sep 2011 17:31:53 +0100 Subject: [PATCH 027/104] More benchmark tools * bench_atomic_1 is used to measure 1 combination * graph_atomic is used to run series, using bench_atomic_1 The idea is to calculate series by varying one parameter which gives much more meaninful results. --- examples/bench_atomic_1.rb | 138 +++++++++++++++++++++++++++++++++ examples/graph_atomic_bench.rb | 68 ++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 examples/bench_atomic_1.rb create mode 100644 examples/graph_atomic_bench.rb diff --git a/examples/bench_atomic_1.rb b/examples/bench_atomic_1.rb new file mode 100644 index 000000000..6778ba844 --- /dev/null +++ b/examples/bench_atomic_1.rb @@ -0,0 +1,138 @@ +#!/usr/bin/env ruby + +$: << File.expand_path('../../lib', __FILE__) + +require 'optparse' +require 'thread' +require 'benchmark' + +require 'atomic' + +Thread.abort_on_exception = true + +$conf = { + :lock => "atomic", + :num_threads => 100, + :count => 100_000, + :count_per_thread => nil, + :slow => nil, +} + +OptionParser.new do |opts| + opts.on("-c", "--count NUM") do |n| + $conf[:count] = n.to_i + end + opts.on("-p", "--count-per-thread") do |n| + $conf[:count_per_thread] = n.to_i + end + opts.on("-t", "--num-threads NUM") do |n| + $conf[:num_threads] = n.to_i + end + opts.on("-s", "--slow NUM") do |n| + $conf[:slow] = n.to_i + end + opts.on("-l", "--lock atomic|mutex") do |x| + $conf[:lock] = x + end + opts.on("-h", "--help"){ puts opts; exit } +end.parse!(ARGV) + +unless $conf[:count_per_thread] + $conf[:count_per_thread] = $conf[:count] / $conf[:num_threads] +end +$conf.delete(:count) + +if $conf[:slow].to_i > 0 + require 'digest/md5' + def slow_down + $conf[:slow].times do |i| + Digest::MD5.hexdigest(i.to_s) + end + end + + ret = [] + 10.times do + m = Benchmark.measure{ slow_down } + ret << m.real + end + + $conf[:slow_time] = [ret.min, ret.max] +else + def slow_down; end +end + +$stderr.puts $conf.inspect + +def para_prepare(&block) + num_threads = $conf[:num_threads] + count = $conf[:count_per_thread] + + if num_threads % 2 > 0 + raise ArgumentError, "num_threads must be a multiple of two" + end + + # Keep those threads together + tg = ThreadGroup.new + + num_threads.times do |i| + diff = (i % 2 == 0) ? 1 : -1 + + t = Thread.new do + nil until $go + count.times do + yield diff + end + end + + tg.add(t) + end + + # Make sure all threads are started + while tg.list.find{|t| t.status != "run"} + Thread.pass + end + + # For good measure + GC.start + + $go = false + + tg +end + + + +$tg = nil +if $conf[:lock] == "atomic" + $atom = Atomic.new(0) + $tg = para_prepare do |diff| + $atom.update do |x| + slow_down + x + diff + end + end +else + $lock = Mutex.new + $value = 0 + $tg = para_prepare do |diff| + $lock.synchronize do + slow_down + $value += diff + end + end +end + + +# Run ! +# +# NOTE: It seems to me that this measurement method +# is sensible to how the system dispatches his resources. +# +# More precise caluclation could be done using +# getrusage's times +ret = Benchmark.measure do + $go = true + $tg.list.each{|t| t.join} + $go = false +end +puts ret.real diff --git a/examples/graph_atomic_bench.rb b/examples/graph_atomic_bench.rb new file mode 100644 index 000000000..c9b0c8f6d --- /dev/null +++ b/examples/graph_atomic_bench.rb @@ -0,0 +1,68 @@ +#!/usr/bin/env ruby +require 'optparse' + +conf = { + :vary => "threads", + :lock => "atomic" +} + +OptionParser.new do |opts| + opts.on("-l", "--lock atomic|mutex") do |l| + conf[:lock] = l + end + opts.on("-v", "--vary threads|speed") do |v| + conf[:vary] = v + end + opts.on("-h", "--help"){ puts opts; exit } +end.parse!(ARGV) + +result = File.open("results_#{conf[:lock]}_#{conf[:vary]}.csv", "w") + + +if conf[:vary] == "threads" + # Vary the number of concurrent threads that update the value. + # + # There is a total count of 1mio updates that is distributed + # between the number of threads. + # + # A pair number of threads is used so that even add and odd substract 1. + # This avoid creating instances for Bignum since the number should + # stay in the Fixnum range. + # + (1..100).each do |i| + i = i * 2 + + ret = [] + 10.times do + ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -t #{i}`.to_f + end + + line = ([i] + ret).join(', ') + + puts line + result.puts line + end +elsif conf[:vary] == "speed" + # Varies the execution time of the update block + # by using long calulation (MD5) + # + # NOTE: Thread.pass and sleep() are not usable by the atomic + # lock. It needs to run the whole block without hitting + # another atomic update otherwise it has to retry + # + # The expected result is that the atomic lock's performance + # will hit a certain threshold where it will be worse than mutexes. + # + (1..30).each do |i| + + ret = [] + 10.times do + ret << `ruby ./bench_atomic_1.rb -l #{conf[:lock]} -s #{i}`.to_f + end + + line = ([i] + ret).join(', ') + + puts line + result.puts line + end +end From 2db4ad757492bfe71a664ddedf7dadd9987002ec Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 12 Sep 2011 08:08:19 -0500 Subject: [PATCH 028/104] Update README with more examples and recommend light blocks for #update calls. --- README.txt => README.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) rename README.txt => README.md (52%) diff --git a/README.txt b/README.md similarity index 52% rename from README.txt rename to README.md index 45e7c70f8..b02ffcf1f 100644 --- a/README.txt +++ b/README.md @@ -1,7 +1,8 @@ atomic: An atomic reference implementation for JRuby and green or GIL-threaded Ruby implementations (MRI 1.8/1.9, Rubinius) -== Summary == +Summary +======= This library provides: @@ -20,8 +21,20 @@ methods: The atomic repository is at http://github.com/headius/ruby-atomic. -== Usage == +Usage +===== +The simplest way to use "atomic" is to call the "update" or "try_update" +methods. + +"try_update" and "update" both call the given block, passing the current +value and using the block's result as the new value. If the value is updated +by another thread before the block completes, "try update" raises a +ConcurrentUpdateError and "update" retries the block. Because "update" may call +the block several times when multiple threads are all updating the same value, +the block's logic should be kept as simple as possible. + +````ruby require 'atomic' my_atomic = Atomic.new(0) @@ -30,4 +43,17 @@ begin my_atomic.try_update {|v| v + 1} rescue Atomic::ConcurrentUpdateError => cue # deal with it (retry, propagate, etc) -end \ No newline at end of file +end +```` + +It's also possible to use the regular get/set operations on the Atomic, if you +want to avoid the exception and respond to contended changes in some other way. + +````ruby +my_atomic = Atomic.new(0) +my_atomic.value # => 0 +my_atomic.value = 1 +my_atomic.swap(2) # => 1 +my_atomic.compare_and_swap(2, 3) => true, updated to 3 +my_atomic.compare_and_swap(2, 3) => false, current is not 2 +```` \ No newline at end of file From aa4b746d5e4a74145402085bdb08dc073bbd461a Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 28 Nov 2011 22:49:29 -0600 Subject: [PATCH 029/104] Use AtomicReferenceFieldUpdater, rather than creating a whole other object. --- .../ext/atomic/AtomicReferenceLibrary.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index 57ccc2fc6..0c3e5b5d5 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -1,7 +1,7 @@ package org.jruby.ext.atomic; import java.io.IOException; -import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; @@ -36,46 +36,48 @@ public IRubyObject allocate(Ruby runtime, RubyClass klazz) { @JRubyClass(name="JRubyReference", parent="Object") public static class JRubyReference extends RubyObject { - private final AtomicReference reference; + private volatile IRubyObject reference; + private final static AtomicReferenceFieldUpdater UPDATER = + AtomicReferenceFieldUpdater.newUpdater(JRubyReference.class, IRubyObject.class, "reference"); public JRubyReference(Ruby runtime, RubyClass klass) { super(runtime, klass); - reference = new AtomicReference(runtime.getNil()); + reference = runtime.getNil(); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { Ruby runtime = context.getRuntime(); - reference.set(runtime.getNil()); + UPDATER.set(this, runtime.getNil()); return runtime.getNil(); } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject value) { Ruby runtime = context.getRuntime(); - reference.set(value); + UPDATER.set(this, value); return runtime.getNil(); } @JRubyMethod(name = {"get", "value"}) public IRubyObject get() { - return reference.get(); + return UPDATER.get(this); } @JRubyMethod(name = {"set", "value="}) public IRubyObject set(IRubyObject newValue) { - reference.set(newValue); + UPDATER.set(this, newValue); return newValue; } @JRubyMethod public IRubyObject compare_and_set(ThreadContext context, IRubyObject oldValue, IRubyObject newValue) { - return context.getRuntime().newBoolean(reference.compareAndSet(oldValue, newValue)); + return context.getRuntime().newBoolean(UPDATER.compareAndSet(this, oldValue, newValue)); } @JRubyMethod public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { - return reference.getAndSet(newValue); + return UPDATER.getAndSet(this, newValue); } } } From 0f34f2553175794b9c7d371689fb2e3e65c6d5d0 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 28 Nov 2011 22:49:50 -0600 Subject: [PATCH 030/104] Update to 0.0.7. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 9ba3d50f7..e2bf66984 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.6" + s.version = "0.0.7" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" From 2864e0cf06307a803bd63d120451ee4ca781bf3f Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 29 Nov 2011 18:55:58 -0600 Subject: [PATCH 031/104] Support Rubinius. --- lib/atomic.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index f69b5f908..fa2ccd8e3 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -55,8 +55,17 @@ def try_update end begin - require 'atomic_reference' + ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' + case ruby_engine + when 'jruby', 'ruby' + require 'atomic_reference' + when 'rbx' + Atomic::InternalReference = Rubinius::AtomicReference + else + raise LoadError + end rescue LoadError + warn 'unsupported Ruby engine, using less-efficient Atomic impl' # Portable/generic (but not very memory or scheduling-efficient) fallback class Atomic::InternalReference #:nodoc: all def initialize(value) From 1d4d3c818483e623cd621b3af1eb33193ae6f8de Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 29 Nov 2011 18:56:05 -0600 Subject: [PATCH 032/104] Update to 0.0.8 with support for Rubinius. --- atomic.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index e2bf66984..9d548c4b4 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,14 +2,14 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.7" + s.version = "0.0.8" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') - s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls" + s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" s.email = ["headius@headius.com", "mental@rydia.net"] s.homepage = "http://github.com/headius/ruby-atomic" s.require_paths = ["lib"] - s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls" + s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" s.test_files = Dir["test/test*.rb"] if defined?(JRUBY_VERSION) s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] From aa4d5472c4dccb77128471926b4ecc62e480cba4 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Sat, 3 Dec 2011 11:54:03 -0600 Subject: [PATCH 033/104] Modifications to support building on Windows. Fixes #8. --- ext/extconf.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ext/extconf.rb b/ext/extconf.rb index b08e71a71..102809ce1 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -1,4 +1,10 @@ require 'mkmf' extension_name = 'atomic_reference' dir_config(extension_name) + +case CONFIG["arch"] +when /mswin32|mingw/ + $CFLAGS += " -march=i686" +end + create_makefile(extension_name) From 2dc992a10bbb46e1ad81a1ac48765b5cc73ecd5c Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Sat, 3 Dec 2011 12:00:20 -0600 Subject: [PATCH 034/104] Bump version to 0.0.9. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 9d548c4b4..5a729a4fe 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.8" + s.version = "0.0.9" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" From a39a90e5549c3b0f4c14726fd6a690d61d22eed8 Mon Sep 17 00:00:00 2001 From: Eric Lindvall Date: Wed, 1 Feb 2012 19:31:45 -0800 Subject: [PATCH 035/104] Fix Atomic::InternalReference allocation Moves the ir_alloc method to be the allocator for Atomic::InternalReference instead of Atomic. Fixes segfault when referencing a type that is not immediate (Fixes #11). --- ext/atomic_reference.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 13a8b5b0e..8c3c44285 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -1,7 +1,7 @@ #include static void ir_mark(void *value) { - rb_gc_mark((VALUE)value); + rb_gc_mark_maybe((VALUE)value); } static VALUE ir_alloc(VALUE klass) { @@ -51,7 +51,8 @@ void Init_atomic_reference() { cAtomic = rb_const_get(rb_cObject, rb_intern("Atomic")); cInternalReference = rb_define_class_under(cAtomic, "InternalReference", rb_cObject); - rb_define_alloc_func(cAtomic, ir_alloc); + + rb_define_alloc_func(cInternalReference, ir_alloc); rb_define_method(cInternalReference, "initialize", ir_initialize, 1); rb_define_method(cInternalReference, "get", ir_get, 0); From 2e284b14bc4c7bfae7f1d95a7b5c0253959038d3 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 1 Feb 2012 23:05:20 -0600 Subject: [PATCH 036/104] Bump to 1.0.0. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 5a729a4fe..e8ef4e8ad 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "0.0.9" + s.version = "1.0.0" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" From bb0cee9077e33ccee795334ec14140f1dbf5e86c Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 22 Mar 2012 15:51:04 +0530 Subject: [PATCH 037/104] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b02ffcf1f..a054a8bf4 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,6 @@ my_atomic = Atomic.new(0) my_atomic.value # => 0 my_atomic.value = 1 my_atomic.swap(2) # => 1 -my_atomic.compare_and_swap(2, 3) => true, updated to 3 -my_atomic.compare_and_swap(2, 3) => false, current is not 2 +my_atomic.compare_and_swap(2, 3) # => true, updated to 3 +my_atomic.compare_and_swap(2, 3) # => false, current is not 2 ```` \ No newline at end of file From b14168318d7e61654f0e4622b13dc4e25e6d4ca6 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 26 Apr 2012 15:03:01 -0500 Subject: [PATCH 038/104] Add Apache-2.0 license file. --- LICENSE | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..533671897 --- /dev/null +++ b/LICENSE @@ -0,0 +1,144 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as +defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that +is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that +control, are controlled by, or are under common control with that entity. For the purposes +of this definition, "control" means (i) the power, direct or indirect, to cause the +direction or management of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of +such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by +this License. + +"Source" form shall mean the preferred form for making modifications, including but not +limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of +a Source form, including but not limited to compiled object code, generated documentation, +and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available +under the License, as indicated by a copyright notice that is included in or attached to the +work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on +(or derived from) the Work and for which the editorial revisions, annotations, elaborations, +or other modifications represent, as a whole, an original work of authorship. For the +purposes of this License, Derivative Works shall not include works that remain separable +from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works +thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work +and any modifications or additions to that Work or Derivative Works thereof, that is +intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by +an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the +purposes of this definition, "submitted" means any form of electronic, verbal, or written +communication sent to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and issue tracking +systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and +improving the Work, but excluding communication that is conspicuously marked or otherwise +designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a +Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such Derivative +Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each +Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license +applies only to those patent claims licensable by such Contributor that are necessarily +infringed by their Contribution(s) alone or by combination of their Contribution(s) with the +Work to which such Contribution(s) was submitted. If You institute patent litigation against +any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or +a Contribution incorporated within the Work constitutes direct or contributory patent +infringement, then any patent licenses granted to You under this License for that Work shall +terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works +thereof in any medium, with or without modifications, and in Source or Object form, provided +that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; +and + +You must cause any modified files to carry prominent notices stating that You changed the +files; and + +You must retain, in the Source form of any Derivative Works that You distribute, all +copyright, patent, trademark, and attribution notices from the Source form of the Work, +excluding those notices that do not pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative +Works that You distribute must include a readable copy of the attribution notices contained +within such NOTICE file, excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a NOTICE text file +distributed as part of the Derivative Works; within the Source form or documentation, if +provided along with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may add Your own +attribution notices within Derivative Works that You distribute, alongside or as an addendum +to the NOTICE text from the Work, provided that such additional attribution notices cannot +be construed as modifying the License. You may add Your own copyright statement to Your +modifications and may provide additional or different license terms and conditions for use, +reproduction, or distribution of Your modifications, or for any such Derivative Works as a +whole, provided Your use, reproduction, and distribution of the Work otherwise complies with +the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution +intentionally submitted for inclusion in the Work by You to the Licensor shall be under the +terms and conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for reasonable and +customary use in describing the origin of the Work and reproducing the content of the NOTICE +file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, +Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" +BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, +without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for +determining the appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort +(including negligence), contract, or otherwise, unless required by applicable law (such as +deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this License or out of the use +or inability to use the Work (including but not limited to damages for loss of goodwill, +work stoppage, computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative +Works thereof, You may choose to offer, and charge a fee for, acceptance of support, +warranty, indemnity, or other liability obligations and/or rights consistent with this +License. However, in accepting such obligations, You may act only on Your own behalf and on +Your sole responsibility, not on behalf of any other Contributor, and only if You agree to +indemnify, defend, and hold each Contributor harmless for any liability incurred by, or +claims asserted against, such Contributor by reason of your accepting any such warranty or +additional liability. + +END OF TERMS AND CONDITIONS From 643e0cb0e0260a6860b78c935088a4e383314f7f Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 26 Apr 2012 15:34:13 -0500 Subject: [PATCH 039/104] Make warning only in verbose mode. --- lib/atomic.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index fa2ccd8e3..5471ac682 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -65,7 +65,7 @@ def try_update raise LoadError end rescue LoadError - warn 'unsupported Ruby engine, using less-efficient Atomic impl' + warn 'unsupported Ruby engine, using less-efficient Atomic impl' if $VERBOSE # Portable/generic (but not very memory or scheduling-efficient) fallback class Atomic::InternalReference #:nodoc: all def initialize(value) From d998fe81589a41ae4e4e6b1a746dd48ea17e657a Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 29 Mar 2013 07:51:35 +0100 Subject: [PATCH 040/104] Add license headers and fix gemspec to include all files. --- Rakefile | 12 ++++++++++++ atomic.gemspec | 6 +++--- examples/atomic_example.rb | 12 ++++++++++++ examples/bench_atomic.rb | 12 ++++++++++++ examples/bench_atomic_1.rb | 11 +++++++++++ examples/graph_atomic_bench.rb | 13 +++++++++++++ ext/AtomicReferenceService.java | 12 ++++++++++++ ext/atomic_reference.c | 12 ++++++++++++ ext/extconf.rb | 12 ++++++++++++ .../jruby/ext/atomic/AtomicReferenceLibrary.java | 12 ++++++++++++ lib/atomic.rb | 12 ++++++++++++ test/test_atomic.rb | 12 ++++++++++++ 12 files changed, 135 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index c26a3eac3..3b63ad045 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'rake' require 'rake/testtask' diff --git a/atomic.gemspec b/atomic.gemspec index e8ef4e8ad..f73225dce 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.0.0" + s.version = "1.0.1" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" @@ -12,10 +12,10 @@ Gem::Specification.new do |s| s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" s.test_files = Dir["test/test*.rb"] if defined?(JRUBY_VERSION) - s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] + s.files = Dir['lib/atomic_reference.jar'] s.platform = 'java' else - s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}'] s.extensions = 'ext/extconf.rb' end + s.files += `git ls-files`.lines.map(&:chomp) end diff --git a/examples/atomic_example.rb b/examples/atomic_example.rb index cfeee63d1..115cd862c 100644 --- a/examples/atomic_example.rb +++ b/examples/atomic_example.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'atomic' my_atomic = Atomic.new(0) diff --git a/examples/bench_atomic.rb b/examples/bench_atomic.rb index 1dd808b5d..09a7b06b2 100644 --- a/examples/bench_atomic.rb +++ b/examples/bench_atomic.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'benchmark' require 'atomic' require 'thread' diff --git a/examples/bench_atomic_1.rb b/examples/bench_atomic_1.rb index 6778ba844..ee5eb1e18 100644 --- a/examples/bench_atomic_1.rb +++ b/examples/bench_atomic_1.rb @@ -1,5 +1,16 @@ #!/usr/bin/env ruby +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. $: << File.expand_path('../../lib', __FILE__) require 'optparse' diff --git a/examples/graph_atomic_bench.rb b/examples/graph_atomic_bench.rb index c9b0c8f6d..d118073a5 100644 --- a/examples/graph_atomic_bench.rb +++ b/examples/graph_atomic_bench.rb @@ -1,4 +1,17 @@ #!/usr/bin/env ruby + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'optparse' conf = { diff --git a/ext/AtomicReferenceService.java b/ext/AtomicReferenceService.java index 8423a6cbc..8ecd08776 100644 --- a/ext/AtomicReferenceService.java +++ b/ext/AtomicReferenceService.java @@ -1,3 +1,15 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + import java.io.IOException; import org.jruby.Ruby; diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 8c3c44285..f3a824efa 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -1,3 +1,15 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + #include static void ir_mark(void *value) { diff --git a/ext/extconf.rb b/ext/extconf.rb index 102809ce1..192d3e764 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'mkmf' extension_name = 'atomic_reference' dir_config(extension_name) diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index 0c3e5b5d5..be5db94cf 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -1,3 +1,15 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package org.jruby.ext.atomic; import java.io.IOException; diff --git a/lib/atomic.rb b/lib/atomic.rb index 5471ac682..e5017b533 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'thread' class Atomic diff --git a/test/test_atomic.rb b/test/test_atomic.rb index 4bc3d5203..dceb01948 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http:#www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'test/unit' require 'atomic' From 5d176ab375f21eaa4df964aa2f9729bda68d2d36 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 29 Mar 2013 07:52:07 +0100 Subject: [PATCH 041/104] Add jar to gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..8067623bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +lib/atomic_reference.jar From aa0b90cbd9046e10a3798ce1764620d084879397 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 29 Mar 2013 07:54:07 +0100 Subject: [PATCH 042/104] Bump version to 0.0.2. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index f73225dce..acb5805cb 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.0.1" + s.version = "1.0.2" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 07a161d50245745a7a04d379c1b7b368bd1af1f3 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 03:47:31 -0500 Subject: [PATCH 043/104] Make JRuby version of Atomic more efficient. * Don't wrap in an additional Ruby object. * Use native impl methods directly. * Use Unsafe directly to avoid AtomicReference* overhead. --- .gitignore | 1 + .../ext/atomic/AtomicReferenceLibrary.java | 78 ++++++++++---- lib/atomic.rb | 100 +----------------- lib/atomic/default.rb | 39 +++++++ lib/atomic/jruby.rb | 28 +++++ lib/atomic/rbx.rb | 3 + lib/atomic/ruby.rb | 2 + lib/atomic/shared.rb | 53 ++++++++++ 8 files changed, 186 insertions(+), 118 deletions(-) create mode 100644 lib/atomic/default.rb create mode 100644 lib/atomic/jruby.rb create mode 100644 lib/atomic/rbx.rb create mode 100644 lib/atomic/ruby.rb create mode 100644 lib/atomic/shared.rb diff --git a/.gitignore b/.gitignore index 8067623bf..59d9b6643 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ lib/atomic_reference.jar +/nbproject/private/ \ No newline at end of file diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index be5db94cf..316df73ed 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -24,6 +24,8 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; +import org.jruby.util.unsafe.UnsafeFactory; +import org.jruby.util.unsafe.UnsafeGetter; /** * This library adds an atomic reference type to JRuby for use in the atomic @@ -34,10 +36,14 @@ */ public class AtomicReferenceLibrary implements Library { public void load(Ruby runtime, boolean wrap) throws IOException { - RubyModule atomicCls = runtime.getClass("Atomic"); - RubyClass jrubyRefClass = runtime.defineClassUnder("InternalReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR, atomicCls); - jrubyRefClass.setAllocator(JRUBYREFERENCE_ALLOCATOR); - jrubyRefClass.defineAnnotatedMethods(JRubyReference.class); + RubyClass atomicCls = runtime.defineClass("Atomic", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + try { + sun.misc.Unsafe.class.getMethod("getAndSetObject", Object.class); + atomicCls.setAllocator(JRUBYREFERENCE8_ALLOCATOR); + } catch (Exception e) { + // leave it as Java 6/7 version + } + atomicCls.defineAnnotatedMethods(JRubyReference.class); } private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { @@ -45,51 +51,83 @@ public IRubyObject allocate(Ruby runtime, RubyClass klazz) { return new JRubyReference(runtime, klazz); } }; + + private static final ObjectAllocator JRUBYREFERENCE8_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JRubyReference(runtime, klazz); + } + }; @JRubyClass(name="JRubyReference", parent="Object") public static class JRubyReference extends RubyObject { - private volatile IRubyObject reference; - private final static AtomicReferenceFieldUpdater UPDATER = - AtomicReferenceFieldUpdater.newUpdater(JRubyReference.class, IRubyObject.class, "reference"); + volatile IRubyObject reference; + + static final sun.misc.Unsafe UNSAFE; + static final long referenceOffset; + + static { + try { + UNSAFE = UnsafeGetter.getUnsafe(); + Class k = JRubyReference.class; + referenceOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("reference")); + } catch (Exception e) { + throw new RuntimeException(e); + } + } public JRubyReference(Ruby runtime, RubyClass klass) { super(runtime, klass); - reference = runtime.getNil(); } @JRubyMethod public IRubyObject initialize(ThreadContext context) { - Ruby runtime = context.getRuntime(); - UPDATER.set(this, runtime.getNil()); - return runtime.getNil(); + UNSAFE.putObject(this, referenceOffset, context.nil); + return context.nil; } @JRubyMethod public IRubyObject initialize(ThreadContext context, IRubyObject value) { - Ruby runtime = context.getRuntime(); - UPDATER.set(this, value); - return runtime.getNil(); + UNSAFE.putObject(this, referenceOffset, value); + return context.nil; } @JRubyMethod(name = {"get", "value"}) public IRubyObject get() { - return UPDATER.get(this); + return reference; } @JRubyMethod(name = {"set", "value="}) public IRubyObject set(IRubyObject newValue) { - UPDATER.set(this, newValue); + UNSAFE.putObjectVolatile(this, referenceOffset, newValue); return newValue; } - @JRubyMethod + @JRubyMethod(name = {"compare_and_set", "compare_and_swap"}) public IRubyObject compare_and_set(ThreadContext context, IRubyObject oldValue, IRubyObject newValue) { - return context.getRuntime().newBoolean(UPDATER.compareAndSet(this, oldValue, newValue)); + return context.runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)); } - @JRubyMethod + @JRubyMethod(name = {"get_and_set", "swap"}) + public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { + // less-efficient version for Java 6 and 7 + while (true) { + IRubyObject oldValue = get(); + if (UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)) { + return oldValue; + } + } + } + } + + public static class JRubyReference8 extends JRubyReference { + public JRubyReference8(Ruby runtime, RubyClass klass) { + super(runtime, klass); + } + + @Override public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { - return UPDATER.getAndSet(this, newValue); + // efficient version for Java 8 + return (IRubyObject)UNSAFE.getAndSetObject(this, referenceOffset, newValue); } } } diff --git a/lib/atomic.rb b/lib/atomic.rb index e5017b533..d77f74deb 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -10,106 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'thread' - -class Atomic - class ConcurrentUpdateError < ThreadError - end - - def initialize(value=nil) - @ref = InternalReference.new(value) - end - - def value - @ref.get - end - alias get value - - def value=(new_value) - @ref.set(new_value) - new_value - end - alias set value= - - def swap(new_value) - @ref.get_and_set(new_value) - end - alias get_and_set swap - - def compare_and_swap(old_value, new_value) - @ref.compare_and_set(old_value, new_value) - end - alias compare_and_set compare_and_swap - - # Pass the current value to the given block, replacing it - # with the block's result. May retry if the value changes - # during the block's execution. - def update - true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) - new_value - end - - # frozen pre-allocated backtrace to speed ConcurrentUpdateError - CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze - - def try_update - old_value = @ref.get - new_value = yield old_value - unless @ref.compare_and_set(old_value, new_value) - if $VERBOSE - raise ConcurrentUpdateError, "Update failed" - else - raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE - end - end - new_value - end -end begin ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' - case ruby_engine - when 'jruby', 'ruby' - require 'atomic_reference' - when 'rbx' - Atomic::InternalReference = Rubinius::AtomicReference - else - raise LoadError - end + require "atomic/#{ruby_engine}" rescue LoadError - warn 'unsupported Ruby engine, using less-efficient Atomic impl' if $VERBOSE - # Portable/generic (but not very memory or scheduling-efficient) fallback - class Atomic::InternalReference #:nodoc: all - def initialize(value) - @mutex = Mutex.new - @value = value - end - - def get - @mutex.synchronize { @value } - end - - def set(new_value) - @mutex.synchronize { @value = new_value } - end - - def get_and_set(new_value) - @mutex.synchronize do - old_value = @value - @value = new_value - old_value - end - end - - def compare_and_set(old_value, new_value) - return false unless @mutex.try_lock - begin - return false unless @value.equal? old_value - @value = new_value - ensure - @mutex.unlock - end - true - end - end + require 'atomic/default' end diff --git a/lib/atomic/default.rb b/lib/atomic/default.rb new file mode 100644 index 000000000..7e1e335d1 --- /dev/null +++ b/lib/atomic/default.rb @@ -0,0 +1,39 @@ +warn 'unsupported Ruby engine, using less-efficient Atomic impl' if $VERBOSE + +require 'atomic/shared' +require 'thread' + +# Portable/generic (but not very memory or scheduling-efficient) fallback +class Atomic::InternalReference #:nodoc: all + def initialize(value) + @mutex = Mutex.new + @value = value + end + + def get + @mutex.synchronize { @value } + end + + def set(new_value) + @mutex.synchronize { @value = new_value } + end + + def get_and_set(new_value) + @mutex.synchronize do + old_value = @value + @value = new_value + old_value + end + end + + def compare_and_set(old_value, new_value) + return false unless @mutex.try_lock + begin + return false unless @value.equal? old_value + @value = new_value + ensure + @mutex.unlock + end + true + end +end \ No newline at end of file diff --git a/lib/atomic/jruby.rb b/lib/atomic/jruby.rb new file mode 100644 index 000000000..c76954aa0 --- /dev/null +++ b/lib/atomic/jruby.rb @@ -0,0 +1,28 @@ +require 'atomic_reference' + +# define additional methods and exception +class Atomic + class ConcurrentUpdateError < ThreadError + end + + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + true until compare_and_set(old_value = get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = get + new_value = yield old_value + unless compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE + end + end + new_value + end +end \ No newline at end of file diff --git a/lib/atomic/rbx.rb b/lib/atomic/rbx.rb new file mode 100644 index 000000000..4a8552385 --- /dev/null +++ b/lib/atomic/rbx.rb @@ -0,0 +1,3 @@ +require 'atomic/shared' + +Atomic::InternalReference = Rubinius::AtomicReference \ No newline at end of file diff --git a/lib/atomic/ruby.rb b/lib/atomic/ruby.rb new file mode 100644 index 000000000..3df2f34f5 --- /dev/null +++ b/lib/atomic/ruby.rb @@ -0,0 +1,2 @@ +require 'atomic/shared' +require 'atomic_reference' \ No newline at end of file diff --git a/lib/atomic/shared.rb b/lib/atomic/shared.rb new file mode 100644 index 000000000..0e79e446a --- /dev/null +++ b/lib/atomic/shared.rb @@ -0,0 +1,53 @@ +class Atomic + class ConcurrentUpdateError < ThreadError + end + + def initialize(value=nil) + @ref = InternalReference.new(value) + end + + def value + @ref.get + end + alias get value + + def value=(new_value) + @ref.set(new_value) + new_value + end + alias set value= + + def swap(new_value) + @ref.get_and_set(new_value) + end + alias get_and_set swap + + def compare_and_swap(old_value, new_value) + @ref.compare_and_set(old_value, new_value) + end + alias compare_and_set compare_and_swap + + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) + new_value + end + + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze + + def try_update + old_value = @ref.get + new_value = yield old_value + unless @ref.compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE + end + end + new_value + end +end \ No newline at end of file From f8f10cca59e5de3faf88d2839ee28cd0ca265b96 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 04:20:09 -0500 Subject: [PATCH 044/104] Reformat in GNU/MRI style. --- ext/atomic_reference.c | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index f3a824efa..5dd956c24 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -13,62 +13,62 @@ #include static void ir_mark(void *value) { - rb_gc_mark_maybe((VALUE)value); + rb_gc_mark_maybe((VALUE) value); } static VALUE ir_alloc(VALUE klass) { - return rb_data_object_alloc(klass, (void *)Qnil, ir_mark, NULL); + return rb_data_object_alloc(klass, (void *) Qnil, ir_mark, NULL); } -static VALUE ir_initialize(VALUE self, VALUE value) { - DATA_PTR(self) = (void *)value; - return Qnil; +static VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { + DATA_PTR(self) = (void *) value; + return Qnil; } static VALUE ir_get(VALUE self) { - return (VALUE)DATA_PTR(self); + return (VALUE) DATA_PTR(self); } static VALUE ir_set(VALUE self, VALUE new_value) { - DATA_PTR(self) = (void *)new_value; - return new_value; + DATA_PTR(self) = (void *) new_value; + return new_value; } static VALUE ir_get_and_set(VALUE self, VALUE new_value) { - VALUE old_value; - old_value = (VALUE)DATA_PTR(self); - DATA_PTR(self) = (void *)new_value; - return old_value; + VALUE old_value; + old_value = (VALUE) DATA_PTR(self); + DATA_PTR(self) = (void *) new_value; + return old_value; } static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) { #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 - if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { - return Qtrue; - } + if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { + return Qtrue; + } #elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 - if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { - return Qtrue; - } + if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { + return Qtrue; + } #else -# error No CAS operation available for this platform +#error No CAS operation available for this platform #endif - return Qfalse; + return Qfalse; } void Init_atomic_reference() { - VALUE cAtomic; - VALUE cInternalReference; + VALUE cAtomic; + VALUE cInternalReference; - cAtomic = rb_const_get(rb_cObject, rb_intern("Atomic")); - cInternalReference = rb_define_class_under(cAtomic, "InternalReference", - rb_cObject); + cAtomic = rb_const_get(rb_cObject, rb_intern("Atomic")); + cInternalReference = rb_define_class_under(cAtomic, "InternalReference", + rb_cObject); - rb_define_alloc_func(cInternalReference, ir_alloc); + rb_define_alloc_func(cInternalReference, ir_alloc); - rb_define_method(cInternalReference, "initialize", ir_initialize, 1); - rb_define_method(cInternalReference, "get", ir_get, 0); - rb_define_method(cInternalReference, "set", ir_set, 1); - rb_define_method(cInternalReference, "get_and_set", ir_get_and_set, 1); - rb_define_method(cInternalReference, "compare_and_set", ir_compare_and_set, 2); + rb_define_method(cInternalReference, "initialize", ir_initialize, 1); + rb_define_method(cInternalReference, "get", ir_get, 0); + rb_define_method(cInternalReference, "set", ir_set, 1); + rb_define_method(cInternalReference, "get_and_set", ir_get_and_set, 1); + rb_define_method(cInternalReference, "compare_and_set", ir_compare_and_set, 2); } From fde37d8965c50ab4f70b79c039d387cd58ba1552 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 04:44:49 -0500 Subject: [PATCH 045/104] More reorg plus efficient impls for Rubinius and MRI. --- ext/atomic_reference.c | 25 ++++++++++++-------- lib/atomic.rb | 5 ++-- lib/atomic/default.rb | 39 ------------------------------- lib/atomic/jruby.rb | 28 +--------------------- lib/atomic/rbx.rb | 12 ++++++++-- lib/atomic/ruby.rb | 4 ++-- lib/atomic/shared.rb | 53 ------------------------------------------ 7 files changed, 30 insertions(+), 136 deletions(-) delete mode 100644 lib/atomic/default.rb delete mode 100644 lib/atomic/shared.rb diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 5dd956c24..c5552f5ce 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -21,6 +21,10 @@ static VALUE ir_alloc(VALUE klass) { } static VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { + VALUE value = Qnil; + if (rb_scan_args(argc, argv, "01", &value) == 1) { + value = argv[0]; + } DATA_PTR(self) = (void *) value; return Qnil; } @@ -58,17 +62,18 @@ static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE n void Init_atomic_reference() { VALUE cAtomic; - VALUE cInternalReference; - cAtomic = rb_const_get(rb_cObject, rb_intern("Atomic")); - cInternalReference = rb_define_class_under(cAtomic, "InternalReference", - rb_cObject); + cAtomic = rb_define_class_under(rb_cObject, "Atomic", rb_cObject); - rb_define_alloc_func(cInternalReference, ir_alloc); + rb_define_alloc_func(cAtomic, ir_alloc); - rb_define_method(cInternalReference, "initialize", ir_initialize, 1); - rb_define_method(cInternalReference, "get", ir_get, 0); - rb_define_method(cInternalReference, "set", ir_set, 1); - rb_define_method(cInternalReference, "get_and_set", ir_get_and_set, 1); - rb_define_method(cInternalReference, "compare_and_set", ir_compare_and_set, 2); + rb_define_method(cAtomic, "initialize", ir_initialize, -1); + rb_define_method(cAtomic, "get", ir_get, 0); + rb_define_method(cAtomic, "value", ir_get, 0); + rb_define_method(cAtomic, "set", ir_set, 1); + rb_define_method(cAtomic, "value=", ir_set, 1); + rb_define_method(cAtomic, "get_and_set", ir_get_and_set, 1); + rb_define_method(cAtomic, "swap", ir_get_and_set, 1); + rb_define_method(cAtomic, "compare_and_set", ir_compare_and_set, 2); + rb_define_method(cAtomic, "compare_and_swap", ir_compare_and_set, 2); } diff --git a/lib/atomic.rb b/lib/atomic.rb index d77f74deb..3f8446986 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -10,10 +10,9 @@ # See the License for the specific language governing permissions and # limitations under the License. - begin ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' require "atomic/#{ruby_engine}" rescue LoadError - require 'atomic/default' -end + require 'atomic/fallback' +end \ No newline at end of file diff --git a/lib/atomic/default.rb b/lib/atomic/default.rb deleted file mode 100644 index 7e1e335d1..000000000 --- a/lib/atomic/default.rb +++ /dev/null @@ -1,39 +0,0 @@ -warn 'unsupported Ruby engine, using less-efficient Atomic impl' if $VERBOSE - -require 'atomic/shared' -require 'thread' - -# Portable/generic (but not very memory or scheduling-efficient) fallback -class Atomic::InternalReference #:nodoc: all - def initialize(value) - @mutex = Mutex.new - @value = value - end - - def get - @mutex.synchronize { @value } - end - - def set(new_value) - @mutex.synchronize { @value = new_value } - end - - def get_and_set(new_value) - @mutex.synchronize do - old_value = @value - @value = new_value - old_value - end - end - - def compare_and_set(old_value, new_value) - return false unless @mutex.try_lock - begin - return false unless @value.equal? old_value - @value = new_value - ensure - @mutex.unlock - end - true - end -end \ No newline at end of file diff --git a/lib/atomic/jruby.rb b/lib/atomic/jruby.rb index c76954aa0..75c594f9e 100644 --- a/lib/atomic/jruby.rb +++ b/lib/atomic/jruby.rb @@ -1,28 +1,2 @@ require 'atomic_reference' - -# define additional methods and exception -class Atomic - class ConcurrentUpdateError < ThreadError - end - - # Pass the current value to the given block, replacing it - # with the block's result. May retry if the value changes - # during the block's execution. - def update - true until compare_and_set(old_value = get, new_value = yield(old_value)) - new_value - end - - def try_update - old_value = get - new_value = yield old_value - unless compare_and_set(old_value, new_value) - if $VERBOSE - raise ConcurrentUpdateError, "Update failed" - else - raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE - end - end - new_value - end -end \ No newline at end of file +require 'atomic/direct_update' \ No newline at end of file diff --git a/lib/atomic/rbx.rb b/lib/atomic/rbx.rb index 4a8552385..89e715f66 100644 --- a/lib/atomic/rbx.rb +++ b/lib/atomic/rbx.rb @@ -1,3 +1,11 @@ -require 'atomic/shared' +Atomic = Rubinius::AtomicReference -Atomic::InternalReference = Rubinius::AtomicReference \ No newline at end of file +require 'atomic/direct_update' + +# define additional aliases +class Atomic + alias value get + alias value= set + alias compare_and_swap compare_and_set + alias swap get_and_set +end \ No newline at end of file diff --git a/lib/atomic/ruby.rb b/lib/atomic/ruby.rb index 3df2f34f5..75c594f9e 100644 --- a/lib/atomic/ruby.rb +++ b/lib/atomic/ruby.rb @@ -1,2 +1,2 @@ -require 'atomic/shared' -require 'atomic_reference' \ No newline at end of file +require 'atomic_reference' +require 'atomic/direct_update' \ No newline at end of file diff --git a/lib/atomic/shared.rb b/lib/atomic/shared.rb deleted file mode 100644 index 0e79e446a..000000000 --- a/lib/atomic/shared.rb +++ /dev/null @@ -1,53 +0,0 @@ -class Atomic - class ConcurrentUpdateError < ThreadError - end - - def initialize(value=nil) - @ref = InternalReference.new(value) - end - - def value - @ref.get - end - alias get value - - def value=(new_value) - @ref.set(new_value) - new_value - end - alias set value= - - def swap(new_value) - @ref.get_and_set(new_value) - end - alias get_and_set swap - - def compare_and_swap(old_value, new_value) - @ref.compare_and_set(old_value, new_value) - end - alias compare_and_set compare_and_swap - - # Pass the current value to the given block, replacing it - # with the block's result. May retry if the value changes - # during the block's execution. - def update - true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) - new_value - end - - # frozen pre-allocated backtrace to speed ConcurrentUpdateError - CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze - - def try_update - old_value = @ref.get - new_value = yield old_value - unless @ref.compare_and_set(old_value, new_value) - if $VERBOSE - raise ConcurrentUpdateError, "Update failed" - else - raise ConcurrentUpdateError, "Update failed", CONC_UP_ERR_BACKTRACE - end - end - new_value - end -end \ No newline at end of file From 842a41613628c9857e1a952780652ae0908104b5 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 04:45:06 -0500 Subject: [PATCH 046/104] Bump version to 1.1.0. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index acb5805cb..a7fb0933c 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.0.2" + s.version = "1.1.0" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" From bb781a50e533312b652f2e44efa92a635a8f3466 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 04:45:38 -0500 Subject: [PATCH 047/104] Grr. --- lib/atomic/concurrent_update_error.rb | 7 +++++ lib/atomic/delegated_update.rb | 25 ++++++++++++++++ lib/atomic/direct_update.rb | 25 ++++++++++++++++ lib/atomic/fallback.rb | 43 +++++++++++++++++++++++++++ 4 files changed, 100 insertions(+) create mode 100644 lib/atomic/concurrent_update_error.rb create mode 100644 lib/atomic/delegated_update.rb create mode 100644 lib/atomic/direct_update.rb create mode 100644 lib/atomic/fallback.rb diff --git a/lib/atomic/concurrent_update_error.rb b/lib/atomic/concurrent_update_error.rb new file mode 100644 index 000000000..4bed89247 --- /dev/null +++ b/lib/atomic/concurrent_update_error.rb @@ -0,0 +1,7 @@ +class Atomic + class ConcurrentUpdateError < ThreadError + end + + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze +end \ No newline at end of file diff --git a/lib/atomic/delegated_update.rb b/lib/atomic/delegated_update.rb new file mode 100644 index 000000000..61d05f9d9 --- /dev/null +++ b/lib/atomic/delegated_update.rb @@ -0,0 +1,25 @@ +require 'atomic/concurrent_update_error' + +# Define update methods that delegate to @ref field +class Atomic + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = @ref.get + new_value = yield old_value + unless @ref.compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE + end + end + new_value + end +end \ No newline at end of file diff --git a/lib/atomic/direct_update.rb b/lib/atomic/direct_update.rb new file mode 100644 index 000000000..7e8c19409 --- /dev/null +++ b/lib/atomic/direct_update.rb @@ -0,0 +1,25 @@ +require 'atomic/concurrent_update_error' + +# Define update methods that use direct paths +class Atomic + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + true until compare_and_set(old_value = get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = get + new_value = yield old_value + unless compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE + end + end + new_value + end +end \ No newline at end of file diff --git a/lib/atomic/fallback.rb b/lib/atomic/fallback.rb new file mode 100644 index 000000000..166b2b676 --- /dev/null +++ b/lib/atomic/fallback.rb @@ -0,0 +1,43 @@ +warn 'unsupported Ruby engine, using less-efficient Atomic impl' if $VERBOSE + +require 'thread' +require 'atomic/direct_update' + +# Portable/generic (but not very memory or scheduling-efficient) fallback +class Atomic #:nodoc: all + def initialize(value) + @mutex = Mutex.new + @value = value + end + + def get + @mutex.synchronize { @value } + end + alias value get + + def set(new_value) + @mutex.synchronize { @value = new_value } + end + alias value= set + + def get_and_set(new_value) + @mutex.synchronize do + old_value = @value + @value = new_value + old_value + end + end + alias swap get_and_set + + def compare_and_set(old_value, new_value) + return false unless @mutex.try_lock + begin + return false unless @value.equal? old_value + @value = new_value + ensure + @mutex.unlock + end + true + end + alias compare_and_swap compare_and_set +end \ No newline at end of file From 3dd9f9c5015e2ca302b8c1b3684f76220954334e Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 04:46:50 -0500 Subject: [PATCH 048/104] Add travis config. --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..6c54c033c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: ruby +rvm: + - 2.0.0 + - 1.9.3 + - 1.8.7 + - jruby-18mode # JRuby in 1.8 mode + - jruby-19mode # JRuby in 1.9 mode + - rbx-18mode + - rbx-19mode From a02f0235041fb7f7846ce1e34a97f851ffcfa6ba Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 05:12:06 -0500 Subject: [PATCH 049/104] Add some ignores. --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 59d9b6643..84fe4c72c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ lib/atomic_reference.jar -/nbproject/private/ \ No newline at end of file +/nbproject +ext/*.bundle +ext/*.so +ext/*.jar From 1d74992edce425b67c0176828a2e549b065f768e Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 05:12:38 -0500 Subject: [PATCH 050/104] Fixes to get tests working on travis. --- Rakefile | 12 ++++++++++++ lib/atomic/concurrent_update_error.rb | 5 ++--- lib/atomic/fallback.rb | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Rakefile b/Rakefile index 3b63ad045..6104eb16c 100644 --- a/Rakefile +++ b/Rakefile @@ -18,6 +18,7 @@ task :default => :test desc "Run tests" Rake::TestTask.new :test do |t| t.libs << "lib" + t.libs << "ext" t.test_files = FileList["test/**/*.rb"] end @@ -50,4 +51,15 @@ if defined?(JRUBY_VERSION) end task :package => :jar +else + task :package do + Dir.chdir("ext") do + # this does essentially the same thing + # as what RubyGems does + ruby "extconf.rb" + sh "make" + end + end end + +task :test => :package diff --git a/lib/atomic/concurrent_update_error.rb b/lib/atomic/concurrent_update_error.rb index 4bed89247..0de4b80de 100644 --- a/lib/atomic/concurrent_update_error.rb +++ b/lib/atomic/concurrent_update_error.rb @@ -1,7 +1,6 @@ class Atomic class ConcurrentUpdateError < ThreadError + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze end - - # frozen pre-allocated backtrace to speed ConcurrentUpdateError - CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze end \ No newline at end of file diff --git a/lib/atomic/fallback.rb b/lib/atomic/fallback.rb index 166b2b676..0af058e65 100644 --- a/lib/atomic/fallback.rb +++ b/lib/atomic/fallback.rb @@ -1,11 +1,11 @@ -warn 'unsupported Ruby engine, using less-efficient Atomic impl' if $VERBOSE +warn "#{__FILE__}:#{__LINE__}: unsupported Ruby engine `#{RUBY_ENGINE}', using less-efficient Atomic impl" require 'thread' require 'atomic/direct_update' # Portable/generic (but not very memory or scheduling-efficient) fallback class Atomic #:nodoc: all - def initialize(value) + def initialize(value = nil) @mutex = Mutex.new @value = value end From 4c700699177ecd0a143af727842a434a8dd6e274 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 05:16:23 -0500 Subject: [PATCH 051/104] Update readme: rbx is not gil-threaded, JDK8 needed to build. --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a054a8bf4..3594c04b0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -atomic: An atomic reference implementation for JRuby and green or GIL-threaded -Ruby implementations (MRI 1.8/1.9, Rubinius) +atomic: An atomic reference implementation for JRuby, Rubinius, and MRI. Summary ======= @@ -56,4 +55,11 @@ my_atomic.value = 1 my_atomic.swap(2) # => 1 my_atomic.compare_and_swap(2, 3) # => true, updated to 3 my_atomic.compare_and_swap(2, 3) # => false, current is not 2 -```` \ No newline at end of file +```` + +Building +======== + +As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use +the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code +should still work fine as far back as Java 5. \ No newline at end of file From cd80d7a779f8d482e9aa98a8284ada570eca1e83 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 4 Apr 2013 05:31:14 -0500 Subject: [PATCH 052/104] Disable JRuby builds temporarily since we need JDK8 to build. --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6c54c033c..a5dfe2303 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ rvm: - 2.0.0 - 1.9.3 - 1.8.7 - - jruby-18mode # JRuby in 1.8 mode - - jruby-19mode # JRuby in 1.9 mode +# Because we need JDK8 to build, these are disabled temporarily +# - jruby-18mode # JRuby in 1.8 mode +# - jruby-19mode # JRuby in 1.9 mode - rbx-18mode - rbx-19mode From 1b687675363d57d881353f90518267d49dabef4b Mon Sep 17 00:00:00 2001 From: Sokolov Yura Date: Fri, 5 Apr 2013 13:24:08 +0400 Subject: [PATCH 053/104] Fix JRUBYREFERENCE8_ALLOCATOR --- ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index 316df73ed..d1af9eff3 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -54,7 +54,7 @@ public IRubyObject allocate(Ruby runtime, RubyClass klazz) { private static final ObjectAllocator JRUBYREFERENCE8_ALLOCATOR = new ObjectAllocator() { public IRubyObject allocate(Ruby runtime, RubyClass klazz) { - return new JRubyReference(runtime, klazz); + return new JRubyReference8(runtime, klazz); } }; From aa24d4d31e7ea4f5f82e1383814a81d79b2f09c5 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 5 Apr 2013 13:37:26 -0500 Subject: [PATCH 054/104] Bump version to 1.1.1. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index a7fb0933c..2b461da67 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -2,7 +2,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.0" + s.version = "1.1.1" s.authors = ["Charles Oliver Nutter", "MenTaLguY"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 6aeb05312e168126d2174b0d58b16244bcc7e85f Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 5 Apr 2013 13:38:31 -0500 Subject: [PATCH 055/104] Add @funny-falcon to authors. --- atomic.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index 2b461da67..50925ccf5 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -3,10 +3,10 @@ Gem::Specification.new do |s| s.name = %q{atomic} s.version = "1.1.1" - s.authors = ["Charles Oliver Nutter", "MenTaLguY"] + s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" - s.email = ["headius@headius.com", "mental@rydia.net"] + s.email = ["headius@headius.com", "mental@rydia.net", "funny.falcon@gmail.com"] s.homepage = "http://github.com/headius/ruby-atomic" s.require_paths = ["lib"] s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 2c5ab6cc32da1781428166df407db74f2c81ee77 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 5 Apr 2013 13:57:24 -0500 Subject: [PATCH 056/104] Include README and oneline logs in gem description. --- atomic.gemspec | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index 50925ccf5..169e8cea8 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,11 +1,20 @@ # -*- encoding: utf-8 -*- +# Update these to get proper version and commit history +new_version = "1.1.1" +old_version = "1.1.0" + Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.1" + s.version = new_version s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') - s.description = "An atomic reference implementation for JRuby, Rubinius, and MRI" + s.description = < Date: Fri, 5 Apr 2013 14:19:01 -0500 Subject: [PATCH 057/104] Attempting to get description to look nice on rubygems.org. --- atomic.gemspec | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index 169e8cea8..e59263c3d 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.1" -old_version = "1.1.0" +new_version = "1.1.2" +old_version = "1.1.1" Gem::Specification.new do |s| s.name = %q{atomic} @@ -13,8 +13,9 @@ Gem::Specification.new do |s| Changes in version #{new_version}: #{`git log --oneline #{old_version}...#{new_version}`} -#{File.read('README.md')} +#{`kramdown README.md`} EOS +puts s.description s.email = ["headius@headius.com", "mental@rydia.net", "funny.falcon@gmail.com"] s.homepage = "http://github.com/headius/ruby-atomic" s.require_paths = ["lib"] From 58d3e344259ff0ab5952f34b0700673c113f35e7 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Fri, 5 Apr 2013 14:39:41 -0500 Subject: [PATCH 058/104] Convert README to rdoc and try again. --- README.md => README.rdoc | 12 +++++------- atomic.gemspec | 22 +++++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) rename README.md => README.rdoc (94%) diff --git a/README.md b/README.rdoc similarity index 94% rename from README.md rename to README.rdoc index 3594c04b0..3c1f98f91 100644 --- a/README.md +++ b/README.rdoc @@ -1,7 +1,6 @@ -atomic: An atomic reference implementation for JRuby, Rubinius, and MRI. += An atomic reference implementation for JRuby, Rubinius, and MRI. -Summary -======= +== Summary This library provides: @@ -20,8 +19,8 @@ methods: The atomic repository is at http://github.com/headius/ruby-atomic. -Usage -===== + +== Usage The simplest way to use "atomic" is to call the "update" or "try_update" methods. @@ -57,8 +56,7 @@ my_atomic.compare_and_swap(2, 3) # => true, updated to 3 my_atomic.compare_and_swap(2, 3) # => false, current is not 2 ```` -Building -======== +== Building As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code diff --git a/atomic.gemspec b/atomic.gemspec index e59263c3d..f0091b092 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,21 +1,25 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.2" -old_version = "1.1.1" +new_version = "1.1.3" +old_version = "1.1.0" + +lines = File.readlines("README.rdoc") +description = < Date: Fri, 5 Apr 2013 14:52:45 -0500 Subject: [PATCH 059/104] More formatting for description. --- README.rdoc | 72 ++++++++++++++++++-------------------------------- atomic.gemspec | 11 ++++---- 2 files changed, 32 insertions(+), 51 deletions(-) diff --git a/README.rdoc b/README.rdoc index 3c1f98f91..95d5b9580 100644 --- a/README.rdoc +++ b/README.rdoc @@ -6,58 +6,38 @@ This library provides: * an Atomic class that guarantees atomic updates to its contained value -The Atomic class provides accessors for the contained "value" plus two update -methods: +The Atomic class provides accessors for the contained "value" plus two update methods: -* update will run the provided block, passing the current value and replacing - it with the block result iff the value has not been changed in the mean time. - It may run the block repeatedly if there are other concurrent updates in - progress. -* try_update will run the provided block, passing the current value and - replacing it with the block result. If the value changes before the update - can happen, it will throw Atomic::ConcurrentUpdateError. +* update will run the provided block, passing the current value and replacing it with the block result iff the value has not been changed in the mean time. It may run the block repeatedly if there are other concurrent updates in progress. +* try_update will run the provided block, passing the current value and replacing it with the block result. If the value changes before the update can happen, it will throw Atomic::ConcurrentUpdateError. The atomic repository is at http://github.com/headius/ruby-atomic. - == Usage -The simplest way to use "atomic" is to call the "update" or "try_update" -methods. - -"try_update" and "update" both call the given block, passing the current -value and using the block's result as the new value. If the value is updated -by another thread before the block completes, "try update" raises a -ConcurrentUpdateError and "update" retries the block. Because "update" may call -the block several times when multiple threads are all updating the same value, -the block's logic should be kept as simple as possible. - -````ruby -require 'atomic' - -my_atomic = Atomic.new(0) -my_atomic.update {|v| v + 1} -begin - my_atomic.try_update {|v| v + 1} -rescue Atomic::ConcurrentUpdateError => cue - # deal with it (retry, propagate, etc) -end -```` - -It's also possible to use the regular get/set operations on the Atomic, if you -want to avoid the exception and respond to contended changes in some other way. - -````ruby -my_atomic = Atomic.new(0) -my_atomic.value # => 0 -my_atomic.value = 1 -my_atomic.swap(2) # => 1 -my_atomic.compare_and_swap(2, 3) # => true, updated to 3 -my_atomic.compare_and_swap(2, 3) # => false, current is not 2 -```` +The simplest way to use "atomic" is to call the "update" or "try_update" methods. + +"try_update" and "update" both call the given block, passing the current value and using the block's result as the new value. If the value is updated by another thread before the block completes, "try update" raises a ConcurrentUpdateError and "update" retries the block. Because "update" may call the block several times when multiple threads are all updating the same value, the block's logic should be kept as simple as possible. + + require 'atomic' + + my_atomic = Atomic.new(0) + my_atomic.update {|v| v + 1} + begin + my_atomic.try_update {|v| v + 1} + rescue Atomic::ConcurrentUpdateError => cue + # deal with it (retry, propagate, etc) + end + +It's also possible to use the regular get/set operations on the Atomic, if you want to avoid the exception and respond to contended changes in some other way. + + my_atomic = Atomic.new(0) + my_atomic.value # => 0 + my_atomic.value = 1 + my_atomic.swap(2) # => 1 + my_atomic.compare_and_swap(2, 3) # => true, updated to 3 + my_atomic.compare_and_swap(2, 3) # => false, current is not 2 == Building -As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use -the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code -should still work fine as far back as Java 5. \ No newline at end of file +As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code should still work fine as far back as Java 5. \ No newline at end of file diff --git a/atomic.gemspec b/atomic.gemspec index f0091b092..10da20a61 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,17 +1,18 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.3" +new_version = "1.1.4" old_version = "1.1.0" -lines = File.readlines("README.rdoc") +git_lines = `git log --oneline #{old_version}...#{new_version}`.lines.map {|str| "* #{str}"}.join +doc_lines = File.readlines("README.rdoc") description = < Date: Sat, 6 Apr 2013 11:23:56 -0500 Subject: [PATCH 060/104] Fix #15 by explicitly testing for GCC's CAS. Patch by @zimbatm. --- atomic.gemspec | 4 ++-- ext/atomic_reference.c | 2 +- ext/extconf.rb | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index 10da20a61..eddb34297 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.4" -old_version = "1.1.0" +new_version = "1.1.5" +old_version = "1.1.4" git_lines = `git log --oneline #{old_version}...#{new_version}`.lines.map {|str| "* #{str}"}.join doc_lines = File.readlines("README.rdoc") diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index c5552f5ce..39747c0d8 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -50,7 +50,7 @@ static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE n if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { return Qtrue; } -#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100 +#elif HAVE_GCC_CAS if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; } diff --git a/ext/extconf.rb b/ext/extconf.rb index 192d3e764..99551b355 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -14,6 +14,14 @@ extension_name = 'atomic_reference' dir_config(extension_name) +try_run(< Date: Sat, 6 Apr 2013 13:17:18 -0500 Subject: [PATCH 061/104] Bump to 1.1.6 for botched 1.1.5 release. --- atomic.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index eddb34297..6f0531064 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.5" -old_version = "1.1.4" +new_version = "1.1.6" +old_version = "1.1.5" git_lines = `git log --oneline #{old_version}...#{new_version}`.lines.map {|str| "* #{str}"}.join doc_lines = File.readlines("README.rdoc") From 7d0ade6e62f3e3ebd11f287e62e9c8257b01d6c5 Mon Sep 17 00:00:00 2001 From: Sawan Ruparel Date: Thu, 11 Apr 2013 09:31:54 -0400 Subject: [PATCH 062/104] Changing the arch to native, to make it successfully compile using mingw --- atomic-1.1.6.gem | Bin 0 -> 16896 bytes ext/extconf.rb | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 atomic-1.1.6.gem diff --git a/atomic-1.1.6.gem b/atomic-1.1.6.gem new file mode 100644 index 0000000000000000000000000000000000000000..ac10e687d900f32b096fea1556c44e1dc884fe9c GIT binary patch literal 16896 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 literal 0 HcmV?d00001 diff --git a/ext/extconf.rb b/ext/extconf.rb index 99551b355..00f2bb337 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -24,7 +24,7 @@ case CONFIG["arch"] when /mswin32|mingw/ - $CFLAGS += " -march=i686" + $CFLAGS += " -march=native" end create_makefile(extension_name) From 14fc4a99d4ccdd2edab1a332574fe1b3e1f80d07 Mon Sep 17 00:00:00 2001 From: Sawan Ruparel Date: Thu, 11 Apr 2013 09:37:48 -0400 Subject: [PATCH 063/104] Removed compiled gem from src --- atomic-1.1.6.gem | Bin 16896 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 atomic-1.1.6.gem diff --git a/atomic-1.1.6.gem b/atomic-1.1.6.gem deleted file mode 100644 index ac10e687d900f32b096fea1556c44e1dc884fe9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16896 zcmeIZb!;WgvnA+jW@ct)w%g3iZDwd=yM4{fcAM=sGeeu1nVFfHnb~)~H>;g_deZEU zH1o8h)i3_2tg5Jt$~>u39!16ZY2j>QZsKghZ0QO1pJlB77$+wu*uS;^*ney}*jTy# z?|c83pN)fqhZ~HP^*?Js|30pZle3BAKd*PQvaqoG_m2N?{{QCxuT%SXllu?d|4+Rn ziG&4PZ2O@K4l$^u^J`rS)%UnMl^;b(Ej&K65Eha*ECDxUp3pxFQzlYOJD$SPEPnio z`4Cq2%d1`i9y_vncPEZd;TS0uG=Xf?40lk}qchmykb5Ci(niP2HY{N|*&AK6i-9#qbgp<7Gn z><`7w$y`rHPVY(`^zSI{Lh8q5nhb9HO>v$|FG`L}u79+|`Yx{h zC_`#?cvGi{qe@VQ>+uvzoIn{$zfnGuF*ksE4jJ;?qEU)f7M7jQMyO+CM2&2&a~-b#3Gm2^&@T{v&PebLNd0rT4BmfHQneg(?Mii6}GHWMYR@fEdM3NQ{ai3&{=hmqe;fE-Qwk< zy}8?io3_V(Xo&@7J`LG|y33!(iL=~xt4y?|jBZc*l4t0&h zl#AFP!vR|u85Rjz*Ol4l|6|WMdx*-V$FyqKSo{#>v^(D>i=);#D#rQ~H%ND(iviI< zLq;L!h4Lf(3V$11X{;RY&cq=i*jPH{PQ4u6m@Vnd7Kbj&>9`*2>@pjSf}%d%Y;l8z z7|=ihR?}U?c`iAyZ31Z*k-43<)jkv_)#LY7_a?^h_UDHYOm>ufCM~d*p>DpCCoFHl zW4ienjz|b#=U)DSj1}emRxH`Q>EhDM7x;B80auDvJIS-P-vD2mt$m=hAoX*OgEK_F z>Zqp#y)ewaKU-E`^EtbM zi<=d823cU~4-Jke!3WE?*fTW#-I(#22fYRHbOV|+gxO8O795FRx$Uk1Y8+T|G32F-oR~A=$qbmg!d-tzsZO4c*lEy*2_2w^E>=I)7>#5SEb;VBw zr20`8t15Wn^ciiQdzM6@5-O!%%YpL7bQo5C0^OJlqOo(q1Z1{u;gRYe)*r5?eO28= zi^`8}ao|+VE4oiV+m-&XiJVxU4hXXN?R7MRqawSpenEP-z87?pn{xG%NFdgeQh)Fu# zeKPsg?Wv|#(|XM`qQ`JI5;}c%r;BBC8TUL{iNo>iV-~Tx?Maz_XoVGFZ-$=mHLHfi z@Dp7XSypJVA3spYVe;i~9G#^f{mFIadp)_n(Q7JyGYmmE%td(~AFTqdKbm_jhu;Hx zzcd|^s(Xl*6dTFw3@k-x4xaQhj7wa3JEU&@=&vuXmYjS2sqGu+3m%m3bK8`U#}EIh z2ua8<*CWbSGHrx`XxtuG3D`J?Qj*+nq$VyHi=83GeD|J()AMNPD>tdv=GBYT+p1E6 zD6lOzcLHm}(m;#8tp^=AY)@C+R<;)crssrQC znTZSCi{ug4@SN;`Q??Fio6pNk=lui0ZpE+NKBe*>QLQc)A5bOP9TvJM|EF$k{~Fi- z1Ooq+`~Aa!{=egY?A&bJ|BV~|H~z=|FaGyGv3mdOkNkK3cOm$xMZnYa`3OV?1uYd0 zPNnyT#uchGQ4PqRLXUvU8Yvsbd?OzJ!M%@n?QKlE>*x0@K4&##CbSk@>~%4Z?j_as zZ)Ox11)cV!6{nul80B4ZnzFycpLmEK$3NGC=uK{gu8~8HFJXKbSs` z?!u^|UTqUyIT%6(M6)nGFbrdrlT4QJ-=#6#fl(WAQjSsI{oNNSwcq0=t{f4bldbj* zJ|c+KSCuv2@JtMdLm#!f+`~+}ff-?H{gGLG>h5ICp2o|(doFS7z_k-UdRE@KIn@ia zgmTby*$NI&Kt~$~nfoGsUK+r6N5!h}XE zNQ^2vM)5{z!$#(Cqa9@BPXNLSqMPBxen7%-0U+ODsc)ox&x#+c%8X`a_5$-WwWU02 z(?fjQ>;%nUYonk#d!RU#a~F^WF}G)9CntGSES)gAuiM~M)Wf=h(WGwoMcb`2J?Mn6 z0`tOu_M&F0C@n-%{sFFqXl{xG`_5=cW^wS0P^P58jXD^~n7EG?d zY5Ku_u!^a$D||kHdtl(QuSx@{znIsw>b+KM8q0@D z@=-b2BEhV^ZwJxHhEJW)^F>0<_hPPNXqWm@E}?_ov%(tf`NTE@&S6G#_?6%vS03|R znCn_w2|^69hr#ZVc2~pA;^IHU%1NtKCQ0J$BpxCAx^X17U=mwJ4@%%<_4&ZTD9Q7# zbBn=~8%4m8EF%QNzKxLs!kC-j1q%N13!X(()IuhaW0{;X^jLqEI)8CeGQeVyV?SSA zi%{pzP9`!qoaw6L@}n`GPHWvyPs9o+Ywh~YbOlYDyloGC{SvmXPPza|S4Ka!ehN2( zel>x#w2qN`KEHt#pcDYK-$;3Ph%`<@uV4@B9l=EmkSJ;Ol*RJ8ND6?$H@_cEJ?dms z)Q5DmL09dY{l{6MFGmEbeqd`XXxlzC$y(WaQzXRZm6Gv`nFv?t{KyyKghBoP=#uRA>I`5Jt4Id^Jr@i{z0a zAN2UU1qR)kULUrn6L^(0K1U*u0>otrf-3QLLb;BmDQl0uHcGMRYu4KGed-5ij}B%!K|!bSuqmF2 z^3Jp7c*4?aGXV>8MQA6G@KY~eI!3ckyaYy#EbdJU{q&cHx4qmamGDkki>2?LepI0F z&#!7>PyKArx$@EN_Iny=jB^E(ttB#dZ(1tj?}Fycij(d~3XvPr23{XMVP~B4)UjW2xuO-osgKH-LivC&EkP}0G zqm{B^CRvYwkM>fbeX)LOx?N_fO@Ecept5xR>-E_?d-{!*;kCXA`1xU^r>Dm<4Qgzp zvAuuwBgx4x{~cO(c)>NOY@gbC8=`I7NW42v;LXhFILEgp4848WdO6tvc6>AmETN0x zuZ~5|>0TWiR-}LQzJ58dx?Uyl4t!jXaYv?hJV~Gt^ZgCvk#szR4#1VYDV^by?TsV@ zL3Iq)OmmHVj?Vmyrov_Yoaq0jyM+M9MQ#S{jZzKW6I5)`FxVQ{x0t%!(wAf+m4{Pu zmVTAwXk|=gvS20K3lwE_G(|DQp@8|JTP_}X<$@JZ^m-Y6Ms^#WF=RB78IMG_(-@$< zGhUnrl?a?~(H+~gIdS~L6H>GpIcvBM?fuUSYJpvuEU6*BbW0*Sh3*3dsYJ#B`mh>b z@Q!+Pz6#E4j6l!M55ilq*6e*oV(A_u)5%wT-79Dkgp9h+H+Aw}F`+@ZjY zjks?0k$5cRWQywe-w5*28>kw%$S6-jqaErYD(XEAMa&SBrHU!L=tR^)j&L7k?=wP3 zVvc9Ac*g<4U~K^z7i24MQs?K;Tu|BZ)NE3^>bZ<_c%k6>PDn^SkLIvMPu{pygzOsn z`ZYKEqMuY_Hu=b0w|e@vEBo*uGNh>wp&_2Us7ZiWHiWOQn(IlpU+Qd6ztkR1>Itsy ztucGA1YVMdm4YFdl=R7^|KE220hnS$FC;Q5CxC%vXDYBpdZW^Yve1E=ZMW2$7=5 zp=xkLP9P7XM!LFp!h5&Gq(oc!EYu`62=>k(w$<>m?*lXsLS-uW1jl+K>i5n;Wsv<4 zugcDRBbFvJVO5Kp=wYpe)CyZ&M+!hqU#6O2k9cH3MX4p0@luNG0+jP8g!eIXqCpL8 z`PT_Qh+CO>DmbOJwip){C#U@w7#mP)5JUb>A(5LT5la<1B0)ZEU(o_qDl%scDdg(_ z@FwylO`C^M5+Tl|O(fPN8ITrm5ELuYq1?ixr!@t$;@kmlO0tzZ+a0DRd+_HtQ)+OP zE;P*cC9fUxh4@D#N>5$bek%Kb(W@Z2bA;50@f;JvGvrIeO_IN%cfSI8676wy0nM(|sj=3z}dk!|pEB-Y6?r!#1_e)Al|YX51@~e_SOY>7!tdK)9{tUG{PugGrnr>Bv$Zhf!UKaSo(Qo)#qD{W8`zRcUm#g|f3gBj0~KswbKb=5SBTnP(ie_G zT#e3K*#UZ7G4bXhut8y7s-a8ppyH(co-E3=9MfZPK65st2R00F`n*G*w3mLFk6bdK6r`E)VMQl3J3iR5#xh~vLl8)qiPAN?;X>>$=c zi&MvDR4aR)t*M0_2mUk!k;Lfy;<@|FC@kXn%1)PR^nEC?_ABhkDos=zFO1q0laqSK z=q7Rei{kV$jl1)f6jflxza}Xj28ar^BUO{W*!KgYUABnbIGb$m_ef0|GR2X&rApt% z0+H9Ys1UB6od@>Xj+KOcWPW*oJ%cp8=>c3#>nG~(tStIu;ZPDZ^tUozVGl9YPbO7+ zx}j)w6ZMSDF%-?2NbBlO1{|s0OM*uGd^@Z{vDO_m6|@esWJ*pxJOi-?x-Zg7 zY@D$L@+bec0B4K`5`{$i942E45sVDoj#m7FOkZ5B@#iY-g$iO4c_r)>a^_(%@2JL9 zzG!~SREBu#7S)Z3KN?H1SXQb-HxI08;v>C-8rziO9uG3~`j}!ZQYV4+5!+^*`>G8Z4u8%- zKP|ac5?y_y4lr|@H?PNQa-vlNrCfixH#|BYwc3V;=3>k?2qPI(m^;G9f!$U}PnI5q02}elAhMpN(qAcep9BLD}lJYf+Ui#XQ=_6;*-v zU#K2RDes*y0eSgbel9X5z<4hE-q9xcCP_8KP`Sv6$D(iYptxUA8=FAjB zq^ls%LY$t*(50FJOktwv?N60G#lk>Oc~JCM>>jRIbe_q+DOO5x#xZ> zK&v7o#}=~xQW7}PVjI&kcB}Yn`J1^I(y>T@dQSj2;3Q18P6A;Mam%4?C=!8i9DDJk zug}_FQ0x%DuOlrnn$Rf7s*Zda(?`lJ=Ou!JFn@L}s zEJ@0b#nG+NawUurubMiyn?0-R9Sh5DCx^hDr*G2j!r-pork@Nivp&QG?o6)_a-Ak3 z+rI5RPN7AOWoUhq-h0d_SpGdsl>F53f?-^P$4V@&E`;tYvZZBIM`3ofiwnyeIGp;=q)>u6e+`SFjQ<4@1G?~6!jUrf##0s(RI78{Ztmh&K_}*RA=2CxpGztA~N{bANS0a^?Rb} z2T&(}EunoQhW~ZZlpMcuqEyAp#0+}HRNT^0uRh^BR!Y>>njOk^!!mrRg|8k(`94u=0miXDYlPJV#-DLx-&n0qn~MY1dFD#ccq zJxp7{rWqh%H+1ZeH>qRDqnd~d*3d=hA3j~wyHhbECvt`chxW7ai1YqcBvS`HPrV)2 z<^bZm)r1pe72jk~CqmI}EdtKUdZz0Tceb_wv>M+rdl1B}#qkaweOsA<_`Q!;4#;U? z)uU@0XzH*6s`%`VU0ND@C0Wu_*1iAqd%j)8{+1_nYK;t*sBEAAkZaJa2=ME*8P@=F z16jpV-#&4-q){|HTf>mT>#$0j@^F9g!&s5zlT|o^JH&&*^CEJj^zGsU`BuRqgOKo8sfgtBu&RQ!Bjy%*BE!34bk6y1dC9>9cIb0tpU=n9 zW8h-m$%dUBc|O)+`**Y_(ErI?sY-a}(rSnm5lQop@;Qf4U9u26FXTa8HiXnaUy$>A z&s2HCpnev&CgCSFU|&{T!Ag$OKhhR)3_qos%mMxlBl#xNOI3VQYus9IUVrG_`~pWt zNWC0pKN+IGDC)))A}-BM!<%om;;8N&e+({#IT|8&`e%JC8v8a_X8`xp&W(y1EBpoz zDqsaBZ?+iX8SaWaWdwx+pBp*hSAPi^XU%_4=hjqMy z4AgxyCh&sOKRdS)XLj`>Ii&dD8I(J$Fe~b}qSYAlR_b7x6E;{scP`-PUzKiNPx8GC zG*Rz8e|$v|Gk-r50Qa~(XIJdG@my7uMQ#ECD#-68V0=!?vf5ee&v?;sFiRobh6c6k z6goqb5{-c-EKqW-qUd<0E5zR!f9vcFnbOWLN(6d*ORn8YDsly(d17V^`>zZf(pGz6 zzjoXVic;x*P_YGa*RKJ?cS$fsbTy0}nDMP=p`B)1IX=^lQ{tE_&)lf3<-Y=vLy!_ zX~C5m7|M;h9nLi|aSg^}Qt^4rv|JL?tbnSBc&ALin1v9Z*Pk3=^p{*MGCpJfp&+c zL4=oQtf;|u{KJ2;vJQ`V7|*N;LF{&p8lF3k*>mLDiu+2j8lklMZ5Uk6Xai%!oCtnE zw5%SrRsoM6**Aa*BA1qn_cvwfU)i5?KI?q^p}jvH-r#;pg_hQl@ma-8$^HB=X^}Im zRIuSE!`y2l$Yn^4PGWc4Um!6y&S_V6_tKECY>JTHbXN(r?CjYG?L2{K67Y!LtCQ+f zR13VXB-3o@Z9_KmJy8nutw!*L0Sd|B9~{dV8L}6mTBW=(`WUa2vWo=^0AiXw|9xr< z%bj7_wS}eg;x+gfm-Q*=B}KOM%r)h=x)h}7Q;RZmT{9dBlw===@D<*Nncfnu3>4-B zMrTje#I@LR+PjHVwRCd@xEINeD!P2>fNvxa>bq!Ii*6Yj5zr8dLpnNmHMy&R5UB7{ zI5{-sA((+Zn9S!e3@Yn5fTaOr*OHacv)S-BsE;#F)@U(bP8WFeH7K-!aqeEpEB)EG z)+|M&4GxDEHme78w>>k(&va@vrfL4~^DOb|s{PT;ji-fHWtLIAvM?8kXT1U{AML_& z4goCwXM4)Epry6grSaG9wMvh#6t6mvCUI2{CIkx-^-b}}T<@5=cW6D59d(R=12+t7 zgvx?x1y}`yk5DAfY1GXEdKm12Q6xfcfBV}fH~dl4JubBi=EHa_k4!hxX9IzMnMC6! z!$(g~l(tT|Sh(`wT+#RYF<@qqe0fN@5mDKB)JAQ~2kg+YG-{LzT$jOORi>XbuGXn^ zwlz2t1Wdo=L#|;xwx|tK6M|_D1^T+Ni8FF+0Coy=U;ENK!(qU6Sqo(QtfWAAU`nyA zmL#riO#Pg%^2nks2xkfZCL3Q@A1t7?)uW<DT!=NdFG9Yj2nj z$n9T1yAiNb#KsoK2oWZ}Noh5w^_CwBit98GHBL>6X-tx5jC`!(*0#|cs@I}{COBkuS1&u7-_T*H|QUyincxdWZc>x)YcNnh#kEn3P^;Y?}49_yqMC}EMlIrJ>C()?Msw%oqe~t;Vy4MIh|0xY=Ca#@r!OYmbJUASXF}Jnxvo%*fIKg4Ky{LA%G1GV z_fWiuIX7uGK%ii9{pJj6yX(drZkzrTR?b!!1uYE?>3>Zhg7m-q((bkg#u-@rN3X;4 z1o6gOf}p#3QzdCGrA&B?ZnukRnZW&6qjqqZ+=I-Agp8Sw)hA%@2uv=9+_S&Ud=umq z$zu`3O`TM&yuGW_g(q~^-~o+*bSdjhcz@eBh_-RvtrgwxZcXN64fi!z?!yc2Zu1B zHFEIcG-7Tp^Ugo%EiM#I_$g52VGP*+Y}E`@3rv4nl?WBdbQ58rqI3{7cgijQriZ`- z`#zxgT-S*;!dUxW%J9{xFn>uU0dUZcR`iQLw|{P1ejEeazfXbQ-7jywKaYJcK;4x; zWINXG`@iF5ms0LnAx~}ww(2=BH1G6M+xO*Bafv|k)b5GN`K$spce{J8nRq0d-%YQ- zm#qK9>gT;*I@;ZOkc z>&do)TC9lTFU57s<8#Z5^w#ep5=R*`ggJQ9w!Sb!h?%n~q#E^5Buc$m%8c-G$z_6E zYQ&_!JQ##sodBgC2dh+%Fk$*i`&S)kQfzVmTz`#7-3n*~>wU2WmjJ?qnFD_dl3jq#U zSJH-VzAjabR;Z&i8nnSMnwX#B% z%?c!@NQk^cQ>W+PflA=)tyFWD3T>+23+O2#91_ZICNP^4Q}~1wywMo)R3=eBH}mA- zzf4&UEXB8UHwE(T-UF=|ioVZjs8-+xx;r%ELdr@c7BTuBzteu*y$grde&hZUUfsxH zgm##J+kTUJ{aU86wY`5gI{pG}fIzlP2)f9E7Vcw2R~&2NaLCPd6^X+JPyN>?^xHc} zP-8!6Jv~H=Qrw1eVU<8`iZl1kx%}dVtvpIjSGmfM}1B(e)0|a#*iB`po=@EFMYIxgSP~8uc z2vxbf#J3-SHc-DB=*1X%xH#M7m>fcBlO69413k6l7c z8MO9PJ_yPpg$TlS!yhZtBYC5rz!PtRH@kOXgTs-YKSF#C6S5|!Ek~UfAm5H!)h5ug z-u>tH^PP^t=YFzK&&z(X5LjztWp|t0;kC_WxlPW%77TAr&khW2&eR@^an8U23@^|6 zhxcK0uK0rQ!3B})L;kuZaXixV+;A(Hbsvg#~S=4<@A%;ZmP)=+3b>|+Wqa6Ov z+b*1rOPNEj@?_oD@CpeHe-k%}zZr=VED?ZH3lc zm*2#lp~5(VI@R5q9*@QIJE#zK3rSEhTVw(}V9NoK5h#Bl9Q_&D0n9B1_9-kU-w#X8 z)oCU0_l#O-#0!=&VSX8QrmvD46r4hT{i?e%Lw&awO;&w957kFCoHzkh(>pK5))NsUf57(!47DQ?{E zOFx>P7aJJwkgMWP45ULua!pClPu0$on$Tf$_ zG1FS=qCce{?@WI~iaz6;-8t7LmJvd0Xj_RqYgSZqjS^8GdBH1KGXU#FD%fVRUuL)` z6ie4pWQKpnVQd2g{G8nEJI81iF;%u8FlG1{AGk>@}RWJVKdQ+Xxuv~H~ z8|)cObCAFO$G7ri2}p4|LA!{?b}@F???G+p!_!}0`+inz3D0fmUP0xHTj$sC@P^l* z#&u=llqpbEWp(rMvET96_6F$P^iw$NTMhkPql=mUjBi>|;*czh@N`&qXU}F<<`CId zo47t&&UOAP=lP-U!ZbMFIn%nv_g}YP^2a5%y~mPIvd@M%&j+EdGvpB91It*4jY=J{ zFfzUdq6+Bn-scwv+X-SP-$!4|9643+jseHcJ1qKRTAuBFEEZ#CFoaJxWZE<+lDqk+ z&D+P3^5c9>bCGO6iz(&K7z7^o+I7Z!{sQ>+EZ4ZsBI2q`=45B#`HrpE+`GDjdLwVR znfdu+z@c-~5KLc*BZBjLR&O*ug0-?m0B`pYCEqdV+i`{TI)#)fVeN)X9}7(F(p8F7 zYKfxl(^DTQU59xFi;=wO`7fbchzwA82|^#b>|4>#E>&nes)K?gWk+K8S@@;1f;N@h zju*@OH?tD@DZbff9U07!DEx)*8&qe^y(O{$VY}D%BIU_l!lPrMBoRUaIJ&t!QzVr38 zj+u8C7DemIVzj&yp{LH-zV;U6%;mF=fakn!d|+ZfNc6*#F;Ue5wxF$lU0dVWW65~;LD5K zlgTAfBbO4UPbPWO|FhS9eGHNc4pfyQ3FW(>Eml-Ur>&Y7%+w?`$xo<4O%QCfC~Ukw zO(g=35pTF-FDMus&CcH(FSOv(b_lC;5vDVy@pqgq7m7J!?`3YFBXqe^#*?{q7}u_D zrHwWQ0qM&ak8fE?fFawk#`L8)<=z<{NfHDsc0uFEp1c#`a`B;g2x3oKsA!b)ezNC8 zD2ik|Zhx9!4F9+lTKvAWB99fL&el{u)R;9`6rht|Bj>)6|2kmf`(FG6Y+CI$vG3@_ zlH8^T@rS->{}2lI15$!6Ql`5NIq4TCU;Iki9? zt%e79Am|*AYq+;zy@f+-&AA<^@&YSIZ^oKha^yxn9*Yl*Wwpe1F>zUh&Sw<4FuF)N z;_*eom`Dqoe$Zo)RMf~?={qf{{_BfGVRc_|3+DHuEBHqCN{iy?C4$QMk|9Pq9flO1 zzZE4p-z|yyV26E;ws8Cm`gN5VN=ld>@go@IzUB-h){{C@Mg~B43$r=Ar~5=tepSkc zemZ^~Pv*p+tYg1Sl83i^WY08>4&1%-F^7?i2gNeaF^z3L_g1$VYj2hcBU5!ovn-2m zpTYbOjcv}>0sWM1^wBI=!-a{^gYWSzb70=?9o!CSuFuoUx4zdjDWGx>L_;dAtGT5x z;VK;aI8f!|Q6& zFh2~KxnVY!Bp5G};=#&vZeC?9Z%)msKCez)2`k6Ay0R_Y+w=XVfanPGMCcT4$niwm zmZlI-+#J8o0?1r$!_)X4Ilaf+lO({Jtlf8|e?7Z=kyLb+-V0wo6}ViRq+m_bBh%+-PTs^q4#ax;tIYIl- zpQo>$WZFSzbCzEdfS~EOt$&iT&FZWLJ9*}qk&!fJsu_ApFE;(XpYc`sIo8)^*N@<} zyGzIgG+ppdVyip(L%KVMPi98a1|%2{;?Dzl9DZg=e(H}+7kykOgZK;YMj?86MnN=} zny();ZIDi{ekeKN1i$l}oJ%=4jehPuYk9#u5FN|^nwLU_8)EM-12&r;hN7UG(5wJj1>fvv)v`fFJ4M=_vKl+= z-%HMfpoh>>{C^fYDqQEDE;!fVr*sWM5-GD#@l+IEj}#WzK8M; zmrF{6S>tniDp>9_qULq@B z>pbkgeWtAX0k1#qF90pT&tuhg0T9XLz2C<4a3=TCbJ8#SWMoE-jW$*5qFZ`a;{BW1 za#sjVqdIbQR*PMYRmx^9zxv9MRvh<~S5Vpl=z10u`wwLm{wFI1nh?I9{@?(4H%)^e zz`#KN99nJ}9>EU&*K3yl72$s$0%legX0}c)Kb@F8On%z^=coYwt*HP1LI26h$;SR4 z^q-tuob3P7fBx@V<^OS{|6c!Z5zEkoDS`;~Sz*e}nyGZWKD~QWL285<$`P?RF90Xx zQhw*zNxa?d6B0Xo|60Fo`1Qmh?CU4MF;Ae4>MYB@JhVBOSU?1``g`o-=1?fD8T59b zq2VNrYJ(w>@`6VuB8wPHC2o-Rv^-V=x`%fY-*@JsDS_Ee|OSmWdo{l4FJ^fR#|1J(Fn%$_O0?4;p9l7J&o0 jVlT{0=wpSWHJKgq0smu!{^j`>0{=qbUkLpF6M_E%6o54C From fa74e58578d9f3455cacb933405f1819820c6ead Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Thu, 11 Apr 2013 11:52:03 -0500 Subject: [PATCH 064/104] Bump version to 1.1.7. --- atomic.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index 6f0531064..ca84e8b3e 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.6" -old_version = "1.1.5" +new_version = "1.1.7" +old_version = "1.1.6" git_lines = `git log --oneline #{old_version}...#{new_version}`.lines.map {|str| "* #{str}"}.join doc_lines = File.readlines("README.rdoc") From 073b4c17c1d3050cd6f5c4622f052a808ba6bd90 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 15 Apr 2013 18:03:14 -0500 Subject: [PATCH 065/104] Partial fix for numeric idempotence differences across Rubies. I have opted to make numerics succeed in CAS if they are == as far as Ruby is concerned. This makes numeric CAS have a bit more overhead, since we do (at least) two additional instanceof and an additional == call, as well as looping until there's no contention for reference equality, but it fits the spirit of what people want better than strict reference equality. See #19. --- .../ext/atomic/AtomicReferenceLibrary.java | 41 ++++++++++++++++- test/test_atomic.rb | 46 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index d1af9eff3..c7f4de580 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -17,6 +17,7 @@ import org.jruby.Ruby; import org.jruby.RubyClass; import org.jruby.RubyModule; +import org.jruby.RubyNumeric; import org.jruby.RubyObject; import org.jruby.anno.JRubyClass; import org.jruby.anno.JRubyMethod; @@ -103,8 +104,15 @@ public IRubyObject set(IRubyObject newValue) { } @JRubyMethod(name = {"compare_and_set", "compare_and_swap"}) - public IRubyObject compare_and_set(ThreadContext context, IRubyObject oldValue, IRubyObject newValue) { - return context.runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, oldValue, newValue)); + public IRubyObject compare_and_set(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { + Ruby runtime = context.runtime; + + if (expectedValue instanceof RubyNumeric) { + // numerics are not always idempotent in Ruby, so we need to do slower logic + return compareAndSetNumeric(context, expectedValue, newValue); + } + + return runtime.newBoolean(UNSAFE.compareAndSwapObject(this, referenceOffset, expectedValue, newValue)); } @JRubyMethod(name = {"get_and_set", "swap"}) @@ -117,6 +125,35 @@ public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) { } } } + + private IRubyObject compareAndSetNumeric(ThreadContext context, IRubyObject expectedValue, IRubyObject newValue) { + Ruby runtime = context.runtime; + + // loop until: + // * reference CAS would succeed for same-valued objects + // * current and expected have different values as determined by #equals + while (true) { + IRubyObject current = reference; + + if (!(current instanceof RubyNumeric)) { + // old value is not numeric, CAS fails + return runtime.getFalse(); + } + + RubyNumeric currentNumber = (RubyNumeric)current; + if (!currentNumber.equals(expectedValue)) { + // current number does not equal expected, fail CAS + return runtime.getFalse(); + } + + // check that current has not changed, or else allow loop to repeat + boolean success = UNSAFE.compareAndSwapObject(this, referenceOffset, current, newValue); + if (success) { + // value is same and did not change in interim...success + return runtime.getTrue(); + } + } + } } public static class JRubyReference8 extends JRubyReference { diff --git a/test/test_atomic.rb b/test/test_atomic.rb index dceb01948..a3cc6039b 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -72,4 +72,50 @@ def test_update_retries atomic.update{|v| tries += 1 ; atomic.value = 1001 ; v + 1} assert_equal 2, tries end + + def test_numeric_cas + atomic = Atomic.new(0) + + # 9-bit idempotent Fixnum (JRuby) + max_8 = 2**256 - 1 + min_8 = -(2**256) + + atomic.set(max_8) + max_8.upto(max_8 + 2) do |i| + assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" + end + + atomic.set(min_8) + min_8.downto(min_8 - 2) do |i| + assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" + end + + # 64-bit idempotent Fixnum (MRI, Rubinius) + max_64 = 2**62 - 1 + min_64 = -(2**62) + + atomic.set(max_64) + max_64.upto(max_64 + 2) do |i| + assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" + end + + atomic.set(min_64) + min_64.downto(min_64 - 2) do |i| + assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" + end + + # 64-bit overflow into Bignum (JRuby) + max_64 = 2**63 - 1 + min_64 = (-2**63) + + atomic.set(max_64) + max_64.upto(max_64 + 2) do |i| + assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" + end + + atomic.set(min_64) + min_64.downto(min_64 - 2) do |i| + assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" + end + end end From 07491450adc01fff158fb6338d3cf31f88544ef3 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 15 Apr 2013 18:07:54 -0500 Subject: [PATCH 066/104] Add pkg/ and *.gem to gitignore. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 84fe4c72c..41d7446a5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ lib/atomic_reference.jar ext/*.bundle ext/*.so ext/*.jar +pkg +*.gem From e59e92bbbc3ac8f91149e3735cf0139ac371049f Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 15 Apr 2013 18:26:28 -0500 Subject: [PATCH 067/104] Add CAS tests for more numeric types. --- test/test_atomic.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/test_atomic.rb b/test/test_atomic.rb index a3cc6039b..7ccf403a0 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -117,5 +117,21 @@ def test_numeric_cas min_64.downto(min_64 - 2) do |i| assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" end + + # non-idempotent Float (JRuby, Rubinius, MRI < 2.0.0 or 32-bit) + atomic.set(1.0 + 0.1) + assert atomic.compare_and_set(1.0 + 0.1, 1.2), "CAS failed for #{1.0 + 0.1} => 1.2" + + # Bignum + atomic.set(2**100) + assert atomic.compare_and_set(2**100, 0), "CAS failed for #{2**100} => 0" + + # Rational + atomic.set("1/3".to_r) + assert atomic.compare_and_set("1/3".to_r, 0), "CAS failed for #{"1/3".to_r} => 0" + + # Complex + atomic.set("1+2i".to_c) + assert atomic.compare_and_set("1+2i".to_c, 0), "CAS failed for #{"1+2i".to_c} => 0" end end From 6c2ce9255039d0baff625168877adc1f0de09e51 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 16 Apr 2013 08:17:24 -0500 Subject: [PATCH 068/104] Fix #21 by moving win32 CFLAGS tweak above other test compiles. Credit to @phasis68 for the patch. --- ext/extconf.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/extconf.rb b/ext/extconf.rb index 00f2bb337..6ea5c0873 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -14,7 +14,12 @@ extension_name = 'atomic_reference' dir_config(extension_name) -try_run(< Date: Tue, 16 Apr 2013 09:16:56 -0500 Subject: [PATCH 069/104] Allow forcing fallback impl. --- lib/atomic.rb | 9 ++++++++- lib/atomic/fallback.rb | 12 +++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/atomic.rb b/lib/atomic.rb index 3f8446986..261941641 100644 --- a/lib/atomic.rb +++ b/lib/atomic.rb @@ -11,8 +11,15 @@ # limitations under the License. begin - ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' + # force fallback impl with FORCE_ATOMIC_FALLBACK=1 + if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK'] + ruby_engine = 'fallback' + else + ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' + end + require "atomic/#{ruby_engine}" rescue LoadError + warn "#{__FILE__}:#{__LINE__}: unsupported Ruby engine `#{RUBY_ENGINE}', using less-efficient Atomic impl" require 'atomic/fallback' end \ No newline at end of file diff --git a/lib/atomic/fallback.rb b/lib/atomic/fallback.rb index 0af058e65..649e4e552 100644 --- a/lib/atomic/fallback.rb +++ b/lib/atomic/fallback.rb @@ -1,4 +1,14 @@ -warn "#{__FILE__}:#{__LINE__}: unsupported Ruby engine `#{RUBY_ENGINE}', using less-efficient Atomic impl" +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. require 'thread' require 'atomic/direct_update' From b6398e5648c8d98bff28a88d724cf506e2073209 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 16 Apr 2013 09:17:42 -0500 Subject: [PATCH 070/104] Add some missing license headers. --- lib/atomic/concurrent_update_error.rb | 12 ++++++++++++ lib/atomic/delegated_update.rb | 12 ++++++++++++ lib/atomic/direct_update.rb | 12 ++++++++++++ lib/atomic/jruby.rb | 12 ++++++++++++ lib/atomic/ruby.rb | 12 ++++++++++++ 5 files changed, 60 insertions(+) diff --git a/lib/atomic/concurrent_update_error.rb b/lib/atomic/concurrent_update_error.rb index 0de4b80de..9d7035a08 100644 --- a/lib/atomic/concurrent_update_error.rb +++ b/lib/atomic/concurrent_update_error.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + class Atomic class ConcurrentUpdateError < ThreadError # frozen pre-allocated backtrace to speed ConcurrentUpdateError diff --git a/lib/atomic/delegated_update.rb b/lib/atomic/delegated_update.rb index 61d05f9d9..f031c4e6b 100644 --- a/lib/atomic/delegated_update.rb +++ b/lib/atomic/delegated_update.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'atomic/concurrent_update_error' # Define update methods that delegate to @ref field diff --git a/lib/atomic/direct_update.rb b/lib/atomic/direct_update.rb index 7e8c19409..d823752a3 100644 --- a/lib/atomic/direct_update.rb +++ b/lib/atomic/direct_update.rb @@ -1,3 +1,15 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'atomic/concurrent_update_error' # Define update methods that use direct paths diff --git a/lib/atomic/jruby.rb b/lib/atomic/jruby.rb index 75c594f9e..9c8b04118 100644 --- a/lib/atomic/jruby.rb +++ b/lib/atomic/jruby.rb @@ -1,2 +1,14 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'atomic_reference' require 'atomic/direct_update' \ No newline at end of file diff --git a/lib/atomic/ruby.rb b/lib/atomic/ruby.rb index 75c594f9e..9c8b04118 100644 --- a/lib/atomic/ruby.rb +++ b/lib/atomic/ruby.rb @@ -1,2 +1,14 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + require 'atomic_reference' require 'atomic/direct_update' \ No newline at end of file From 40eca8e01eae72469442b3de2a89bcc30c985e9c Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 16 Apr 2013 09:18:07 -0500 Subject: [PATCH 071/104] Make test work under 1.8-compat. --- test/test_atomic.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/test_atomic.rb b/test/test_atomic.rb index 7ccf403a0..2a0f37b1d 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -127,11 +127,13 @@ def test_numeric_cas assert atomic.compare_and_set(2**100, 0), "CAS failed for #{2**100} => 0" # Rational - atomic.set("1/3".to_r) - assert atomic.compare_and_set("1/3".to_r, 0), "CAS failed for #{"1/3".to_r} => 0" + require 'rational' unless ''.respond_to? :to_r + atomic.set(Rational(1,3)) + assert atomic.compare_and_set(Rational(1,3), 0), "CAS failed for #{Rational(1,3)} => 0" # Complex - atomic.set("1+2i".to_c) - assert atomic.compare_and_set("1+2i".to_c, 0), "CAS failed for #{"1+2i".to_c} => 0" + require 'complex' unless ''.respond_to? :to_c + atomic.set(Complex(1,2)) + assert atomic.compare_and_set(Complex(1,2), 0), "CAS failed for #{Complex(1,2)} => 0" end end From ed84820891fab3c2e552a2e5c6068758221c7d16 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 16 Apr 2013 09:18:41 -0500 Subject: [PATCH 072/104] Add numeric CAS logic for fallback, MRI, and Rubinius. Note that this impl is pure-Ruby, so MRI and Rubinius will have slower CAS than JRuby. A pure native impl is welcomed. --- lib/atomic/fallback.rb | 3 ++- lib/atomic/numeric_cas_wrapper.rb | 32 +++++++++++++++++++++++++++++++ lib/atomic/rbx.rb | 24 ++++++++++++++++------- lib/atomic/ruby.rb | 3 ++- 4 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 lib/atomic/numeric_cas_wrapper.rb diff --git a/lib/atomic/fallback.rb b/lib/atomic/fallback.rb index 649e4e552..66d9164f8 100644 --- a/lib/atomic/fallback.rb +++ b/lib/atomic/fallback.rb @@ -49,5 +49,6 @@ def compare_and_set(old_value, new_value) end true end - alias compare_and_swap compare_and_set + + require 'atomic/numeric_cas_wrapper' end \ No newline at end of file diff --git a/lib/atomic/numeric_cas_wrapper.rb b/lib/atomic/numeric_cas_wrapper.rb new file mode 100644 index 000000000..919f36297 --- /dev/null +++ b/lib/atomic/numeric_cas_wrapper.rb @@ -0,0 +1,32 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +class Atomic + alias _compare_and_set compare_and_set + def compare_and_set(expected, new) + if expected.kind_of? Numeric + while true + old = get + + return false unless old.kind_of? Numeric + + return false unless old == expected + + result = _compare_and_set(old, new) + return result if result + end + else + _compare_and_set(expected, new) + end + end + alias compare_and_swap compare_and_set +end \ No newline at end of file diff --git a/lib/atomic/rbx.rb b/lib/atomic/rbx.rb index 89e715f66..39cb52c71 100644 --- a/lib/atomic/rbx.rb +++ b/lib/atomic/rbx.rb @@ -1,11 +1,21 @@ -Atomic = Rubinius::AtomicReference +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. -require 'atomic/direct_update' - -# define additional aliases -class Atomic +# extend Rubinius's version adding aliases and numeric logic +class Atomic < Rubinius::AtomicReference alias value get alias value= set - alias compare_and_swap compare_and_set alias swap get_and_set -end \ No newline at end of file +end + +require 'atomic/direct_update' +require 'atomic/numeric_cas_wrapper' diff --git a/lib/atomic/ruby.rb b/lib/atomic/ruby.rb index 9c8b04118..4e8afd198 100644 --- a/lib/atomic/ruby.rb +++ b/lib/atomic/ruby.rb @@ -11,4 +11,5 @@ # limitations under the License. require 'atomic_reference' -require 'atomic/direct_update' \ No newline at end of file +require 'atomic/direct_update' +require 'atomic/numeric_cas_wrapper' \ No newline at end of file From 6869b890930cf75317f2a1e995869e800b2f0344 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 16 Apr 2013 09:23:14 -0500 Subject: [PATCH 073/104] Version 1.1.8. --- atomic.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index ca84e8b3e..9f5ff8569 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,8 +1,8 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.7" -old_version = "1.1.6" +new_version = "1.1.8" +old_version = "1.1.7" git_lines = `git log --oneline #{old_version}...#{new_version}`.lines.map {|str| "* #{str}"}.join doc_lines = File.readlines("README.rdoc") From e8d43f12d33ab8f462d9ffdcb63c3c71a775cc69 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Tue, 16 Apr 2013 09:24:22 -0500 Subject: [PATCH 074/104] Limit gem description to just commit log. --- atomic.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 9f5ff8569..30fc6c7d9 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -12,7 +12,6 @@ description = < Date: Tue, 16 Apr 2013 09:25:35 -0500 Subject: [PATCH 075/104] Add license to gemspec. --- atomic.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/atomic.gemspec b/atomic.gemspec index 30fc6c7d9..b4b2ada63 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -24,6 +24,7 @@ Gem::Specification.new do |s| s.homepage = "http://github.com/headius/ruby-atomic" s.require_paths = ["lib"] s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" + s.licenses = ["Apache-2.0"] s.test_files = Dir["test/test*.rb"] if defined?(JRUBY_VERSION) s.files = Dir['lib/atomic_reference.jar'] From 86f39613c5bd61912ab7004d1ebf898ff8f9f85b Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 6 May 2013 12:43:00 -0500 Subject: [PATCH 076/104] Revert "Convert README to rdoc and try again." This reverts commit 58d3e344259ff0ab5952f34b0700673c113f35e7. Conflicts: README.md atomic.gemspec --- README.rdoc => README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) rename README.rdoc => README.md (93%) diff --git a/README.rdoc b/README.md similarity index 93% rename from README.rdoc rename to README.md index 95d5b9580..af9c5e34b 100644 --- a/README.rdoc +++ b/README.md @@ -1,6 +1,7 @@ -= An atomic reference implementation for JRuby, Rubinius, and MRI. +atomic: An atomic reference implementation for JRuby, Rubinius, and MRI. -== Summary +Summary +======= This library provides: @@ -13,7 +14,8 @@ The Atomic class provides accessors for the contained "value" plus two update me The atomic repository is at http://github.com/headius/ruby-atomic. -== Usage +Usage +===== The simplest way to use "atomic" is to call the "update" or "try_update" methods. @@ -38,6 +40,7 @@ It's also possible to use the regular get/set operations on the Atomic, if you w my_atomic.compare_and_swap(2, 3) # => true, updated to 3 my_atomic.compare_and_swap(2, 3) # => false, current is not 2 -== Building +Building +======== -As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code should still work fine as far back as Java 5. \ No newline at end of file +As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code should still work fine as far back as Java 5. From e9f1430ff65ff7887992aad0294654eaa32fde32 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 6 May 2013 12:43:14 -0500 Subject: [PATCH 077/104] Revert description changes (damn you, RubyGems.org!). Fixes #22 --- atomic.gemspec | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index b4b2ada63..013c093a6 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -1,29 +1,17 @@ # -*- encoding: utf-8 -*- # Update these to get proper version and commit history -new_version = "1.1.8" -old_version = "1.1.7" - -git_lines = `git log --oneline #{old_version}...#{new_version}`.lines.map {|str| "* #{str}"}.join -doc_lines = File.readlines("README.rdoc") -description = < Date: Wed, 26 Jun 2013 11:44:16 -0500 Subject: [PATCH 078/104] Use -march=native on Solaris as well. Fixes #23. --- ext/extconf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/extconf.rb b/ext/extconf.rb index 6ea5c0873..583dd75c1 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -15,7 +15,7 @@ dir_config(extension_name) case CONFIG["arch"] -when /mswin32|mingw/ +when /mswin32|mingw|solaris/ $CFLAGS += " -march=native" end From d1a97cb354b9ce0e07aa4c6153066dda3190dba3 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 26 Jun 2013 11:47:22 -0500 Subject: [PATCH 079/104] Bump version to 1.1.10. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 013c093a6..1a326c54a 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.9" + s.version = "1.1.10" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From ad690f7cc82a655259b370df375072b43e6ddc4e Mon Sep 17 00:00:00 2001 From: Peter Abrahamsen Date: Thu, 11 Jul 2013 15:47:34 -0700 Subject: [PATCH 080/104] Set march appropriately on RHEL5 32bit Fix for issue 24. --- ext/extconf.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/extconf.rb b/ext/extconf.rb index 583dd75c1..b6b1a0546 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -17,6 +17,8 @@ case CONFIG["arch"] when /mswin32|mingw|solaris/ $CFLAGS += " -march=native" +when 'i686-linux' + $CFLAGS += " -march-i686" end try_run(< Date: Sat, 3 Aug 2013 12:10:15 +0800 Subject: [PATCH 081/104] Fix -march-i686 not supported in Ubuntu 12.04 LTS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` root@eric:/usr/local/rvm/gems/ruby-1.9.3-p392/gems/atomic-1.1.11/ext# cat mkmf.log "gcc -o conftest -I/usr/local/rvm/rubies/ruby-1.9.3-p392/include/ruby-1.9.1/i686-linux -I/usr/local/rvm/rubies/ruby-1.9.3-p392/include/ruby-1.9.1/ruby/backward -I/usr/local/rvm/rubies/ruby-1.9.3-p392/include/ruby-1.9.1 -I. -D_FILE_OFFSET_BITS=64 -I/usr/local/rvm/usr/include -O3 -ggdb -Wall -Wextra -Wno-unused-parameter -Wno-parentheses -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith -Wwrite-strings -Wdeclaration-after-statement -Wimplicit-function-declaration -fPIC -march-i686 conftest.c -L. -L/usr/local/rvm/rubies/ruby-1.9.3-p392/lib -Wl,-R/usr/local/rvm/rubies/ruby-1.9.3-p392/lib -L/usr/local/rvm/usr/lib -Wl,-R/usr/local/rvm/usr/lib -L. -rdynamic -Wl,-export-dynamic -L/usr/local/rvm/usr/lib -Wl,-R/usr/local/rvm/usr/lib -Wl,-R -Wl,/usr/local/rvm/rubies/ruby-1.9.3-p392/lib -L/usr/local/rvm/rubies/ruby-1.9.3-p392/lib -lruby -lpthread -lrt -ldl -lcrypt -lm -lc" cc1: error: unrecognized command line option ‘-march-i686’ ``` --- ext/extconf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/extconf.rb b/ext/extconf.rb index b6b1a0546..a1013e3c4 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -18,7 +18,7 @@ when /mswin32|mingw|solaris/ $CFLAGS += " -march=native" when 'i686-linux' - $CFLAGS += " -march-i686" + $CFLAGS += " -march=i686" end try_run(< Date: Fri, 2 Aug 2013 21:45:38 -0500 Subject: [PATCH 082/104] Fix references to removed Unsafe stuff in JRuby and bump to 1.1.11 --- atomic.gemspec | 2 +- ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/atomic.gemspec b/atomic.gemspec index 1a326c54a..d773a0546 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.10" + s.version = "1.1.11" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index c7f4de580..b125844c9 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -25,8 +25,7 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; -import org.jruby.util.unsafe.UnsafeFactory; -import org.jruby.util.unsafe.UnsafeGetter; +import org.jruby.util.unsafe.UnsafeHolder; /** * This library adds an atomic reference type to JRuby for use in the atomic @@ -68,7 +67,7 @@ public static class JRubyReference extends RubyObject { static { try { - UNSAFE = UnsafeGetter.getUnsafe(); + UNSAFE = UnsafeHolder.U; Class k = JRubyReference.class; referenceOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("reference")); } catch (Exception e) { From 74502f15245a46c911a449b4776ba2e67e08e560 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Sat, 3 Aug 2013 01:18:53 -0500 Subject: [PATCH 083/104] Bump to 1.1.12. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index d773a0546..bbb85cf63 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.11" + s.version = "1.1.12" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 6ee28c33433a0682543d8eec60d38da7a2eea996 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 14 Aug 2013 13:47:06 +0200 Subject: [PATCH 084/104] Copy relevant UnsafeHolder logic so it works across all JRubies. No issue filed; see ruby-amqp/hot_bunnies#17. --- .../ext/atomic/AtomicReferenceLibrary.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java index b125844c9..f549d93d0 100644 --- a/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java @@ -12,6 +12,7 @@ package org.jruby.ext.atomic; +import java.lang.reflect.Field; import java.io.IOException; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.jruby.Ruby; @@ -25,7 +26,6 @@ import org.jruby.runtime.ThreadContext; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.runtime.load.Library; -import org.jruby.util.unsafe.UnsafeHolder; /** * This library adds an atomic reference type to JRuby for use in the atomic @@ -154,6 +154,23 @@ private IRubyObject compareAndSetNumeric(ThreadContext context, IRubyObject expe } } } + + private static final class UnsafeHolder { + private UnsafeHolder(){} + + public static final sun.misc.Unsafe U = loadUnsafe(); + + private static sun.misc.Unsafe loadUnsafe() { + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + return (sun.misc.Unsafe) f.get(null); + } catch (Exception e) { + return null; + } + } + } public static class JRubyReference8 extends JRubyReference { public JRubyReference8(Ruby runtime, RubyClass klass) { From ba2cd36f2eac81f1e4fe7b916557509f08757b84 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 14 Aug 2013 13:55:41 +0200 Subject: [PATCH 085/104] Bump version to 1.1.13. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index bbb85cf63..5c55abbc4 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.12" + s.version = "1.1.13" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 07d114594e20ac35444a3791834994ebe2914192 Mon Sep 17 00:00:00 2001 From: "Brett N. DiFrischia" Date: Mon, 9 Sep 2013 14:39:05 -0500 Subject: [PATCH 086/104] Adding Solaris support for atomic operations based on the comment at: https://github.com/headius/ruby-atomic/issues/30#issuecomment-23004627 --- ext/atomic_reference.c | 17 +++++++++++++++++ ext/extconf.rb | 12 +++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 39747c0d8..0e0c0d759 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -11,6 +11,9 @@ // limitations under the License. #include +#if defined(__sun) +#include +#endif static void ir_mark(void *value) { rb_gc_mark_maybe((VALUE) value); @@ -50,6 +53,20 @@ static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE n if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { return Qtrue; } +#elif defined(__sun) +/* Assuming VALUE is uintptr_t */ +/* Based on the definition of uintptr_t from /usr/include/sys/int_types.h */ +#if defined(_LP64) || defined(_I32LPx) + /* 64-bit: uintptr_t === unsigned long */ + if (atomic_cas_ulong((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) { + return Qtrue; + } +#else + /* 32-bit: uintptr_t === unsigned int */ + if (atomic_cas_uint((uintptr_t *) &DATA_PTR(self), expect_value, new_value)) { + return Qtrue; + } +#endif #elif HAVE_GCC_CAS if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; diff --git a/ext/extconf.rb b/ext/extconf.rb index a1013e3c4..7955e5e37 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -14,11 +14,13 @@ extension_name = 'atomic_reference' dir_config(extension_name) -case CONFIG["arch"] -when /mswin32|mingw|solaris/ - $CFLAGS += " -march=native" -when 'i686-linux' - $CFLAGS += " -march=i686" +if CONFIG["GCC"] && CONFIG["GCC"] != "" + case CONFIG["arch"] + when /mswin32|mingw|solaris/ + $CFLAGS += " -march=native" + when 'i686-linux' + $CFLAGS += " -march=i686" + end end try_run(< Date: Tue, 10 Sep 2013 19:26:42 -0500 Subject: [PATCH 087/104] Bump version to 1.1.14. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index 5c55abbc4..a7c8e4540 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.13" + s.version = "1.1.14" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 1945844168031327d4848acad9735ce3af831c18 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Sat, 14 Sep 2013 23:56:53 -0500 Subject: [PATCH 088/104] Format Ruby code --- README.md | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index af9c5e34b..87d2053ef 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,28 @@ The simplest way to use "atomic" is to call the "update" or "try_update" methods "try_update" and "update" both call the given block, passing the current value and using the block's result as the new value. If the value is updated by another thread before the block completes, "try update" raises a ConcurrentUpdateError and "update" retries the block. Because "update" may call the block several times when multiple threads are all updating the same value, the block's logic should be kept as simple as possible. - require 'atomic' - - my_atomic = Atomic.new(0) - my_atomic.update {|v| v + 1} - begin - my_atomic.try_update {|v| v + 1} - rescue Atomic::ConcurrentUpdateError => cue - # deal with it (retry, propagate, etc) - end +```ruby +require 'atomic' + +my_atomic = Atomic.new(0) +my_atomic.update {|v| v + 1} +begin + my_atomic.try_update {|v| v + 1} +rescue Atomic::ConcurrentUpdateError => cue + # deal with it (retry, propagate, etc) +end +``` It's also possible to use the regular get/set operations on the Atomic, if you want to avoid the exception and respond to contended changes in some other way. - my_atomic = Atomic.new(0) - my_atomic.value # => 0 - my_atomic.value = 1 - my_atomic.swap(2) # => 1 - my_atomic.compare_and_swap(2, 3) # => true, updated to 3 - my_atomic.compare_and_swap(2, 3) # => false, current is not 2 +```ruby +my_atomic = Atomic.new(0) +my_atomic.value # => 0 +my_atomic.value = 1 +my_atomic.swap(2) # => 1 +my_atomic.compare_and_swap(2, 3) # => true, updated to 3 +my_atomic.compare_and_swap(2, 3) # => false, current is not 2 +``` Building ======== From f3b2cc6021b5b52277031ff8d3088297208c25ee Mon Sep 17 00:00:00 2001 From: Shannon Skipper Date: Tue, 22 Oct 2013 10:26:16 -0700 Subject: [PATCH 089/104] Fix typo and grammar nits. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 87d2053ef..22ce63ac6 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,8 @@ This library provides: The Atomic class provides accessors for the contained "value" plus two update methods: -* update will run the provided block, passing the current value and replacing it with the block result iff the value has not been changed in the mean time. It may run the block repeatedly if there are other concurrent updates in progress. -* try_update will run the provided block, passing the current value and replacing it with the block result. If the value changes before the update can happen, it will throw Atomic::ConcurrentUpdateError. +* update will run the provided block, passing the current value and replacing it with the block result if the value has not been changed in the meantime. It may run the block repeatedly if there are other concurrent updates in progress. +* try_update will run the provided block, passing the current value and replacing it with the block result. If the value changes before the update can happen, it will throw an Atomic::ConcurrentUpdateError. The atomic repository is at http://github.com/headius/ruby-atomic. From ebc351b705c959d3307b2b1a6c6e31ce07b0b98a Mon Sep 17 00:00:00 2001 From: Sooraj Balakrishnan Date: Thu, 28 Nov 2013 17:13:04 +0530 Subject: [PATCH 090/104] attempt compilation using gcc instead of throwing error --- ext/atomic_reference.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 0e0c0d759..2c81a292a 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -67,12 +67,10 @@ static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE n return Qtrue; } #endif -#elif HAVE_GCC_CAS +#else if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; } -#else -#error No CAS operation available for this platform #endif return Qfalse; } From 9f8896cbdea2782183b097e8ead0f1267d6e49d5 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Sat, 11 Jan 2014 13:10:47 -0800 Subject: [PATCH 091/104] include libkern/OSAtomic if available --- Rakefile | 16 +++++++--------- ext/atomic_reference.c | 4 ++++ ext/extconf.rb | 2 ++ test/test_atomic.rb | 6 +++--- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Rakefile b/Rakefile index 6104eb16c..b6d938668 100644 --- a/Rakefile +++ b/Rakefile @@ -12,6 +12,7 @@ require 'rake' require 'rake/testtask' +require "rake/extensiontask" task :default => :test @@ -50,16 +51,13 @@ if defined?(JRUBY_VERSION) ant.jar :basedir => "pkg/classes", :destfile => "lib/atomic_reference.jar", :includes => "**/*.class" end - task :package => :jar + task :compile => :jar else - task :package do - Dir.chdir("ext") do - # this does essentially the same thing - # as what RubyGems does - ruby "extconf.rb" - sh "make" - end + Rake::ExtensionTask.new "atomic" do |ext| + ext.ext_dir = 'ext' + ext.name ='atomic_reference' end end -task :test => :package +task :package => :compile +task :test => :compile diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 0e0c0d759..9c4008d20 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -15,6 +15,10 @@ #include #endif +#ifdef HAVE_LIBKERN_OSATOMIC_H +#include +#endif + static void ir_mark(void *value) { rb_gc_mark_maybe((VALUE) value); } diff --git a/ext/extconf.rb b/ext/extconf.rb index 7955e5e37..e9e1f5098 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -14,6 +14,8 @@ extension_name = 'atomic_reference' dir_config(extension_name) +have_header "libkern/OSAtomic.h" + if CONFIG["GCC"] && CONFIG["GCC"] != "" case CONFIG["arch"] when /mswin32|mingw|solaris/ diff --git a/test/test_atomic.rb b/test/test_atomic.rb index 2a0f37b1d..79eb315a9 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -10,10 +10,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -require 'test/unit' +require 'minitest/autorun' require 'atomic' -class TestAtomic < Test::Unit::TestCase +class TestAtomic < MiniTest::Test def test_construct atomic = Atomic.new assert_equal nil, atomic.value @@ -58,7 +58,7 @@ def test_swap def test_try_update_fails # use a number outside JRuby's fixnum cache range, to ensure identity is preserved atomic = Atomic.new(1000) - assert_raise Atomic::ConcurrentUpdateError do + assert_raises Atomic::ConcurrentUpdateError do # assigning within block exploits implementation detail for test atomic.try_update{|v| atomic.value = 1001 ; v + 1} end From 3c4861f0eb25de0f1f02f72d785d39182fab8304 Mon Sep 17 00:00:00 2001 From: "U.Nakamura" Date: Wed, 5 Feb 2014 00:06:50 +0900 Subject: [PATCH 092/104] mswin-support * Rakefile: use "nmake" on mswin platform. * ext/atomic_reference.c: mswin's CAS operations. --- Rakefile | 6 +++++- ext/atomic_reference.c | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 6104eb16c..222883cc2 100644 --- a/Rakefile +++ b/Rakefile @@ -57,7 +57,11 @@ else # this does essentially the same thing # as what RubyGems does ruby "extconf.rb" - sh "make" + if /mswin/ =~ RUBY_PLATFORM + sh "nmake" + else + sh "make" + end end end end diff --git a/ext/atomic_reference.c b/ext/atomic_reference.c index 0e0c0d759..9147c56d8 100644 --- a/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -71,6 +71,14 @@ static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE n if (__sync_bool_compare_and_swap(&DATA_PTR(self), expect_value, new_value)) { return Qtrue; } +#elif defined _MSC_VER && defined _M_AMD64 + if (InterlockedCompareExchange64((LONGLONG*)&DATA_PTR(self), new_value, expect_value)) { + return Qtrue; + } +#elif defined _MSC_VER && defined _M_IX86 + if (InterlockedCompareExchange((LONG*)&DATA_PTR(self), new_value, expect_value)) { + return Qtrue; + } #else #error No CAS operation available for this platform #endif From 4f971342d69a9ea1c43d2896abfdc77e3edde645 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 26 Feb 2014 09:45:52 -0600 Subject: [PATCH 093/104] Add Gemfile to get appropriate dependencies installed. --- Gemfile | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Gemfile diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..83d71a7ad --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" + +gem 'rake-compiler' +gem 'minitest', :group => :development From b60856ac370c135a932e33dbd73db3d6169744e5 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 26 Feb 2014 09:46:49 -0600 Subject: [PATCH 094/104] Fix rbx reference in travis build. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a5dfe2303..c5ae59d2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,4 @@ rvm: # Because we need JDK8 to build, these are disabled temporarily # - jruby-18mode # JRuby in 1.8 mode # - jruby-19mode # JRuby in 1.9 mode - - rbx-18mode - - rbx-19mode + - rbx-2 From 53610b70ca85ea74aafd80fa90cd19772647ade1 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 26 Feb 2014 09:50:39 -0600 Subject: [PATCH 095/104] Reenable JRuby builds. --- .travis.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5ae59d2e..315bff925 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,8 @@ rvm: - 2.0.0 - 1.9.3 - 1.8.7 -# Because we need JDK8 to build, these are disabled temporarily -# - jruby-18mode # JRuby in 1.8 mode -# - jruby-19mode # JRuby in 1.9 mode + - jruby-18mode # JRuby in 1.8 mode + - jruby-19mode # JRuby in 1.9 mode - rbx-2 +jdk: + - oraclejdk8 From b7485bb7be7c411cecffc22accba4995546ab213 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 26 Feb 2014 10:55:03 -0600 Subject: [PATCH 096/104] Fix compile task on JRuby. --- Rakefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Rakefile b/Rakefile index b6d938668..a0e109c75 100644 --- a/Rakefile +++ b/Rakefile @@ -12,7 +12,6 @@ require 'rake' require 'rake/testtask' -require "rake/extensiontask" task :default => :test @@ -40,19 +39,20 @@ if defined?(JRUBY_VERSION) end desc "Compile the extension" - task :compile => "pkg/classes" do |t| + task :compile_java => "pkg/classes" do |t| ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, :source => "1.5", :target => "1.5", :debug => true, :classpath => "${java.class.path}:${sun.boot.class.path}" end desc "Build the jar" - task :jar => :compile do + task :jar => :compile_java do ant.jar :basedir => "pkg/classes", :destfile => "lib/atomic_reference.jar", :includes => "**/*.class" end task :compile => :jar else + require "rake/extensiontask" Rake::ExtensionTask.new "atomic" do |ext| ext.ext_dir = 'ext' ext.name ='atomic_reference' From c096362e97b9e314b8ea485dff4435bcfc513b6b Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Wed, 26 Feb 2014 11:48:25 -0600 Subject: [PATCH 097/104] Update version to 1.1.15. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index a7c8e4540..f98f6d815 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.14" + s.version = "1.1.15" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From 4d3040f61f57ada5cbb27fd17384e8669cf8635d Mon Sep 17 00:00:00 2001 From: "Brett N. DiFrischia" Date: Wed, 5 Mar 2014 12:38:13 -0600 Subject: [PATCH 098/104] Allow GCC to be detected via CONFIG["CC"]. --- ext/extconf.rb | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ext/extconf.rb b/ext/extconf.rb index e9e1f5098..03faf6e19 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -16,7 +16,19 @@ have_header "libkern/OSAtomic.h" -if CONFIG["GCC"] && CONFIG["GCC"] != "" +def compiler_is_gcc + if CONFIG["GCC"] && CONFIG["GCC"] != "" + return true + elsif ( # This could stand to be more generic... but I am afraid. + CONFIG["CC"] =~ /\bgcc\b/ + ) + return true + end + return false +end + + +if compiler_is_gcc case CONFIG["arch"] when /mswin32|mingw|solaris/ $CFLAGS += " -march=native" From 3f768985bf17b2d8fc4360eb35f6efb357573ecc Mon Sep 17 00:00:00 2001 From: "Brett N. DiFrischia" Date: Wed, 5 Mar 2014 12:40:20 -0600 Subject: [PATCH 099/104] Ignore vim swap files. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 41d7446a5..5f3f73d5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.*.sw? lib/atomic_reference.jar /nbproject ext/*.bundle From 63107c09afca85df9136050185fdb1968da13bc9 Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 17 Mar 2014 08:00:15 -0500 Subject: [PATCH 100/104] Add travis badge --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 22ce63ac6..6001f9fbb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ atomic: An atomic reference implementation for JRuby, Rubinius, and MRI. +======================================================================== + +[![Build Status](https://travis-ci.org/headius/ruby-atomic.png?branch=master)](https://travis-ci.org/headius/ruby-atomic) Summary ======= From ba672dee7d3dcd85624612b8657bbd4e579ca53c Mon Sep 17 00:00:00 2001 From: Charles Oliver Nutter Date: Mon, 17 Mar 2014 08:08:22 -0500 Subject: [PATCH 101/104] Bump version to 1.1.16. --- atomic.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atomic.gemspec b/atomic.gemspec index f98f6d815..3f65f940e 100644 --- a/atomic.gemspec +++ b/atomic.gemspec @@ -4,7 +4,7 @@ Gem::Specification.new do |s| s.name = %q{atomic} - s.version = "1.1.15" + s.version = "1.1.16" s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] s.date = Time.now.strftime('%Y-%m-%d') s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" From d780eec0ad2c2696385cb01d373b1fd73cadce39 Mon Sep 17 00:00:00 2001 From: Josef Stribny Date: Thu, 10 Apr 2014 11:03:52 +0200 Subject: [PATCH 102/104] Update test suite to Minitest 5 --- Gemfile | 2 +- test/test_atomic.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index 83d71a7ad..55034a9e7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,4 @@ source "https://rubygems.org" gem 'rake-compiler' -gem 'minitest', :group => :development +gem 'minitest', '>= 5.0.0', :group => :development diff --git a/test/test_atomic.rb b/test/test_atomic.rb index 79eb315a9..0e8f62aae 100644 --- a/test/test_atomic.rb +++ b/test/test_atomic.rb @@ -13,7 +13,7 @@ require 'minitest/autorun' require 'atomic' -class TestAtomic < MiniTest::Test +class TestAtomic < Minitest::Test def test_construct atomic = Atomic.new assert_equal nil, atomic.value From 49bbaecdb34c29ea163263bee221bf30ae69eca0 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Fri, 30 May 2014 07:16:26 -0400 Subject: [PATCH 103/104] Merged ruby-atomic gem. --- .gitignore | 12 +- Gemfile | 2 +- Rakefile | 68 ++++++++- concurrent-ruby.gemspec | 7 + examples/atomic_example.rb | 12 ++ .../examples => examples}/bench_atomic.rb | 18 +-- .../examples => examples}/bench_atomic_1.rb | 15 +- .../graph_atomic_bench.rb | 12 -- ext/AtomicReferenceService.java | 12 ++ {ruby-atomic/ext => ext}/atomic_reference.c | 46 ++---- ext/atomic_reference.h | 12 ++ .../ext}/AtomicReferenceLibrary.java | 17 +-- ext/extconf.rb | 45 ++++++ ext/rb_concurrent.c | 29 ++++ lib/concurrent.rb | 2 + lib/concurrent/atomic.rb | 13 ++ lib/concurrent/atomic/atomic.rb | 48 ------ .../concurrent_update_error.rb | 9 ++ .../atomic_reference/delegated_update.rb | 28 ++++ .../atomic_reference/direct_update.rb | 28 ++++ lib/concurrent/atomic_reference/fallback.rb | 45 ++++++ lib/concurrent/atomic_reference/jruby.rb | 2 + .../atomic_reference/numeric_cas_wrapper.rb | 23 +++ lib/concurrent/atomic_reference/rbx.rb | 11 ++ lib/concurrent/atomic_reference/ruby.rb | 3 + lib/concurrent/atomics.rb | 2 +- lib/concurrent_cruby.bundle | Bin 0 -> 10780 bytes lib/extension_helper.rb | 7 + ruby-atomic/.gitignore | 8 - ruby-atomic/.travis.yml | 10 -- ruby-atomic/Gemfile | 4 - ruby-atomic/LICENSE | 144 ------------------ ruby-atomic/README.md | 53 ------- ruby-atomic/Rakefile | 63 -------- ruby-atomic/atomic.gemspec | 24 --- ruby-atomic/examples/atomic_example.rb | 24 --- ruby-atomic/ext/AtomicReferenceService.java | 24 --- ruby-atomic/ext/extconf.rb | 48 ------ ruby-atomic/lib/atomic.rb | 25 --- .../lib/atomic/concurrent_update_error.rb | 18 --- ruby-atomic/lib/atomic/delegated_update.rb | 37 ----- ruby-atomic/lib/atomic/direct_update.rb | 37 ----- ruby-atomic/lib/atomic/fallback.rb | 54 ------- ruby-atomic/lib/atomic/jruby.rb | 14 -- ruby-atomic/lib/atomic/numeric_cas_wrapper.rb | 32 ---- ruby-atomic/lib/atomic/rbx.rb | 21 --- ruby-atomic/lib/atomic/ruby.rb | 15 -- ruby-atomic/test/test_atomic.rb | 139 ----------------- spec/concurrent/atomic/atomic_spec.rb | 133 ---------------- spec/concurrent/atomic_spec.rb | 131 ++++++++++++++++ tasks/metrics.rake | 9 +- 51 files changed, 513 insertions(+), 1082 deletions(-) create mode 100644 examples/atomic_example.rb rename {ruby-atomic/examples => examples}/bench_atomic.rb (74%) rename {ruby-atomic/examples => examples}/bench_atomic_1.rb (80%) rename {ruby-atomic/examples => examples}/graph_atomic_bench.rb (75%) create mode 100644 ext/AtomicReferenceService.java rename {ruby-atomic/ext => ext}/atomic_reference.c (51%) create mode 100644 ext/atomic_reference.h rename {ruby-atomic/ext/org/jruby/ext/atomic => ext/com/concurrent_ruby/ext}/AtomicReferenceLibrary.java (90%) create mode 100644 ext/extconf.rb create mode 100644 ext/rb_concurrent.c create mode 100644 lib/concurrent/atomic.rb delete mode 100644 lib/concurrent/atomic/atomic.rb create mode 100644 lib/concurrent/atomic_reference/concurrent_update_error.rb create mode 100644 lib/concurrent/atomic_reference/delegated_update.rb create mode 100644 lib/concurrent/atomic_reference/direct_update.rb create mode 100644 lib/concurrent/atomic_reference/fallback.rb create mode 100644 lib/concurrent/atomic_reference/jruby.rb create mode 100644 lib/concurrent/atomic_reference/numeric_cas_wrapper.rb create mode 100644 lib/concurrent/atomic_reference/rbx.rb create mode 100644 lib/concurrent/atomic_reference/ruby.rb create mode 100755 lib/concurrent_cruby.bundle create mode 100644 lib/extension_helper.rb delete mode 100644 ruby-atomic/.gitignore delete mode 100644 ruby-atomic/.travis.yml delete mode 100644 ruby-atomic/Gemfile delete mode 100644 ruby-atomic/LICENSE delete mode 100644 ruby-atomic/README.md delete mode 100644 ruby-atomic/Rakefile delete mode 100644 ruby-atomic/atomic.gemspec delete mode 100644 ruby-atomic/examples/atomic_example.rb delete mode 100644 ruby-atomic/ext/AtomicReferenceService.java delete mode 100644 ruby-atomic/ext/extconf.rb delete mode 100644 ruby-atomic/lib/atomic.rb delete mode 100644 ruby-atomic/lib/atomic/concurrent_update_error.rb delete mode 100644 ruby-atomic/lib/atomic/delegated_update.rb delete mode 100644 ruby-atomic/lib/atomic/direct_update.rb delete mode 100644 ruby-atomic/lib/atomic/fallback.rb delete mode 100644 ruby-atomic/lib/atomic/jruby.rb delete mode 100644 ruby-atomic/lib/atomic/numeric_cas_wrapper.rb delete mode 100644 ruby-atomic/lib/atomic/rbx.rb delete mode 100644 ruby-atomic/lib/atomic/ruby.rb delete mode 100644 ruby-atomic/test/test_atomic.rb delete mode 100644 spec/concurrent/atomic/atomic_spec.rb create mode 100644 spec/concurrent/atomic_spec.rb diff --git a/.gitignore b/.gitignore index a291e1f63..9fadacbd5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ Gemfile.lock -tests.txt *.gem .rvmrc .ruby-version @@ -21,9 +20,12 @@ coverage .DS_Store TAGS tmtags -*.swo -*.swp +*.sw? .idea .rbx/* -*.py -*.pyc +lib/*.jar +ext/*.bundle +ext/*.so +ext/*.jar +pkg +*.gem diff --git a/Gemfile b/Gemfile index 4d65462ed..be251a5a7 100644 --- a/Gemfile +++ b/Gemfile @@ -2,12 +2,12 @@ source 'https://rubygems.org' gemspec - group :development do gem 'rake', '~> 10.2.2' gem 'countloc', '~> 0.4.0', platforms: :mri gem 'yard', '~> 0.8.7.4' gem 'inch', '~> 0.4.1', platforms: :mri + gem 'rake-compiler', '~> 0.9.2', platforms: [:mri, :mswin, :mingw] end group :testing do diff --git a/Rakefile b/Rakefile index d15de5f71..99371ee0b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,12 +1,9 @@ -$:.push File.join(File.dirname(__FILE__), 'lib') -$:.push File.join(File.dirname(__FILE__), 'tasks/support') - -require 'rubygems' +require 'rake' require 'bundler/gem_tasks' require 'rspec' require 'rspec/core/rake_task' -require 'concurrent' +require_relative 'lib/extension_helper' Bundler::GemHelper.install_tasks @@ -16,8 +13,67 @@ Dir.glob('tasks/**/*.rake').each do|rakefile| load rakefile end +desc "Run benchmarks" +task :bench do + exec "ruby -Ilib -Iext examples/bench_atomic.rb" +end + +if defined?(JRUBY_VERSION) + require 'ant' + + EXTENSION_NAME = 'concurrent_jruby' + + directory "pkg/classes" + + desc "Clean up build artifacts" + task :clean do + rm_rf "pkg/classes" + rm_rf "lib/#{EXTENSION_NAME}.jar" + end + + desc "Compile the extension" + task :compile_java => "pkg/classes" do |t| + ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, + :source => "1.5", :target => "1.5", :debug => true, + :classpath => "${java.class.path}:${sun.boot.class.path}" + end + + desc "Build the jar" + task :jar => :compile_java do + ant.jar :basedir => "pkg/classes", :destfile => "lib/#{EXTENSION_NAME}.jar", :includes => "**/*.class" + end + + task :compile => :jar + +elsif use_c_extensions? + + EXTENSION_NAME = 'concurrent_cruby' + + require 'rake/extensiontask' + + CLEAN.include Rake::FileList['**/*.so', '**/*.bundle', '**/*.o', '**/mkmf.log', '**/Makefile'] + + spec = Gem::Specification.load('concurrent-ruby.gemspec') + Rake::ExtensionTask.new(EXTENSION_NAME, spec) do |ext| + ext.ext_dir = 'ext' + ext.name = EXTENSION_NAME + ext.source_pattern = "**/*.{h,c,cpp}" + end + + desc 'Clean, compile, and build the extension from scratch' + task :compile_c => [ :clean, :compile ] + + task :irb => [:compile] do + sh "irb -r ./lib/#{EXTENSION_NAME}.bundle -I #{File.join(File.dirname(__FILE__), 'lib')}" + end +end + RSpec::Core::RakeTask.new(:travis_spec) do |t| t.rspec_opts = '--tag ~@not_on_travis' end -task :default => [:travis_spec] +if use_c_extensions? + task :default => [:compile_c, :travis_spec] +else + task :default => [:travis_spec] +end diff --git a/concurrent-ruby.gemspec b/concurrent-ruby.gemspec index 81ea1cc79..97294ea1a 100644 --- a/concurrent-ruby.gemspec +++ b/concurrent-ruby.gemspec @@ -25,5 +25,12 @@ Gem::Specification.new do |s| s.extra_rdoc_files = Dir['README*', 'LICENSE*', 'CHANGELOG*'] s.require_paths = ['lib'] + if defined?(JRUBY_VERSION) + s.files = Dir['lib/concurrent_jruby.jar'] + s.platform = 'java' + else + s.extensions = 'ext/extconf.rb' + end + s.required_ruby_version = '>= 1.9.3' end diff --git a/examples/atomic_example.rb b/examples/atomic_example.rb new file mode 100644 index 000000000..5debe298f --- /dev/null +++ b/examples/atomic_example.rb @@ -0,0 +1,12 @@ +require 'concurrent' + +my_atomic = Concurrent::Atomic.new(0) +my_atomic.update {|v| v + 1} +puts "new value: #{my_atomic.value}" + +begin + my_atomic.try_update {|v| v + 1} +rescue Concurrent::Atomic::ConcurrentUpdateError => cue + # deal with it (retry, propagate, etc) +end +puts "new value: #{my_atomic.value}" diff --git a/ruby-atomic/examples/bench_atomic.rb b/examples/bench_atomic.rb similarity index 74% rename from ruby-atomic/examples/bench_atomic.rb rename to examples/bench_atomic.rb index 09a7b06b2..ec9fccfa4 100644 --- a/ruby-atomic/examples/bench_atomic.rb +++ b/examples/bench_atomic.rb @@ -1,17 +1,5 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - require 'benchmark' -require 'atomic' +require 'concurrent' require 'thread' Thread.abort_on_exception = true @@ -43,7 +31,7 @@ end end - @atom = Atomic.new(0) + @atom = Concurrent::Atomic.new(0) x.report "atomic" do N.times do @atom.update{|x| x += 1} @@ -111,7 +99,7 @@ def para_run(tg) raise unless value == 0 - @atom = Atomic.new(0) + @atom = Concurrent::Atomic.new(0) tg = para_setup(M, N/M) do |diff| @atom.update{|x| x + diff} end diff --git a/ruby-atomic/examples/bench_atomic_1.rb b/examples/bench_atomic_1.rb similarity index 80% rename from ruby-atomic/examples/bench_atomic_1.rb rename to examples/bench_atomic_1.rb index ee5eb1e18..c945e75ea 100644 --- a/ruby-atomic/examples/bench_atomic_1.rb +++ b/examples/bench_atomic_1.rb @@ -1,23 +1,12 @@ #!/usr/bin/env ruby -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. $: << File.expand_path('../../lib', __FILE__) require 'optparse' require 'thread' require 'benchmark' -require 'atomic' +require 'concurrent' Thread.abort_on_exception = true @@ -115,7 +104,7 @@ def para_prepare(&block) $tg = nil if $conf[:lock] == "atomic" - $atom = Atomic.new(0) + $atom = Concurrent::Atomic.new(0) $tg = para_prepare do |diff| $atom.update do |x| slow_down diff --git a/ruby-atomic/examples/graph_atomic_bench.rb b/examples/graph_atomic_bench.rb similarity index 75% rename from ruby-atomic/examples/graph_atomic_bench.rb rename to examples/graph_atomic_bench.rb index d118073a5..abafc6de0 100644 --- a/ruby-atomic/examples/graph_atomic_bench.rb +++ b/examples/graph_atomic_bench.rb @@ -1,17 +1,5 @@ #!/usr/bin/env ruby -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - require 'optparse' conf = { diff --git a/ext/AtomicReferenceService.java b/ext/AtomicReferenceService.java new file mode 100644 index 000000000..649a9f49f --- /dev/null +++ b/ext/AtomicReferenceService.java @@ -0,0 +1,12 @@ +import java.io.IOException; + +import org.jruby.Ruby; +import org.jruby.runtime.load.BasicLibraryService; + +public class AtomicReferenceService implements BasicLibraryService { + public boolean basicLoad(final Ruby runtime) throws IOException { + new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false); + return true; + } +} + diff --git a/ruby-atomic/ext/atomic_reference.c b/ext/atomic_reference.c similarity index 51% rename from ruby-atomic/ext/atomic_reference.c rename to ext/atomic_reference.c index 0a09cc6a1..e87fc2556 100644 --- a/ruby-atomic/ext/atomic_reference.c +++ b/ext/atomic_reference.c @@ -1,15 +1,3 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - #include #if defined(__sun) #include @@ -19,15 +7,17 @@ #include #endif -static void ir_mark(void *value) { +#include "atomic_reference.h" + +void ir_mark(void *value) { rb_gc_mark_maybe((VALUE) value); } -static VALUE ir_alloc(VALUE klass) { +VALUE ir_alloc(VALUE klass) { return rb_data_object_alloc(klass, (void *) Qnil, ir_mark, NULL); } -static VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { +VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { VALUE value = Qnil; if (rb_scan_args(argc, argv, "01", &value) == 1) { value = argv[0]; @@ -36,23 +26,23 @@ static VALUE ir_initialize(int argc, VALUE* argv, VALUE self) { return Qnil; } -static VALUE ir_get(VALUE self) { +VALUE ir_get(VALUE self) { return (VALUE) DATA_PTR(self); } -static VALUE ir_set(VALUE self, VALUE new_value) { +VALUE ir_set(VALUE self, VALUE new_value) { DATA_PTR(self) = (void *) new_value; return new_value; } -static VALUE ir_get_and_set(VALUE self, VALUE new_value) { +VALUE ir_get_and_set(VALUE self, VALUE new_value) { VALUE old_value; old_value = (VALUE) DATA_PTR(self); DATA_PTR(self) = (void *) new_value; return old_value; } -static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) { +VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE new_value) { #if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 if (OSAtomicCompareAndSwap64(expect_value, new_value, &DATA_PTR(self))) { return Qtrue; @@ -86,21 +76,3 @@ static VALUE ir_compare_and_set(volatile VALUE self, VALUE expect_value, VALUE n #endif return Qfalse; } - -void Init_atomic_reference() { - VALUE cAtomic; - - cAtomic = rb_define_class_under(rb_cObject, "Atomic", rb_cObject); - - rb_define_alloc_func(cAtomic, ir_alloc); - - rb_define_method(cAtomic, "initialize", ir_initialize, -1); - rb_define_method(cAtomic, "get", ir_get, 0); - rb_define_method(cAtomic, "value", ir_get, 0); - rb_define_method(cAtomic, "set", ir_set, 1); - rb_define_method(cAtomic, "value=", ir_set, 1); - rb_define_method(cAtomic, "get_and_set", ir_get_and_set, 1); - rb_define_method(cAtomic, "swap", ir_get_and_set, 1); - rb_define_method(cAtomic, "compare_and_set", ir_compare_and_set, 2); - rb_define_method(cAtomic, "compare_and_swap", ir_compare_and_set, 2); -} diff --git a/ext/atomic_reference.h b/ext/atomic_reference.h new file mode 100644 index 000000000..efcb676a3 --- /dev/null +++ b/ext/atomic_reference.h @@ -0,0 +1,12 @@ +#ifndef __ATOMIC_REFERENCE_H__ +#define __ATOMIC_REFERENCE_H__ + +void ir_mark(void*); +VALUE ir_alloc(VALUE); +VALUE ir_initialize(int, VALUE*, VALUE); +VALUE ir_get(VALUE); +VALUE ir_set(VALUE, VALUE); +VALUE ir_get_and_set(VALUE, VALUE); +VALUE ir_compare_and_set(volatile VALUE, VALUE, VALUE); + +#endif diff --git a/ruby-atomic/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java b/ext/com/concurrent_ruby/ext/AtomicReferenceLibrary.java similarity index 90% rename from ruby-atomic/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java rename to ext/com/concurrent_ruby/ext/AtomicReferenceLibrary.java index f549d93d0..2aebb7b98 100644 --- a/ruby-atomic/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +++ b/ext/com/concurrent_ruby/ext/AtomicReferenceLibrary.java @@ -1,16 +1,4 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package org.jruby.ext.atomic; +package com.concurrent_ruby.ext; import java.lang.reflect.Field; import java.io.IOException; @@ -36,7 +24,8 @@ */ public class AtomicReferenceLibrary implements Library { public void load(Ruby runtime, boolean wrap) throws IOException { - RubyClass atomicCls = runtime.defineClass("Atomic", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("Atomic", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); try { sun.misc.Unsafe.class.getMethod("getAndSetObject", Object.class); atomicCls.setAllocator(JRUBYREFERENCE8_ALLOCATOR); diff --git a/ext/extconf.rb b/ext/extconf.rb new file mode 100644 index 000000000..fd16ebe84 --- /dev/null +++ b/ext/extconf.rb @@ -0,0 +1,45 @@ +require_relative '../lib/extension_helper' + +if defined?(JRUBY_VERSION) + puts 'JRuby detected. Pure Java optimizations will be used.' +elsif ! use_c_extensions? + puts 'C optimizations are only supported on MRI 2.0 and above.' +else + + require 'mkmf' + + extension_name = 'concurrent_cruby' + dir_config(extension_name) + + have_header "libkern/OSAtomic.h" + + def compiler_is_gcc + if CONFIG["GCC"] && CONFIG["GCC"] != "" + return true + elsif ( # This could stand to be more generic... but I am afraid. + CONFIG["CC"] =~ /\bgcc\b/ + ) + return true + end + return false + end + + if compiler_is_gcc + case CONFIG["arch"] + when /mswin32|mingw|solaris/ + $CFLAGS += " -march=native" + when 'i686-linux' + $CFLAGS += " -march=i686" + end + end + + try_run(< + +#include "atomic_reference.h" + +// module and class definitions + +static VALUE rb_mConcurrent; +static VALUE rb_cAtomic; + +// Init_concurrent_cruby + +void Init_concurrent_cruby() { + + // define modules and classes + rb_mConcurrent = rb_define_module("Concurrent"); + rb_cAtomic = rb_define_class_under(rb_mConcurrent, "Atomic", rb_cObject); + + // CAtomic + rb_define_alloc_func(rb_cAtomic, ir_alloc); + rb_define_method(rb_cAtomic, "initialize", ir_initialize, -1); + rb_define_method(rb_cAtomic, "get", ir_get, 0); + rb_define_method(rb_cAtomic, "value", ir_get, 0); + rb_define_method(rb_cAtomic, "set", ir_set, 1); + rb_define_method(rb_cAtomic, "value=", ir_set, 1); + rb_define_method(rb_cAtomic, "get_and_set", ir_get_and_set, 1); + rb_define_method(rb_cAtomic, "swap", ir_get_and_set, 1); + rb_define_method(rb_cAtomic, "compare_and_set", ir_compare_and_set, 2); + rb_define_method(rb_cAtomic, "compare_and_swap", ir_compare_and_set, 2); +} diff --git a/lib/concurrent.rb b/lib/concurrent.rb index 15302c436..58c06ff74 100644 --- a/lib/concurrent.rb +++ b/lib/concurrent.rb @@ -1,4 +1,5 @@ require 'concurrent/version' + require 'concurrent/configuration' require 'concurrent/atomics' @@ -8,6 +9,7 @@ require 'concurrent/executors' require 'concurrent/utilities' +require 'concurrent/atomic' require 'concurrent/agent' require 'concurrent/async' require 'concurrent/dataflow' diff --git a/lib/concurrent/atomic.rb b/lib/concurrent/atomic.rb new file mode 100644 index 000000000..0013c68ce --- /dev/null +++ b/lib/concurrent/atomic.rb @@ -0,0 +1,13 @@ +begin + # force fallback impl with FORCE_ATOMIC_FALLBACK=1 + if /[^0fF]/ =~ ENV['FORCE_ATOMIC_FALLBACK'] + ruby_engine = 'fallback' + else + ruby_engine = defined?(RUBY_ENGINE)? RUBY_ENGINE : 'ruby' + end + + require "concurrent/atomic_reference/#{ruby_engine}" +rescue LoadError + warn "#{__FILE__}:#{__LINE__}: unsupported Ruby engine `#{RUBY_ENGINE}', using less-efficient Atomic impl" + require 'concurrent/atomic_reference/fallback' +end diff --git a/lib/concurrent/atomic/atomic.rb b/lib/concurrent/atomic/atomic.rb deleted file mode 100644 index e328da8b8..000000000 --- a/lib/concurrent/atomic/atomic.rb +++ /dev/null @@ -1,48 +0,0 @@ -module Concurrent - - class MutexAtomic - - def initialize(init = nil) - @value = init - @mutex = Mutex.new - end - - def value - @mutex.lock - @value - ensure - @mutex.unlock - end - - def value=(value) - @mutex.lock - @value = value - ensure - @mutex.unlock - end - - def modify - @mutex.lock - result = yield @value - @value = result - ensure - @mutex.unlock - end - - def compare_and_set(expect, update) - @mutex.lock - if @value == expect - @value = update - true - else - false - end - ensure - @mutex.unlock - end - end - - class Atomic < MutexAtomic - end - -end diff --git a/lib/concurrent/atomic_reference/concurrent_update_error.rb b/lib/concurrent/atomic_reference/concurrent_update_error.rb new file mode 100644 index 000000000..c1b22c24e --- /dev/null +++ b/lib/concurrent/atomic_reference/concurrent_update_error.rb @@ -0,0 +1,9 @@ +module Concurrent + + class Atomic + class ConcurrentUpdateError < ThreadError + # frozen pre-allocated backtrace to speed ConcurrentUpdateError + CONC_UP_ERR_BACKTRACE = ['backtrace elided; set verbose to enable'].freeze + end + end +end diff --git a/lib/concurrent/atomic_reference/delegated_update.rb b/lib/concurrent/atomic_reference/delegated_update.rb new file mode 100644 index 000000000..96771c502 --- /dev/null +++ b/lib/concurrent/atomic_reference/delegated_update.rb @@ -0,0 +1,28 @@ +require 'concurrent/atomic_reference/concurrent_update_error' + +module Concurrent + + # Define update methods that delegate to @ref field + class Atomic + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + true until @ref.compare_and_set(old_value = @ref.get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = @ref.get + new_value = yield old_value + unless @ref.compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE + end + end + new_value + end + end +end diff --git a/lib/concurrent/atomic_reference/direct_update.rb b/lib/concurrent/atomic_reference/direct_update.rb new file mode 100644 index 000000000..80408dab2 --- /dev/null +++ b/lib/concurrent/atomic_reference/direct_update.rb @@ -0,0 +1,28 @@ +require 'concurrent/atomic_reference/concurrent_update_error' + +module Concurrent + + # Define update methods that use direct paths + class Atomic + # Pass the current value to the given block, replacing it + # with the block's result. May retry if the value changes + # during the block's execution. + def update + true until compare_and_set(old_value = get, new_value = yield(old_value)) + new_value + end + + def try_update + old_value = get + new_value = yield old_value + unless compare_and_set(old_value, new_value) + if $VERBOSE + raise ConcurrentUpdateError, "Update failed" + else + raise ConcurrentUpdateError, "Update failed", ConcurrentUpdateError::CONC_UP_ERR_BACKTRACE + end + end + new_value + end + end +end diff --git a/lib/concurrent/atomic_reference/fallback.rb b/lib/concurrent/atomic_reference/fallback.rb new file mode 100644 index 000000000..74809566d --- /dev/null +++ b/lib/concurrent/atomic_reference/fallback.rb @@ -0,0 +1,45 @@ +require 'thread' +require 'concurrent/atomic_reference/direct_update' + +module Concurrent + + # Portable/generic (but not very memory or scheduling-efficient) fallback + class Atomic #:nodoc: all + def initialize(value = nil) + @mutex = Mutex.new + @value = value + end + + def get + @mutex.synchronize { @value } + end + alias value get + + def set(new_value) + @mutex.synchronize { @value = new_value } + end + alias value= set + + def get_and_set(new_value) + @mutex.synchronize do + old_value = @value + @value = new_value + old_value + end + end + alias swap get_and_set + + def compare_and_set(old_value, new_value) + return false unless @mutex.try_lock + begin + return false unless @value.equal? old_value + @value = new_value + ensure + @mutex.unlock + end + true + end + + require 'concurrent/atomic_reference/numeric_cas_wrapper' + end +end diff --git a/lib/concurrent/atomic_reference/jruby.rb b/lib/concurrent/atomic_reference/jruby.rb new file mode 100644 index 000000000..095104f7f --- /dev/null +++ b/lib/concurrent/atomic_reference/jruby.rb @@ -0,0 +1,2 @@ +require 'concurrent_jruby' +require 'concurrent/atomic_reference/direct_update' diff --git a/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb b/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb new file mode 100644 index 000000000..f313688df --- /dev/null +++ b/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb @@ -0,0 +1,23 @@ +module Concurrent + + class Atomic + alias _compare_and_set compare_and_set + def compare_and_set(expected, new) + if expected.kind_of? Numeric + while true + old = get + + return false unless old.kind_of? Numeric + + return false unless old == expected + + result = _compare_and_set(old, new) + return result if result + end + else + _compare_and_set(expected, new) + end + end + alias compare_and_swap compare_and_set + end +end diff --git a/lib/concurrent/atomic_reference/rbx.rb b/lib/concurrent/atomic_reference/rbx.rb new file mode 100644 index 000000000..7d0b8dca5 --- /dev/null +++ b/lib/concurrent/atomic_reference/rbx.rb @@ -0,0 +1,11 @@ +module Concurrent + + # extend Rubinius's version adding aliases and numeric logic + class Atomic < Rubinius::AtomicReference + alias value get + alias value= set + alias swap get_and_set + end + + require 'concurrent/atomic_reference/direct_update' + require 'concurrent/atomic_reference/numeric_cas_wrapper' diff --git a/lib/concurrent/atomic_reference/ruby.rb b/lib/concurrent/atomic_reference/ruby.rb new file mode 100644 index 000000000..f62d537ca --- /dev/null +++ b/lib/concurrent/atomic_reference/ruby.rb @@ -0,0 +1,3 @@ +require 'concurrent_cruby' +require 'concurrent/atomic_reference/direct_update' +require 'concurrent/atomic_reference/numeric_cas_wrapper' diff --git a/lib/concurrent/atomics.rb b/lib/concurrent/atomics.rb index 31e11ff0e..b3b0d3985 100644 --- a/lib/concurrent/atomics.rb +++ b/lib/concurrent/atomics.rb @@ -1,4 +1,4 @@ -require 'concurrent/atomic/atomic' +require 'concurrent/atomic' require 'concurrent/atomic/atomic_boolean' require 'concurrent/atomic/atomic_fixnum' require 'concurrent/atomic/condition' diff --git a/lib/concurrent_cruby.bundle b/lib/concurrent_cruby.bundle new file mode 100755 index 0000000000000000000000000000000000000000..babb2f3913466089e5432ad0b1573fb8f96f70ea GIT binary patch literal 10780 zcmeHNTWnOv8J-1)m;&*d2FWxamefR~ExYRkJG7~zb;0RzF5uQsS*6afyFRuT_F~TN zf}OSzl8Ka+>&ogwRHYZ8DymSFNN&Xgl`3SFNH|YW9?}Y-iiajy_a>TFD&>Lg_nnzp zpFOtQR8{(PM*Gjq_uuB9|IF?=J9Dny{qw#1g$S(`LNtTIpgZ>o@iJPLt)Sg&gpl%Z z@8DsV)mYKMTQr7G0XJfumPuK%CrV3-et+?eN_GHau@E<@uBw~F884KwSSqKAb(Y^> z=>a8*YYpO1T^n=N{+8mSKRIS+$886Cet)lPf5)^BVjZgDEQ>E)EIFC{sMh!UYidyf zBR5#9H~I!s%5wg6CO<4Q`H_N)8?VO+?e81ffx*U~zm?J+lOs+tXDf+6z6I^ilm9NhHtjE=ZHT@8INuFg#zx9iacLDV&)=XgKH7Nw zdDk>$ybcyf%IEqHKHGbs&wOViV6td`BH|*kO;3(-d3`-B#F;o%A}XKFX!jB8l86ZL zTlCv@3Nee8--R~N_hI-H+P5DOVi19HuKggE&uL<=_kz561#Bo2u>WKOM}ddXaGZDl z(){Mwx8e_(PXfb}^1BbM@f!-gg{2%4v2xKdh69tu zlAViw$z$fmnk%6mhLgSdH)wCp$_1hF-<<-J<1 zc8T}(j(3I@w?W#nBvP_dFt)((ViEEF3-B-O@BEublEe0<#fcV+#b5zvO~oK zxdk3{ls*QxD&M{Xmv^kGdC2}@F_vFde;8uKXXh_I$cS2c7p%&Hg|RS@E*x*5-qu8Y2>L_Z`ZhtTv4)OJ0Oc6JOt#Nzu% z)YvxmZnDRRqQ&d%G0MdS_Hyi9Vvm1k7ca2)Blg~4?`Q0tLoePT_80Q$vg6qKlISTF za+$Qqbt|6^noPbbGkx{w=BI(D7efT@7c1>Q+zOUQcy1lF0)jbE2AOk@Lf(!&12r>|4Ajm+F zfgl4x27(L(83-~EWZ?guf!3XEgB-IpA)S;=A4(m!(&7OT0fq57`TOAu@Y?;5LHtj>LkAL8ef@ z9Te6K;)AHXnEn!Os)X2rKK&Vtu4^Ch*?TeVk7@fI+TLJe-|w^cV%pDXd-gfL!N%Sj z??EuVm^Sm;z6*WY8;tHpn*TLz|CF{j_@mn2()Nsv;~Q-3xxvXoOdT&CCQ}#xdPqU$ zT@McMO6wuQV|5g6-*bF}|BC)f>)|l?ENmE$!L1135xiPp-p8Qa8{c-wAMnT@1#W?o z884x6Lg(WdjZHpY(AZqx5sgj0PicHi+rO-FT;uO*Jg@Pqz!)C2Dsu`mY`6T=t&TNy!dWNHwY!siRwS;MjGGZ z=ywXd4HaWg9~u~lE&Xoq;m>xglpBvt?CX+Ud-n_{9lTQ2@pv@u(Ne$eG4DVJS4hzzDH2txSy=WGVeVw8JA7k*Wp|wMQmXuO*ZEm7PrkIe z*M|CTURQm{@IGm=zx>(B@$U+b9Z A4*&oF literal 0 HcmV?d00001 diff --git a/lib/extension_helper.rb b/lib/extension_helper.rb new file mode 100644 index 000000000..82e0725c1 --- /dev/null +++ b/lib/extension_helper.rb @@ -0,0 +1,7 @@ +require 'rbconfig' + +def use_c_extensions? + host_os = RbConfig::CONFIG['host_os'] + ruby_name = RbConfig::CONFIG['ruby_install_name'] + (ruby_name =~ /^ruby$/i || host_os =~ /mswin32/i || host_os =~ /mingw32/i) && RUBY_VERSION >= '2.0' +end diff --git a/ruby-atomic/.gitignore b/ruby-atomic/.gitignore deleted file mode 100644 index 5f3f73d5a..000000000 --- a/ruby-atomic/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.*.sw? -lib/atomic_reference.jar -/nbproject -ext/*.bundle -ext/*.so -ext/*.jar -pkg -*.gem diff --git a/ruby-atomic/.travis.yml b/ruby-atomic/.travis.yml deleted file mode 100644 index 315bff925..000000000 --- a/ruby-atomic/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: ruby -rvm: - - 2.0.0 - - 1.9.3 - - 1.8.7 - - jruby-18mode # JRuby in 1.8 mode - - jruby-19mode # JRuby in 1.9 mode - - rbx-2 -jdk: - - oraclejdk8 diff --git a/ruby-atomic/Gemfile b/ruby-atomic/Gemfile deleted file mode 100644 index 55034a9e7..000000000 --- a/ruby-atomic/Gemfile +++ /dev/null @@ -1,4 +0,0 @@ -source "https://rubygems.org" - -gem 'rake-compiler' -gem 'minitest', '>= 5.0.0', :group => :development diff --git a/ruby-atomic/LICENSE b/ruby-atomic/LICENSE deleted file mode 100644 index 533671897..000000000 --- a/ruby-atomic/LICENSE +++ /dev/null @@ -1,144 +0,0 @@ -Apache License - -Version 2.0, January 2004 - -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and distribution as -defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that -is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities that -control, are controlled by, or are under common control with that entity. For the purposes -of this definition, "control" means (i) the power, direct or indirect, to cause the -direction or management of such entity, whether by contract or otherwise, or (ii) ownership -of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of -such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by -this License. - -"Source" form shall mean the preferred form for making modifications, including but not -limited to software source code, documentation source, and configuration files. - -"Object" form shall mean any form resulting from mechanical transformation or translation of -a Source form, including but not limited to compiled object code, generated documentation, -and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made available -under the License, as indicated by a copyright notice that is included in or attached to the -work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that is based on -(or derived from) the Work and for which the editorial revisions, annotations, elaborations, -or other modifications represent, as a whole, an original work of authorship. For the -purposes of this License, Derivative Works shall not include works that remain separable -from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works -thereof. - -"Contribution" shall mean any work of authorship, including the original version of the Work -and any modifications or additions to that Work or Derivative Works thereof, that is -intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by -an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the -purposes of this definition, "submitted" means any form of electronic, verbal, or written -communication sent to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and issue tracking -systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and -improving the Work, but excluding communication that is conspicuously marked or otherwise -designated in writing by the copyright owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a -Contribution has been received by Licensor and subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such Derivative -Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of this License, each -Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, -royalty-free, irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license -applies only to those patent claims licensable by such Contributor that are necessarily -infringed by their Contribution(s) alone or by combination of their Contribution(s) with the -Work to which such Contribution(s) was submitted. If You institute patent litigation against -any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or -a Contribution incorporated within the Work constitutes direct or contributory patent -infringement, then any patent licenses granted to You under this License for that Work shall -terminate as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works -thereof in any medium, with or without modifications, and in Source or Object form, provided -that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of this License; -and - -You must cause any modified files to carry prominent notices stating that You changed the -files; and - -You must retain, in the Source form of any Derivative Works that You distribute, all -copyright, patent, trademark, and attribution notices from the Source form of the Work, -excluding those notices that do not pertain to any part of the Derivative Works; and - -If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative -Works that You distribute must include a readable copy of the attribution notices contained -within such NOTICE file, excluding those notices that do not pertain to any part of the -Derivative Works, in at least one of the following places: within a NOTICE text file -distributed as part of the Derivative Works; within the Source form or documentation, if -provided along with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of the NOTICE -file are for informational purposes only and do not modify the License. You may add Your own -attribution notices within Derivative Works that You distribute, alongside or as an addendum -to the NOTICE text from the Work, provided that such additional attribution notices cannot -be construed as modifying the License. You may add Your own copyright statement to Your -modifications and may provide additional or different license terms and conditions for use, -reproduction, or distribution of Your modifications, or for any such Derivative Works as a -whole, provided Your use, reproduction, and distribution of the Work otherwise complies with -the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution -intentionally submitted for inclusion in the Work by You to the Licensor shall be under the -terms and conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of any -separate license agreement you may have executed with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for reasonable and -customary use in describing the origin of the Work and reproducing the content of the NOTICE -file. - -7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, -Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" -BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, -without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, -MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for -determining the appropriateness of using or redistributing the Work and assume any risks -associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, whether in tort -(including negligence), contract, or otherwise, unless required by applicable law (such as -deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, or -consequential damages of any character arising as a result of this License or out of the use -or inability to use the Work (including but not limited to damages for loss of goodwill, -work stoppage, computer failure or malfunction, or any and all other commercial damages or -losses), even if such Contributor has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative -Works thereof, You may choose to offer, and charge a fee for, acceptance of support, -warranty, indemnity, or other liability obligations and/or rights consistent with this -License. However, in accepting such obligations, You may act only on Your own behalf and on -Your sole responsibility, not on behalf of any other Contributor, and only if You agree to -indemnify, defend, and hold each Contributor harmless for any liability incurred by, or -claims asserted against, such Contributor by reason of your accepting any such warranty or -additional liability. - -END OF TERMS AND CONDITIONS diff --git a/ruby-atomic/README.md b/ruby-atomic/README.md deleted file mode 100644 index 6001f9fbb..000000000 --- a/ruby-atomic/README.md +++ /dev/null @@ -1,53 +0,0 @@ -atomic: An atomic reference implementation for JRuby, Rubinius, and MRI. -======================================================================== - -[![Build Status](https://travis-ci.org/headius/ruby-atomic.png?branch=master)](https://travis-ci.org/headius/ruby-atomic) - -Summary -======= - -This library provides: - -* an Atomic class that guarantees atomic updates to its contained value - -The Atomic class provides accessors for the contained "value" plus two update methods: - -* update will run the provided block, passing the current value and replacing it with the block result if the value has not been changed in the meantime. It may run the block repeatedly if there are other concurrent updates in progress. -* try_update will run the provided block, passing the current value and replacing it with the block result. If the value changes before the update can happen, it will throw an Atomic::ConcurrentUpdateError. - -The atomic repository is at http://github.com/headius/ruby-atomic. - -Usage -===== - -The simplest way to use "atomic" is to call the "update" or "try_update" methods. - -"try_update" and "update" both call the given block, passing the current value and using the block's result as the new value. If the value is updated by another thread before the block completes, "try update" raises a ConcurrentUpdateError and "update" retries the block. Because "update" may call the block several times when multiple threads are all updating the same value, the block's logic should be kept as simple as possible. - -```ruby -require 'atomic' - -my_atomic = Atomic.new(0) -my_atomic.update {|v| v + 1} -begin - my_atomic.try_update {|v| v + 1} -rescue Atomic::ConcurrentUpdateError => cue - # deal with it (retry, propagate, etc) -end -``` - -It's also possible to use the regular get/set operations on the Atomic, if you want to avoid the exception and respond to contended changes in some other way. - -```ruby -my_atomic = Atomic.new(0) -my_atomic.value # => 0 -my_atomic.value = 1 -my_atomic.swap(2) # => 1 -my_atomic.compare_and_swap(2, 3) # => true, updated to 3 -my_atomic.compare_and_swap(2, 3) # => false, current is not 2 -``` - -Building -======== - -As of 1.1.0, JDK8 is required to build the atomic gem, since it attempts to use the new atomic Unsafe.getAndSetObject method only in JDK8. The resulting code should still work fine as far back as Java 5. diff --git a/ruby-atomic/Rakefile b/ruby-atomic/Rakefile deleted file mode 100644 index a0e109c75..000000000 --- a/ruby-atomic/Rakefile +++ /dev/null @@ -1,63 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http:#www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -require 'rake' -require 'rake/testtask' - -task :default => :test - -desc "Run tests" -Rake::TestTask.new :test do |t| - t.libs << "lib" - t.libs << "ext" - t.test_files = FileList["test/**/*.rb"] -end - -desc "Run benchmarks" -task :bench do - exec "ruby -Ilib -Iext test/bench_atomic.rb" -end - -if defined?(JRUBY_VERSION) - require 'ant' - - directory "pkg/classes" - - desc "Clean up build artifacts" - task :clean do - rm_rf "pkg/classes" - rm_rf "lib/refqueue.jar" - end - - desc "Compile the extension" - task :compile_java => "pkg/classes" do |t| - ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, - :source => "1.5", :target => "1.5", :debug => true, - :classpath => "${java.class.path}:${sun.boot.class.path}" - end - - desc "Build the jar" - task :jar => :compile_java do - ant.jar :basedir => "pkg/classes", :destfile => "lib/atomic_reference.jar", :includes => "**/*.class" - end - - task :compile => :jar -else - require "rake/extensiontask" - Rake::ExtensionTask.new "atomic" do |ext| - ext.ext_dir = 'ext' - ext.name ='atomic_reference' - end -end - -task :package => :compile -task :test => :compile diff --git a/ruby-atomic/atomic.gemspec b/ruby-atomic/atomic.gemspec deleted file mode 100644 index 3f65f940e..000000000 --- a/ruby-atomic/atomic.gemspec +++ /dev/null @@ -1,24 +0,0 @@ -# -*- encoding: utf-8 -*- - -# Update these to get proper version and commit history - -Gem::Specification.new do |s| - s.name = %q{atomic} - s.version = "1.1.16" - s.authors = ["Charles Oliver Nutter", "MenTaLguY", "Sokolov Yura"] - s.date = Time.now.strftime('%Y-%m-%d') - s.summary = "An atomic reference implementation for JRuby, Rubinius, and MRI" - s.description = s.summary - s.email = ["headius@headius.com", "mental@rydia.net", "funny.falcon@gmail.com"] - s.homepage = "http://github.com/headius/ruby-atomic" - s.require_paths = ["lib"] - s.licenses = ["Apache-2.0"] - s.test_files = Dir["test/test*.rb"] - if defined?(JRUBY_VERSION) - s.files = Dir['lib/atomic_reference.jar'] - s.platform = 'java' - else - s.extensions = 'ext/extconf.rb' - end - s.files += `git ls-files`.lines.map(&:chomp) -end diff --git a/ruby-atomic/examples/atomic_example.rb b/ruby-atomic/examples/atomic_example.rb deleted file mode 100644 index 115cd862c..000000000 --- a/ruby-atomic/examples/atomic_example.rb +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -require 'atomic' - -my_atomic = Atomic.new(0) -my_atomic.update {|v| v + 1} -puts "new value: #{my_atomic.value}" - -begin - my_atomic.try_update {|v| v + 1} -rescue Atomic::ConcurrentUpdateError => cue - # deal with it (retry, propagate, etc) -end -puts "new value: #{my_atomic.value}" diff --git a/ruby-atomic/ext/AtomicReferenceService.java b/ruby-atomic/ext/AtomicReferenceService.java deleted file mode 100644 index 8ecd08776..000000000 --- a/ruby-atomic/ext/AtomicReferenceService.java +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -import java.io.IOException; - -import org.jruby.Ruby; -import org.jruby.runtime.load.BasicLibraryService; - -public class AtomicReferenceService implements BasicLibraryService { - public boolean basicLoad(final Ruby runtime) throws IOException { - new org.jruby.ext.atomic.AtomicReferenceLibrary().load(runtime, false); - return true; - } -} - diff --git a/ruby-atomic/ext/extconf.rb b/ruby-atomic/ext/extconf.rb deleted file mode 100644 index 03faf6e19..000000000 --- a/ruby-atomic/ext/extconf.rb +++ /dev/null @@ -1,48 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -require 'mkmf' -extension_name = 'atomic_reference' -dir_config(extension_name) - -have_header "libkern/OSAtomic.h" - -def compiler_is_gcc - if CONFIG["GCC"] && CONFIG["GCC"] != "" - return true - elsif ( # This could stand to be more generic... but I am afraid. - CONFIG["CC"] =~ /\bgcc\b/ - ) - return true - end - return false -end - - -if compiler_is_gcc - case CONFIG["arch"] - when /mswin32|mingw|solaris/ - $CFLAGS += " -march=native" - when 'i686-linux' - $CFLAGS += " -march=i686" - end -end - -try_run(< #{i + 1}" - end - - atomic.set(min_8) - min_8.downto(min_8 - 2) do |i| - assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" - end - - # 64-bit idempotent Fixnum (MRI, Rubinius) - max_64 = 2**62 - 1 - min_64 = -(2**62) - - atomic.set(max_64) - max_64.upto(max_64 + 2) do |i| - assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" - end - - atomic.set(min_64) - min_64.downto(min_64 - 2) do |i| - assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" - end - - # 64-bit overflow into Bignum (JRuby) - max_64 = 2**63 - 1 - min_64 = (-2**63) - - atomic.set(max_64) - max_64.upto(max_64 + 2) do |i| - assert atomic.compare_and_swap(i, i+1), "CAS failed for numeric #{i} => #{i + 1}" - end - - atomic.set(min_64) - min_64.downto(min_64 - 2) do |i| - assert atomic.compare_and_swap(i, i-1), "CAS failed for numeric #{i} => #{i - 1}" - end - - # non-idempotent Float (JRuby, Rubinius, MRI < 2.0.0 or 32-bit) - atomic.set(1.0 + 0.1) - assert atomic.compare_and_set(1.0 + 0.1, 1.2), "CAS failed for #{1.0 + 0.1} => 1.2" - - # Bignum - atomic.set(2**100) - assert atomic.compare_and_set(2**100, 0), "CAS failed for #{2**100} => 0" - - # Rational - require 'rational' unless ''.respond_to? :to_r - atomic.set(Rational(1,3)) - assert atomic.compare_and_set(Rational(1,3), 0), "CAS failed for #{Rational(1,3)} => 0" - - # Complex - require 'complex' unless ''.respond_to? :to_c - atomic.set(Complex(1,2)) - assert atomic.compare_and_set(Complex(1,2), 0), "CAS failed for #{Complex(1,2)} => 0" - end -end diff --git a/spec/concurrent/atomic/atomic_spec.rb b/spec/concurrent/atomic/atomic_spec.rb deleted file mode 100644 index a22062a15..000000000 --- a/spec/concurrent/atomic/atomic_spec.rb +++ /dev/null @@ -1,133 +0,0 @@ -require 'spec_helper' - -share_examples_for :atomic do - - context 'construction' do - - it 'sets the initial value' do - described_class.new(:foo).value.should eq :foo - end - - it 'defaults the initial value to nil' do - described_class.new.value.should eq nil - end - end - - context '#value' do - - it 'returns the current value' do - counter = described_class.new(:foo) - counter.value.should eq :foo - end - end - - context '#value=' do - - it 'sets the #value to the given object' do - atomic = described_class.new(:foo) - atomic.value = :bar - atomic.value.should eq :bar - end - - it 'returns the new value' do - atomic = described_class.new(:foo) - (atomic.value = :bar).should eq :bar - end - end - - context '#modify' do - - it 'yields the current value' do - atomic = described_class.new(:foo) - current = [] - atomic.modify { |value| current << value } - current.should eq [:foo] - end - - it 'stores the value returned from the yield' do - atomic = described_class.new(:foo) - atomic.modify { |value| :bar } - atomic.value.should eq :bar - end - - it 'returns the new value' do - atomic = described_class.new(:foo) - atomic.modify{ |value| :bar }.should eq :bar - end - end - - context '#compare_and_set' do - - it 'returns false if the value is not found' do - described_class.new(:foo).compare_and_set(:bar, :foo).should eq false - end - - it 'returns true if the value is found' do - described_class.new(:foo).compare_and_set(:foo, :bar).should eq true - end - - it 'sets if the value is found' do - f = described_class.new(:foo) - f.compare_and_set(:foo, :bar) - f.value.should eq :bar - end - - it 'does not set if the value is not found' do - f = described_class.new(:foo) - f.compare_and_set(:bar, :baz) - f.value.should eq :foo - end - end -end - -module Concurrent - - describe MutexAtomic do - - it_should_behave_like :atomic - - specify 'construction is synchronized' do - mutex = double('mutex') - Mutex.should_receive(:new).once.with(no_args).and_return(mutex) - described_class.new - end - - specify 'value is synchronized' do - mutex = double('mutex') - Mutex.stub(:new).with(no_args).and_return(mutex) - mutex.should_receive(:lock) - mutex.should_receive(:unlock) - described_class.new.value - end - - specify 'value= is synchronized' do - mutex = double('mutex') - Mutex.stub(:new).with(no_args).and_return(mutex) - mutex.should_receive(:lock) - mutex.should_receive(:unlock) - described_class.new.value = 10 - end - - specify 'modify is synchronized' do - mutex = double('mutex') - Mutex.stub(:new).with(no_args).and_return(mutex) - mutex.should_receive(:lock) - mutex.should_receive(:unlock) - described_class.new(:foo).modify { |value| value } - end - - specify 'compare_and_set is synchronized' do - mutex = double('mutex') - Mutex.stub(:new).with(no_args).and_return(mutex) - mutex.should_receive(:lock) - mutex.should_receive(:unlock) - described_class.new(14).compare_and_set(14, 2) - end - end - - describe Atomic do - it 'inherits from MutexAtomic' do - Atomic.ancestors.should include(MutexAtomic) - end - end -end diff --git a/spec/concurrent/atomic_spec.rb b/spec/concurrent/atomic_spec.rb new file mode 100644 index 000000000..6de0ff4af --- /dev/null +++ b/spec/concurrent/atomic_spec.rb @@ -0,0 +1,131 @@ +require 'spec_helper' + +module Concurrent + + describe Atomic do + + specify :test_construct do + atomic = Atomic.new + atomic.value.should be_nil + + atomic = Atomic.new(0) + atomic.value.should eq 0 + end + + specify :test_value do + atomic = Atomic.new(0) + atomic.value = 1 + + atomic.value.should eq 1 + end + + specify :test_update do + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) + res = atomic.update {|v| v + 1} + + atomic.value.should eq 1001 + res.should eq 1001 + end + + specify :test_try_update do + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) + res = atomic.try_update {|v| v + 1} + + atomic.value.should eq 1001 + res.should eq 1001 + end + + specify :test_swap do + atomic = Atomic.new(1000) + res = atomic.swap(1001) + + atomic.value.should eq 1001 + res.should eq 1000 + end + + specify :test_try_update_fails do + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) + expect { + # assigning within block exploits implementation detail for test + atomic.try_update{|v| atomic.value = 1001 ; v + 1} + }.to raise_error(Concurrent::Atomic::ConcurrentUpdateError) + end + + specify :test_update_retries do + tries = 0 + # use a number outside JRuby's fixnum cache range, to ensure identity is preserved + atomic = Atomic.new(1000) + # assigning within block exploits implementation detail for test + atomic.update{|v| tries += 1 ; atomic.value = 1001 ; v + 1} + + tries.should eq 2 + end + + specify :test_numeric_cas do + atomic = Atomic.new(0) + + # 9-bit idempotent Fixnum (JRuby) + max_8 = 2**256 - 1 + min_8 = -(2**256) + + atomic.set(max_8) + max_8.upto(max_8 + 2) do |i| + atomic.compare_and_swap(i, i+1).should be_true, "CAS failed for numeric #{i} => #{i + 1}" + end + + atomic.set(min_8) + min_8.downto(min_8 - 2) do |i| + atomic.compare_and_swap(i, i-1).should be_true, "CAS failed for numeric #{i} => #{i - 1}" + end + + # 64-bit idempotent Fixnum (MRI, Rubinius) + max_64 = 2**62 - 1 + min_64 = -(2**62) + + atomic.set(max_64) + max_64.upto(max_64 + 2) do |i| + atomic.compare_and_swap(i, i+1).should be_true, "CAS failed for numeric #{i} => #{i + 1}" + end + + atomic.set(min_64) + min_64.downto(min_64 - 2) do |i| + atomic.compare_and_swap(i, i-1).should be_true, "CAS failed for numeric #{i} => #{i - 1}" + end + + ## 64-bit overflow into Bignum (JRuby) + max_64 = 2**63 - 1 + min_64 = (-2**63) + + atomic.set(max_64) + max_64.upto(max_64 + 2) do |i| + atomic.compare_and_swap(i, i+1).should be_true, "CAS failed for numeric #{i} => #{i + 1}" + end + + atomic.set(min_64) + min_64.downto(min_64 - 2) do |i| + atomic.compare_and_swap(i, i-1).should be_true, "CAS failed for numeric #{i} => #{i - 1}" + end + + # non-idempotent Float (JRuby, Rubinius, MRI < 2.0.0 or 32-bit) + atomic.set(1.0 + 0.1) + atomic.compare_and_set(1.0 + 0.1, 1.2).should be_true, "CAS failed for #{1.0 + 0.1} => 1.2" + + # Bignum + atomic.set(2**100) + atomic.compare_and_set(2**100, 0).should be_true, "CAS failed for #{2**100} => 0" + + # Rational + require 'rational' unless ''.respond_to? :to_r + atomic.set(Rational(1,3)) + atomic.compare_and_set(Rational(1,3), 0).should be_true, "CAS failed for #{Rational(1,3)} => 0" + + # Complex + require 'complex' unless ''.respond_to? :to_c + atomic.set(Complex(1,2)) + atomic.compare_and_set(Complex(1,2), 0).should be_true, "CAS failed for #{Complex(1,2)} => 0" + end + end +end diff --git a/tasks/metrics.rake b/tasks/metrics.rake index 661d06ba6..dfa81d4bd 100644 --- a/tasks/metrics.rake +++ b/tasks/metrics.rake @@ -1,4 +1,7 @@ -desc 'Display LOC (lines of code) report' -task :loc do - puts `countloc -r lib` +unless defined?(JRUBY_VERSION) + + desc 'Display LOC (lines of code) report' + task :loc do + puts `countloc -r lib` + end end From 4f84b08c8825e3669967b85e4ba9ee9310976e87 Mon Sep 17 00:00:00 2001 From: Jerry D'Antonio Date: Fri, 30 May 2014 07:27:22 -0400 Subject: [PATCH 104/104] Fixed Rubinius bug --- lib/concurrent/atomic_reference/rbx.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/concurrent/atomic_reference/rbx.rb b/lib/concurrent/atomic_reference/rbx.rb index 7d0b8dca5..c90ec45cb 100644 --- a/lib/concurrent/atomic_reference/rbx.rb +++ b/lib/concurrent/atomic_reference/rbx.rb @@ -9,3 +9,4 @@ class Atomic < Rubinius::AtomicReference require 'concurrent/atomic_reference/direct_update' require 'concurrent/atomic_reference/numeric_cas_wrapper' +end