Skip to content

Commit

Permalink
Fix timed countdownlatch hang. (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
aoli-al authored Nov 8, 2024
1 parent 76a3fec commit 98b2e50
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 22 deletions.
8 changes: 2 additions & 6 deletions core/src/main/kotlin/org/pastalab/fray/core/RunContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -517,8 +517,7 @@ class RunContext(val config: Configuration) {
context.state = ThreadState.Enabled
}
is CountDownLatchAwaitBlocking -> {
context.pendingOperation = ThreadResumeOperation(false)
context.state = ThreadState.Enabled
latchManager.unblockThread(pendingOperation.latch, context.thread.id, true, false)
if (context.thread != Thread.currentThread()) {
syncManager.createWait(pendingOperation.latch, 1)
context.thread.interrupt()
Expand Down Expand Up @@ -795,10 +794,7 @@ class RunContext(val config: Configuration) {
if (latchManager.await(latch, true, context)) {
context.pendingOperation = CountDownLatchAwaitBlocking(latch, timed)
context.state = ThreadState.Paused
checkDeadlock {
context.state = ThreadState.Running
context.pendingOperation = ThreadResumeOperation(true)
}
checkDeadlock { latchManager.unblockThread(latch, t, false, false) }
executor.submit {
while (registeredThreads[t]!!.thread.state == Thread.State.RUNNABLE) {
Thread.yield()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,18 @@ class CountDownLatchContext(var count: Long) : Interruptible {
return false
}

override fun interrupt(tid: Long) {
fun unblockThread(tid: Long, isTimeout: Boolean, isInterrupt: Boolean) {
val lockWaiter = latchWaiters[tid] ?: return
if (lockWaiter.canInterrupt) {
lockWaiter.thread.pendingOperation = ThreadResumeOperation(false)
lockWaiter.thread.state = ThreadState.Enabled
latchWaiters.remove(tid)
if (isInterrupt && !lockWaiter.canInterrupt) {
return
}
lockWaiter.thread.pendingOperation = ThreadResumeOperation(!isTimeout)
lockWaiter.thread.state = ThreadState.Enabled
latchWaiters.remove(tid)
}

override fun interrupt(tid: Long) {
unblockThread(tid, false, true)
}

fun release(): Int {
Expand All @@ -35,8 +40,7 @@ class CountDownLatchContext(var count: Long) : Interruptible {
count = 0
var threads = 0
for (lockWaiter in latchWaiters.values) {
lockWaiter.thread.pendingOperation = ThreadResumeOperation(true)
lockWaiter.thread.state = ThreadState.Enabled
unblockThread(lockWaiter.thread.thread.id, false, false)
threads += 1
}
return threads
Expand All @@ -55,8 +59,7 @@ class CountDownLatchContext(var count: Long) : Interruptible {
if (count == 0L) {
var threads = 0
for (lockWaiter in latchWaiters.values) {
lockWaiter.thread.pendingOperation = ThreadResumeOperation(true)
lockWaiter.thread.state = ThreadState.Enabled
unblockThread(lockWaiter.thread.thread.id, false, false)
threads += 1
}
return threads
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ class CountDownLatchManager {
return latchStore.getContext(latch).await(canInterrupt, thread)
}

fun unblockThread(latch: CountDownLatch, tid: Long, isTimeout: Boolean, isInterrupt: Boolean) {
latchStore.getContext(latch).unblockThread(tid, isTimeout, isInterrupt)
}

/*
* Returns number of unblocked threads.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.pastalab.fray.test.success.cdl;

import java.util.concurrent.CountDownLatch;

public class CountDownLatchNormalNotify {
public static void main(String[] args) throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(1);
Thread t = new Thread(() -> {
try {
cdl.await(1000, java.util.concurrent.TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
Object o = new Object();
synchronized (o) {
o.wait(1000);
}
cdl.countDown();
t.join();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import org.pastalab.fray.core.scheduler.POSScheduler;
import org.pastalab.fray.core.scheduler.RandomScheduler;
import org.pastalab.fray.runtime.TargetTerminateException;
import org.pastalab.fray.test.success.cdl.CountDownLatchNormalNotify;
import org.pastalab.fray.test.success.condition.ConditionAwaitTimeoutInterrupt;
import org.pastalab.fray.test.success.condition.ConditionAwaitTimeoutNotifyInterrupt;

Expand Down Expand Up @@ -70,7 +71,11 @@ public void testOne() throws Throwable {
Configuration config = new Configuration(
new ExecutionInfo(
new LambdaExecutor(() -> {
ConditionAwaitTimeoutNotifyInterrupt.main(new String[]{});
try {
CountDownLatchNormalNotify.main(new String[]{});
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return null;
}),
false,
Expand All @@ -79,13 +84,9 @@ public void testOne() throws Throwable {
-1
),
"/tmp/report2",
100,
1000,
60,
new RandomScheduler(new ControlledRandom(
new ArrayList<>(List.of(1, 1, 1, 0)),
new ArrayList<>(),
new Random()
)),
new POSScheduler(),
new ControlledRandom(
new ArrayList<>(List.of(0, 0, 0, 0, 0, 0)),
new ArrayList<>(),
Expand Down

0 comments on commit 98b2e50

Please sign in to comment.