atomic 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +26 -0
- data/atomic.gemspec +2 -2
- data/ext/AtomicReferenceService.java +12 -0
- data/ext/org/jruby/ext/atomic/AtomicReferenceLibrary.java +81 -0
- data/lib/atomic.rb +14 -3
- data/lib/atomic_reference.jar +0 -0
- data/lib/atomicreference.jar +0 -0
- data/test/test_atomic.rb +22 -10
- metadata +7 -3
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.
|
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
|
-
|
41
|
+
new_value
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
41
45
|
if defined? RUBY_ENGINE && RUBY_ENGINE == "jruby"
|
42
|
-
require '
|
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
|
-
|
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
|
25
|
-
assert_equal
|
25
|
+
assert_equal 1001, atomic.value
|
26
|
+
assert_equal 1001, res
|
26
27
|
end
|
27
28
|
|
28
29
|
def test_try_update
|
29
|
-
|
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
|
33
|
-
assert_equal
|
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
|
-
|
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 =
|
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
|
-
|
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 =
|
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
|
-
-
|
9
|
-
version: 0.0.
|
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
|
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
|