atomic 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -8,3 +8,29 @@ Rake::TestTask.new :test do |t|
8
8
  t.libs << "lib"
9
9
  t.test_files = FileList["test/**/*.rb"]
10
10
  end
11
+
12
+ if defined?(JRUBY_VERSION)
13
+ require 'ant'
14
+
15
+ directory "pkg/classes"
16
+
17
+ desc "Clean up build artifacts"
18
+ task :clean do
19
+ rm_rf "pkg/classes"
20
+ rm_rf "lib/refqueue.jar"
21
+ end
22
+
23
+ desc "Compile the extension"
24
+ task :compile => "pkg/classes" do |t|
25
+ ant.javac :srcdir => "ext", :destdir => t.prerequisites.first,
26
+ :source => "1.5", :target => "1.5", :debug => true,
27
+ :classpath => "${java.class.path}:${sun.boot.class.path}"
28
+ end
29
+
30
+ desc "Build the jar"
31
+ task :jar => :compile do
32
+ ant.jar :basedir => "pkg/classes", :destfile => "lib/atomic_reference.jar", :includes => "**/*.class"
33
+ end
34
+
35
+ task :package => :jar
36
+ end
data/atomic.gemspec CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{atomic}
5
- s.version = "0.0.2"
5
+ s.version = "0.0.3"
6
6
  s.authors = ["Charles Oliver Nutter", "MenTaLguY"]
7
7
  s.date = Time.now.strftime('YYYY-MM-DD')
8
8
  s.description = "An atomic reference implementation for JRuby and green or GIL-threaded impls"
9
9
  s.email = ["headius@headius.com", "mental@rydia.net"]
