Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Use thread-local state for all recursive checks.

  • Loading branch information...
commit 46c59ad659136fbda7c7fcd77b8bb47180f424f0 1 parent f882e9d
@headius headius authored
View
11 spec/regression/recursive_check_thread_safety_spec.rb
@@ -0,0 +1,11 @@
+require 'rspec'
+
+describe 'Joining an array that contains arrays' do
+ it 'should work across multiple threads without error' do
+ a = [(1..100).to_a]
+ lambda do
+ result = (1..100).map { Thread.new { 10.times { a.join }; :ok } }.map(&:value)
+ result.should == [:ok] * 100
+ end.should_not raise_exception
+ end
+end
View
19 src/org/jruby/Ruby.java
@@ -1480,7 +1480,8 @@ private void initExceptions() {
keyError = defineClassIfAllowed("KeyError", indexError);
mathDomainError = defineClassUnder("DomainError", argumentError, argumentError.getAllocator(), mathModule);
- recursiveKey = newSymbol("__recursive_key__");
+ recursiveKey.set(newSymbol("__recursive_key__"));
+ inRecursiveListOperation.set(false);
}
initErrno();
@@ -3796,7 +3797,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
ExecRecursiveParams p = new ExecRecursiveParams();
p.list = recursiveListAccess();
p.objid = obj.id();
- boolean outermost = outer && !recursiveCheck(p.list, recursiveKey, null);
+ boolean outermost = outer && !recursiveCheck(p.list, recursiveKey.get(), null);
if(recursiveCheck(p.list, p.objid, pairid)) {
if(outer && !outermost) {
throw new RecursiveError(p.list);
@@ -3809,7 +3810,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
p.pairid = pairid;
if(outermost) {
- recursivePush(p.list, recursiveKey, null);
+ recursivePush(p.list, recursiveKey.get(), null);
try {
result = execRecursiveI(p);
} catch(RecursiveError e) {
@@ -3819,7 +3820,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
result = p.list;
}
}
- recursivePop(p.list, recursiveKey, null);
+ recursivePop(p.list, recursiveKey.get(), null);
if(result == p.list) {
result = func.call(obj, true);
}
@@ -3849,7 +3850,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
* @return
*/
public IRubyObject execRecursive(RecursiveFunction func, IRubyObject obj) {
- if (!inRecursiveListOperation) {
+ if (!inRecursiveListOperation.get()) {
throw newThreadError("BUG: execRecursive called outside recursiveListOperation");
}
return execRecursiveInternal(func, obj, null, false);
@@ -3888,14 +3889,14 @@ public IRubyObject execRecursiveOuter(RecursiveFunction func, IRubyObject obj) {
*/
public <T extends IRubyObject> T recursiveListOperation(Callable<T> body) {
try {
- inRecursiveListOperation = true;
+ inRecursiveListOperation.set(true);
return body.call();
} catch (Exception e) {
UnsafeFactory.getUnsafe().throwException(e);
return null; // not reached
} finally {
recursiveListClear();
- inRecursiveListOperation = false;
+ inRecursiveListOperation.set(false);
}
}
@@ -4447,8 +4448,8 @@ public void setFFI(FFI ffi) {
// structures and such for recursive operations
private ThreadLocal<Map<String, RubyHash>> recursive = new ThreadLocal<Map<String, RubyHash>>();
- private RubySymbol recursiveKey;
- private boolean inRecursiveListOperation;
+ private ThreadLocal<RubySymbol> recursiveKey = new ThreadLocal<RubySymbol>();
+ private ThreadLocal<Boolean> inRecursiveListOperation = new ThreadLocal<Boolean>();
private FFI ffi;
}
Please sign in to comment.
Something went wrong with that request. Please try again.