diff --git a/ext/ConcurrentRubyExtService.java b/ext/ConcurrentRubyExtService.java index 1dd929b10..eed602147 100644 --- a/ext/ConcurrentRubyExtService.java +++ b/ext/ConcurrentRubyExtService.java @@ -1,11 +1,13 @@ import java.io.IOException; - + import org.jruby.Ruby; import org.jruby.runtime.load.BasicLibraryService; public class ConcurrentRubyExtService implements BasicLibraryService { public boolean basicLoad(final Ruby runtime) throws IOException { new com.concurrent_ruby.ext.AtomicReferenceLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaAtomicBooleanLibrary().load(runtime, false); + new com.concurrent_ruby.ext.JavaAtomicFixnumLibrary().load(runtime, false); return true; } } diff --git a/ext/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java b/ext/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java new file mode 100644 index 000000000..90ee5189c --- /dev/null +++ b/ext/com/concurrent_ruby/ext/JavaAtomicBooleanLibrary.java @@ -0,0 +1,96 @@ +package com.concurrent_ruby.ext; + +import java.io.IOException; +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.builtin.IRubyObject; +import org.jruby.runtime.load.Library; +import java.util.concurrent.atomic.AtomicBoolean; +import org.jruby.RubyBoolean; +import org.jruby.RubyNil; +import org.jruby.runtime.ThreadContext; + +public class JavaAtomicBooleanLibrary implements Library { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicBoolean", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + atomicCls.defineAnnotatedMethods(JavaAtomicBoolean.class); + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaAtomicBoolean(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaAtomicBoolean", parent = "Object") + public static class JavaAtomicBoolean extends RubyObject { + + private AtomicBoolean atomicBoolean; + private ThreadContext context; + + public JavaAtomicBoolean(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + atomicBoolean = new AtomicBoolean(convertRubyBooleanToJavaBoolean(value)); + this.context = context; + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + atomicBoolean = new AtomicBoolean(); + this.context = context; + return context.nil; + } + + @JRubyMethod(name = "value") + public IRubyObject value() { + return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.get()); + } + + @JRubyMethod(name = "true?") + public IRubyObject isAtomicTrue() { + return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.get()); + } + + @JRubyMethod(name = "false?") + public IRubyObject isAtomicFalse() { + return RubyBoolean.newBoolean(getRuntime(), (atomicBoolean.get() == false)); + } + + @JRubyMethod(name = "value=") + public IRubyObject setAtomic(IRubyObject newValue) { + atomicBoolean.set(convertRubyBooleanToJavaBoolean(newValue)); + return context.nil; + } + + @JRubyMethod(name = "make_true") + public IRubyObject makeTrue() { + return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.compareAndSet(false, true)); + } + + @JRubyMethod(name = "make_false") + public IRubyObject makeFalse() { + return RubyBoolean.newBoolean(getRuntime(), atomicBoolean.compareAndSet(true, false)); + } + + private boolean convertRubyBooleanToJavaBoolean(IRubyObject newValue) { + if (newValue instanceof RubyBoolean.False || newValue instanceof RubyNil) { + return false; + } else { + return true; + } + } + } +} + diff --git a/ext/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java b/ext/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java new file mode 100755 index 000000000..7fc89beee --- /dev/null +++ b/ext/com/concurrent_ruby/ext/JavaAtomicFixnumLibrary.java @@ -0,0 +1,94 @@ +package com.concurrent_ruby.ext; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicLong; +import org.jruby.Ruby; +import org.jruby.RubyBoolean; +import org.jruby.RubyClass; +import org.jruby.RubyFixnum; +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; + +public class JavaAtomicFixnumLibrary implements Library { + + public void load(Ruby runtime, boolean wrap) throws IOException { + RubyModule concurrentMod = runtime.defineModule("Concurrent"); + RubyClass atomicCls = concurrentMod.defineClassUnder("JavaAtomicFixnum", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR); + + atomicCls.defineAnnotatedMethods(JavaAtomicFixnum.class); + + } + + private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() { + public IRubyObject allocate(Ruby runtime, RubyClass klazz) { + return new JavaAtomicFixnum(runtime, klazz); + } + }; + + @JRubyClass(name = "JavaAtomicFixnum", parent = "Object") + public static class JavaAtomicFixnum extends RubyObject { + + private AtomicLong atomicLong; + private ThreadContext context; + + public JavaAtomicFixnum(Ruby runtime, RubyClass metaClass) { + super(runtime, metaClass); + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context) { + this.atomicLong = new AtomicLong(0); + this.context = context; + return context.nil; + } + + @JRubyMethod + public IRubyObject initialize(ThreadContext context, IRubyObject value) { + this.atomicLong = new AtomicLong(rubyFixnumToLong(value)); + this.context = context; + return context.nil; + } + + @JRubyMethod(name = "value") + public IRubyObject getValue() { + return new RubyFixnum(getRuntime(), atomicLong.get()); + } + + @JRubyMethod(name = "value=") + public IRubyObject setValue(IRubyObject newValue) { + atomicLong.set(rubyFixnumToLong(newValue)); + return context.nil; + } + + @JRubyMethod(name = {"increment", "up"}) + public IRubyObject increment() { + return new RubyFixnum(getRuntime(), atomicLong.incrementAndGet()); + } + + @JRubyMethod(name = {"decrement", "down"}) + public IRubyObject decrement() { + return new RubyFixnum(getRuntime(), atomicLong.decrementAndGet()); + } + + @JRubyMethod(name = "compare_and_set") + public IRubyObject compareAndSet(IRubyObject expect, IRubyObject update) { + return RubyBoolean.newBoolean(getRuntime(), atomicLong.compareAndSet(rubyFixnumToLong(expect), rubyFixnumToLong(update))); + } + + private long rubyFixnumToLong(IRubyObject value) { + if (value instanceof RubyFixnum) { + RubyFixnum fixNum = (RubyFixnum) value; + return fixNum.getLongValue(); + } else { + throw getRuntime().newArgumentError("initial value must be a Fixnum"); + } + } + } +} + diff --git a/lib/concurrent/atomic/atomic_boolean.rb b/lib/concurrent/atomic/atomic_boolean.rb index 7bcdfe6e4..3bca953d7 100644 --- a/lib/concurrent/atomic/atomic_boolean.rb +++ b/lib/concurrent/atomic/atomic_boolean.rb @@ -115,49 +115,6 @@ def make_false if RUBY_PLATFORM == 'java' - # @!macro atomic_boolean - class JavaAtomicBoolean - - # @!macro atomic_boolean_method_initialize - # - def initialize(initial = false) - @atomic = java.util.concurrent.atomic.AtomicBoolean.new(!!initial) - end - - # @!macro atomic_boolean_method_value_get - # - def value - @atomic.get - end - - # @!macro atomic_boolean_method_value_set - # - def value=(value) - @atomic.set(!!value) - end - - # @!macro atomic_boolean_method_true_question - def true? - @atomic.get - end - - # @!macro atomic_boolean_method_false_question - def false? - !@atomic.get - end - - # @!macro atomic_boolean_method_make_true - def make_true - @atomic.compareAndSet(false, true) - end - - # @!macro atomic_boolean_method_make_false - def make_false - @atomic.compareAndSet(true, false) - end - end - - # @!macro atomic_boolean class AtomicBoolean < JavaAtomicBoolean end diff --git a/lib/concurrent/atomic/atomic_fixnum.rb b/lib/concurrent/atomic/atomic_fixnum.rb index 87e474e8e..f6968b751 100644 --- a/lib/concurrent/atomic/atomic_fixnum.rb +++ b/lib/concurrent/atomic/atomic_fixnum.rb @@ -97,14 +97,14 @@ def decrement alias_method :down, :decrement # @!macro [attach] atomic_fixnum_method_compare_and_set - # + # # Atomically sets the value to the given updated value if the current # value == the expected value. # # @param [Fixnum] expect the expected value # @param [Fixnum] update the new value # - # @return [Boolean] true if the value was updated else false + # @return [Boolean] true if the value was updated else false def compare_and_set(expect, update) @mutex.lock if @value == expect @@ -120,47 +120,6 @@ def compare_and_set(expect, update) if RUBY_PLATFORM == 'java' - # @!macro atomic_fixnum - class JavaAtomicFixnum - - MIN_VALUE = Java::JavaLang::Long::MIN_VALUE - MAX_VALUE = Java::JavaLang::Long::MAX_VALUE - - # @!macro atomic_fixnum_method_initialize - def initialize(init = 0) - raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum) - @atomic = java.util.concurrent.atomic.AtomicLong.new(init) - end - - # @!macro atomic_fixnum_method_value_get - def value - @atomic.get - end - - # @!macro atomic_fixnum_method_value_set - def value=(value) - raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum) - @atomic.set(value) - end - - # @!macro atomic_fixnum_method_increment - def increment - @atomic.increment_and_get - end - alias_method :up, :increment - - # @!macro atomic_fixnum_method_decrement - def decrement - @atomic.decrement_and_get - end - alias_method :down, :decrement - - # @!macro atomic_fixnum_method_compare_and_set - def compare_and_set(expect, update) - @atomic.compare_and_set(expect, update) - end - end - # @!macro atomic_fixnum class AtomicFixnum < JavaAtomicFixnum end