10
- s.files = Dir['{lib,examples,test}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
10
+ s.files = Dir['{lib,examples,test,ext}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
11
11
  s.homepage = "http://github.com/headius/ruby-atomic"
12
12
  s.require_paths = ["lib"]
13
13
  s.summary = "An atomic reference implementation for JRuby and green or GIL-threaded impls"
@@ -0,0 +1,12 @@
1
+ import java.io.IOException;
2
+
3
+ import org.jruby.Ruby;
4
+ import org.jruby.runtime.load.BasicLibraryService;
5
+
6
+ public class AtomicReferenceService implements BasicLibraryService {
7
+ public boolean basicLoad(final Ruby runtime) throws IOException {
8
+ new org.jruby.ext.atomic.AtomicReferenceLibrary().load(runtime, false);
9
+ return true;
10
+ }
11
+ }
12
+
@@ -0,0 +1,81 @@
1
+ package org.jruby.ext.atomic;
2
+
3
+ import java.io.IOException;
4
+ import java.util.concurrent.atomic.AtomicReference;
5
+ import org.jruby.Ruby;
6
+ import org.jruby.RubyClass;
7
+ import org.jruby.RubyModule;
8
+ import org.jruby.RubyObject;
9
+ import org.jruby.anno.JRubyClass;
10
+ import org.jruby.anno.JRubyMethod;
11
+ import org.jruby.runtime.ObjectAllocator;
12
+ import org.jruby.runtime.ThreadContext;
13
+ import org.jruby.runtime.builtin.IRubyObject;
14
+ import org.jruby.runtime.load.Library;
15
+
16
+ /**
17
+ * This library adds an atomic reference type to JRuby for use in the atomic
18
+ * library. We do a native version to avoid the implicit value coercion that
19
+ * normally happens through JI.
20
+ *
21
+ * @author headius
22
+ */
23
+ public class AtomicReferenceLibrary implements Library {
24
+ public void load(Ruby runtime, boolean wrap) throws IOException {
25
+ RubyModule atomicCls = runtime.getClass("Atomic");
26
+ RubyClass jrubyRefClass = runtime.defineClassUnder("InternalReference", runtime.getObject(), JRUBYREFERENCE_ALLOCATOR, atomicCls);
27
+ jrubyRefClass.setAllocator(JRUBYREFERENCE_ALLOCATOR);
28
+ jrubyRefClass.defineAnnotatedMethods(JRubyReference.class);
29
+ }
30
+
31
+ private static final ObjectAllocator JRUBYREFERENCE_ALLOCATOR = new ObjectAllocator() {
32
+ public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
33
+ return new JRubyReference(runtime, klazz);
34
+ }
35
+ };
36
+
37
+ @JRubyClass(name="JRubyReference", parent="Object")
38
+ public static class JRubyReference extends RubyObject {
39
+ private final AtomicReference<IRubyObject> reference;
40
+
41
+ public JRubyReference(Ruby runtime, RubyClass klass) {
42
+ super(runtime, klass);
43
+ reference = new AtomicReference<IRubyObject>(runtime.getNil());
44
+ }
45
+
46
+ @JRubyMethod
47
+ public IRubyObject initialize(ThreadContext context) {
48
+ Ruby runtime = context.getRuntime();
49
+ reference.set(runtime.getNil());
50
+ return runtime.getNil();
51
+ }
52
+
53
+ @JRubyMethod
54
+ public IRubyObject initialize(ThreadContext context, IRubyObject value) {
55
+ Ruby runtime = context.getRuntime();
56
+ reference.set(value);
57
+ return runtime.getNil();
58
+ }
59
+
60
+ @JRubyMethod(name = {"get", "value"})
61
+ public IRubyObject get() {
62
+ return reference.get();
63
+ }
64
+
65
+ @JRubyMethod(name = {"set", "value="})
66
+ public IRubyObject set(IRubyObject newValue) {
67
+ reference.set(newValue);
68
+ return newValue;
69
+ }
70
+
71
+ @JRubyMethod
72
+ public IRubyObject compare_and_set(ThreadContext context, IRubyObject oldValue, IRubyObject newValue) {
73
+ return context.getRuntime().newBoolean(reference.compareAndSet(oldValue, newValue));
74
+ }
75
+
76
+ @JRubyMethod
77
+ public IRubyObject get_and_set(ThreadContext context, IRubyObject newValue) {
78
+ return reference.getAndSet(newValue);
79
+ }
80
+ }
81
+ }
data/lib/atomic.rb CHANGED
@@ -17,6 +17,10 @@ class Atomic
17
17
  new_value
18
18
  end
19
19
 
20
+ def swap(new_value)
21
+ @ref.get_and_set(new_value)
22
+ end
23
+
20
24
  # Pass the current value to the given block, replacing it
21
25
  # with the block's result. May retry if the value changes
22
26
  # during the block's execution.
@@ -34,13 +38,12 @@ class Atomic
34
38
  unless @ref.compare_and_set(old_value, new_value)
35
39
  raise ConcurrentUpdateError, "Update failed"
36
40
  end
37
- old_value
41
+ new_value
38
42
  end
39
43
  end
40
44
 
41
45
  if defined? RUBY_ENGINE && RUBY_ENGINE == "jruby"
42
- require 'java'
43
- Atomic::InternalReference = java.util.concurrent.atomic.AtomicReference
46
+ require 'atomic_reference'
44
47
  else
45
48
  class Atomic::InternalReference
46
49
  attr_accessor :value
@@ -51,6 +54,14 @@ else
51
54
  @value = value
52
55
  end
53
56
 
57
+ def get_and_set(new_value)
58
+ Thread.exclusive do
59
+ old_value = @value
60
+ @value = new_value
61
+ old_value
62
+ end
63
+ end
64
+
54
65
  def compare_and_set(old_value, new_value)
55
66
  Thread.exclusive do
56
67
  return false unless @value.equal? old_value
Binary file
Binary file
data/test/test_atomic.rb CHANGED
@@ -18,34 +18,46 @@ class TestAtomic < Test::Unit::TestCase
18
18
  end
19
19
 
20
20
  def test_update
21
- atomic = Atomic.new(0)
21
+ # use a number outside JRuby's fixnum cache range, to ensure identity is preserved
22
+ atomic = Atomic.new(1000)
22
23
  res = atomic.update {|v| v + 1}
23
24
 
24
- assert_equal 1, atomic.value
25
- assert_equal 0, res
25
+ assert_equal 1001, atomic.value
26
+ assert_equal 1001, res
26
27
  end
27
28
 
28
29
  def test_try_update
29
- atomic = Atomic.new(0)
30
+ # use a number outside JRuby's fixnum cache range, to ensure identity is preserved
31
+ atomic = Atomic.new(1000)
30
32
  res = atomic.try_update {|v| v + 1}
31
33
 
32
- assert_equal 1, atomic.value
33
- assert_equal 0, res
34
+ assert_equal 1001, atomic.value
35
+ assert_equal 1001, res
36
+ end
37
+
38
+ def test_swap
39
+ atomic = Atomic.new(1000)
40
+ res = atomic.swap(1001)
41
+
42
+ assert_equal 1001, atomic.value
43
+ assert_equal 1000, res
34
44
  end
35
45
 
36
46
  def test_try_update_fails
37
- atomic = Atomic.new(0)
47
+ # use a number outside JRuby's fixnum cache range, to ensure identity is preserved
48
+ atomic = Atomic.new(1000)
38
49
  assert_raise Atomic::ConcurrentUpdateError do
39
50
  # assigning within block exploits implementation detail for test
40
- atomic.try_update{|v| atomic.value = 1 ; v + 1}
51
+ atomic.try_update{|v| atomic.value = 1001 ; v + 1}
41
52
  end
42
53
  end
43
54
 
44
55
  def test_update_retries
45
56
  tries = 0
46
- atomic = Atomic.new(0)
57
+ # use a number outside JRuby's fixnum cache range, to ensure identity is preserved
58
+ atomic = Atomic.new(1000)
47
59
  # assigning within block exploits implementation detail for test
48
- atomic.update{|v| tries += 1 ; atomic.value = 1 ; v + 1}
60
+ atomic.update{|v| tries += 1 ; atomic.value = 1001 ; v + 1}
49
61
  assert_equal 2, tries
50
62
  end
51
63
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Charles Oliver Nutter
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-08 00:29:12.585000 -04:00
18
+ date: 2010-06-08 08:04:17.179000 -04:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -31,8 +31,12 @@ extra_rdoc_files: []
31
31
 
32
32
  files:
33
33
  - lib/atomic.rb
34
+ - lib/atomic_reference.jar
35
+ - lib/atomicreference.jar
34
36
  - examples/atomic_example.rb
35
37
  - test/test_atomic.rb
38
+ - ext/AtomicReferenceService.java
39
+ - ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java
36
40
  - README.txt
37
41
  - atomic.gemspec
38
42
  - Rakefile