Skip to content

Commit

Permalink
[fix] take a snapshot for the interrupt stack
Browse files Browse the repository at this point in the history
... as a way of 'double' resolving GH-5520
  • Loading branch information
kares committed Dec 21, 2018
1 parent 4e8c4e9 commit c5191a6
Showing 1 changed file with 8 additions and 17 deletions.
25 changes: 8 additions & 17 deletions core/src/main/java/org/jruby/RubyThread.java
Expand Up @@ -39,21 +39,15 @@
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.Queue;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
Expand Down Expand Up @@ -161,7 +155,7 @@ public class RubyThread extends RubyObject implements ExecutionContext {
//private volatile boolean handleInterrupt = true;

/** Stack of interrupt masks active for this thread */
private final List<RubyHash> interruptMaskStack = Collections.synchronizedList(new ArrayList<RubyHash>());
private final Vector<RubyHash> interruptMaskStack = new Vector<>(4);

/** Thread-local tuple used for sleeping (semaphore, millis, nanos) */
private final SleepTask2 sleepTask = new SleepTask2();
Expand Down Expand Up @@ -193,7 +187,7 @@ public enum Status {
private volatile Object unblockArg;

/** The list of locks this thread currently holds, so they can be released on exit */
private final List<Lock> heldLocks = new Vector<Lock>();
private final List<Lock> heldLocks = new Vector<>();

/** Whether or not this thread has been disposed of */
private volatile boolean disposed = false;
Expand Down Expand Up @@ -345,12 +339,7 @@ private int pendingInterruptCheckMask(ThreadContext context, IRubyObject err) {
List<IRubyObject> ancestors = getMetaClass(err).getAncestorList();
int ancestorsLen = ancestors.size();

List<RubyHash> maskStack = interruptMaskStack;
int maskStackLen = maskStack.size();

for (int i = 0; i < maskStackLen; i++) {
RubyHash mask = maskStack.get(maskStackLen - (i + 1));

for (RubyHash mask : interruptMaskStack) {
for (int j = 0; j < ancestorsLen; j++) {
IRubyObject klass = ancestors.get(j);
IRubyObject sym;
Expand Down Expand Up @@ -657,10 +646,12 @@ private IRubyObject startThread(ThreadContext context, Runnable runnable) throws
}
}

private static void copyInterrupts(ThreadContext context, List<RubyHash> sourceStack, List<RubyHash> targetStack) {
private static final RubyHash[] NULL_ARRAY = new RubyHash[0];

private static void copyInterrupts(ThreadContext context, Vector<RubyHash> sourceStack, Vector<RubyHash> targetStack) {
// We do this in a loop so we can use synchronized collections but not deadlock inside addAll.
// See https://github.com/jruby/jruby/issues/5520
for (RubyHash h : sourceStack) {
for (RubyHash h : sourceStack.toArray(NULL_ARRAY)) {
targetStack.add(h.dupFast(context));
}
}
Expand Down

0 comments on commit c5191a6

Please sign in to comment.