Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Use thread-local state for all recursive checks.

Backport from 46c59ad. Partial fix for #162.
  • Loading branch information...
commit 3aab61bc00c814624815b228951f5b8a30758846 1 parent 26e08ba
Charles Oliver Nutter authored April 20, 2012 João Duarte committed September 04, 2012
11  spec/regression/recursive_check_thread_safety_spec.rb
... ...
@@ -0,0 +1,11 @@
  1
+require 'rspec'
  2
+
  3
+describe 'Joining an array that contains arrays' do
  4
+  it 'should work across multiple threads without error' do
  5
+    a = [(1..100).to_a]
  6
+    lambda do
  7
+      result = (1..100).map { Thread.new { 10.times { a.join }; :ok } }.map(&:value)
  8
+      result.should == [:ok] * 100
  9
+    end.should_not raise_exception
  10
+  end
  11
+end
19  src/org/jruby/Ruby.java
@@ -1377,7 +1377,8 @@ private void initExceptions() {
1377 1377
             keyError = defineClassIfAllowed("KeyError", indexError);
1378 1378
 
1379 1379
             mathDomainError = defineClassUnder("DomainError", argumentError, argumentError.getAllocator(), mathModule);
1380  
-            recursiveKey = newSymbol("__recursive_key__");
  1380
+            recursiveKey.set(newSymbol("__recursive_key__"));
  1381
+            inRecursiveListOperation.set(false);
1381 1382
         }
1382 1383
 
1383 1384
         initErrno();
@@ -3659,7 +3660,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
3659 3660
         ExecRecursiveParams p = new ExecRecursiveParams();
3660 3661
         p.list = recursiveListAccess();
3661 3662
         p.objid = obj.id();
3662  
-        boolean outermost = outer && !recursiveCheck(p.list, recursiveKey, null);
  3663
+        boolean outermost = outer && !recursiveCheck(p.list, recursiveKey.get(), null);
3663 3664
         if(recursiveCheck(p.list, p.objid, pairid)) {
3664 3665
             if(outer && !outermost) {
3665 3666
                 throw new RecursiveError(p.list);
@@ -3672,7 +3673,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
3672 3673
             p.pairid = pairid;
3673 3674
 
3674 3675
             if(outermost) {
3675  
-                recursivePush(p.list, recursiveKey, null);
  3676
+                recursivePush(p.list, recursiveKey.get(), null);
3676 3677
                 try {
3677 3678
                     result = execRecursiveI(p);
3678 3679
                 } catch(RecursiveError e) {
@@ -3682,7 +3683,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
3682 3683
                         result = p.list;
3683 3684
                     }
3684 3685
                 }
3685  
-                recursivePop(p.list, recursiveKey, null);
  3686
+                recursivePop(p.list, recursiveKey.get(), null);
3686 3687
                 if(result == p.list) {
3687 3688
                     result = func.call(obj, true);
3688 3689
                 }
@@ -3712,7 +3713,7 @@ private IRubyObject execRecursiveInternal(RecursiveFunction func, IRubyObject ob
3712 3713
      * @return
3713 3714
      */
3714 3715
     public IRubyObject execRecursive(RecursiveFunction func, IRubyObject obj) {
3715  
-        if (!inRecursiveListOperation) {
  3716
+        if (!inRecursiveListOperation.get()) {
3716 3717
             throw newThreadError("BUG: execRecursive called outside recursiveListOperation");
3717 3718
         }
3718 3719
         return execRecursiveInternal(func, obj, null, false);
@@ -3751,14 +3752,14 @@ public IRubyObject execRecursiveOuter(RecursiveFunction func, IRubyObject obj) {
3751 3752
      */
3752 3753
     public <T extends IRubyObject> T recursiveListOperation(Callable<T> body) {
3753 3754
         try {
3754  
-            inRecursiveListOperation = true;
  3755
+            inRecursiveListOperation.set(true);
3755 3756
             return body.call();
3756 3757
         } catch (Exception e) {
3757 3758
             UnsafeFactory.getUnsafe().throwException(e);
3758 3759
             return null; // not reached
3759 3760
         } finally {
3760 3761
             recursiveListClear();
3761  
-            inRecursiveListOperation = false;
  3762
+            inRecursiveListOperation.set(false);
3762 3763
         }
3763 3764
     }
3764 3765
 
@@ -4280,6 +4281,6 @@ public CoverageData getCoverageData() {
4280 4281
 
4281 4282
     // structures and such for recursive operations
4282 4283
     private ThreadLocal<Map<String, RubyHash>> recursive = new ThreadLocal<Map<String, RubyHash>>();
4283  
-    private RubySymbol recursiveKey;
4284  
-    private boolean inRecursiveListOperation;
  4284
+    private ThreadLocal<RubySymbol> recursiveKey = new ThreadLocal<RubySymbol>();
  4285
+    private ThreadLocal<Boolean> inRecursiveListOperation = new ThreadLocal<Boolean>();
4285 4286
 }

0 notes on commit 3aab61b

Please sign in to comment.
Something went wrong with that request. Please try again.