From 04aaeeb40aa718328f281dec43941ff88a526be1 Mon Sep 17 00:00:00 2001 From: Ao Li Date: Tue, 23 Apr 2024 23:08:50 -0400 Subject: [PATCH] more error info & fix deadlocks. --- .../cmu/pasta/fray/core/GlobalContext.kt | 22 +++++++++----- .../cmu/pasta/fray/core/RuntimeDelegate.kt | 29 ++++++++++++++----- .../kotlin/cmu/pasta/fray/core/TestRunner.kt | 7 +---- .../pasta/fray/core/logger/ConsoleLogger.kt | 3 +- .../cmu/pasta/fray/core/logger/CsvLogger.kt | 3 +- .../cmu/pasta/fray/core/logger/JsonLogger.kt | 6 ++-- .../cmu/pasta/fray/core/logger/LoggerBase.kt | 3 +- integration-tests/build.gradle.kts | 1 + .../java/cmu/pasta/fray/it/EventLogger.java | 2 +- run.sh | 4 +++ .../java/cmu/pasta/fray/runtime/Delegate.java | 15 +++++----- .../java/cmu/pasta/fray/runtime/Runtime.java | 15 +++++----- 12 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 run.sh diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/GlobalContext.kt b/core/src/main/kotlin/cmu/pasta/fray/core/GlobalContext.kt index 08c3bd1..93a2483 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/GlobalContext.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/GlobalContext.kt @@ -7,7 +7,6 @@ import cmu.pasta.fray.core.concurrency.locks.LockManager import cmu.pasta.fray.core.concurrency.locks.SemaphoreManager import cmu.pasta.fray.core.concurrency.operations.* import cmu.pasta.fray.core.logger.LoggerBase -import cmu.pasta.fray.core.runtime.AnalysisResult import cmu.pasta.fray.core.scheduler.Choice import cmu.pasta.fray.core.scheduler.FifoScheduler import cmu.pasta.fray.core.scheduler.Scheduler @@ -22,6 +21,7 @@ import java.util.concurrent.CountDownLatch import java.util.concurrent.Executors import java.util.concurrent.Semaphore import java.util.concurrent.locks.Condition +import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock @@ -100,6 +100,8 @@ object GlobalContext { } } context.state = ThreadState.Completed + Runtime.DELEGATE = Delegate() + done() } fun start() { @@ -118,8 +120,8 @@ object GlobalContext { scheduleNextOperation(true) } - fun done(result: AnalysisResult) { - loggers.forEach { it.executionDone(result) } + fun done() { + loggers.forEach { it.executionDone() } assert(lockManager.waitingThreads.isEmpty()) assert(syncManager.synchronizationPoints.isEmpty()) @@ -175,7 +177,7 @@ object GlobalContext { if (context.state == ThreadState.Running) { return } - assert(context.state == ThreadState.Paused) + assert(context.state == ThreadState.Enabled) syncManager.signal(t) context.block() } @@ -192,7 +194,7 @@ object GlobalContext { } fun threadUnparkDone(t: Thread) { - if (registeredThreads[t.id]!!.state == ThreadState.Paused) { + if (registeredThreads[t.id]!!.state != ThreadState.Paused) { // SFuzz only needs to wait if `t` is parked and then // waken up by this `unpark` operation. syncManager.wait(t) @@ -224,7 +226,6 @@ object GlobalContext { size = it.size } syncManager.createWait(t, size) - executor.submit { while (t.isAlive) { Thread.yield() @@ -392,7 +393,7 @@ object GlobalContext { objectNotifyAllImpl(o, lockManager.lockFromCondition(o)) } - fun reentrantLockTrylock(lock: Any) { + fun lockTryLock(lock: Any) { val t = Thread.currentThread().id val objId = System.identityHashCode(lock) registeredThreads[t]?.pendingOperation = LockLockOperation(objId) @@ -514,7 +515,7 @@ object GlobalContext { syncManager.wait(lock) } - fun lockNewCondition(condition: Condition, lock: ReentrantLock) { + fun lockNewCondition(condition: Condition, lock: Lock) { lockManager.registerNewCondition(condition, lock) } @@ -660,6 +661,11 @@ object GlobalContext { } } + fun yield() { + registeredThreads[Thread.currentThread().id]!!.state = ThreadState.Enabled + scheduleNextOperation(true) + } + fun scheduleNextOperation(shouldBlockCurrentThread: Boolean) { try { // Our current design makes sure that reschedule is only called diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/RuntimeDelegate.kt b/core/src/main/kotlin/cmu/pasta/fray/core/RuntimeDelegate.kt index 95a3ba2..8d6f2d1 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/RuntimeDelegate.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/RuntimeDelegate.kt @@ -7,7 +7,7 @@ import cmu.pasta.fray.runtime.TargetTerminateException import java.util.concurrent.CountDownLatch import java.util.concurrent.Semaphore import java.util.concurrent.locks.Condition -import java.util.concurrent.locks.ReentrantLock +import java.util.concurrent.locks.Lock import java.util.concurrent.locks.ReentrantReadWriteLock class RuntimeDelegate : Delegate() { @@ -101,7 +101,7 @@ class RuntimeDelegate : Delegate() { entered.set(false) } - override fun onLockLockInterruptibly(l: ReentrantLock) { + override fun onLockLockInterruptibly(l: Lock) { if (checkEntered()) { skipFunctionEntered.set(1 + skipFunctionEntered.get()) return @@ -114,7 +114,20 @@ class RuntimeDelegate : Delegate() { } } - override fun onLockLock(l: ReentrantLock) { + override fun onLockTryLock(l: Lock) { + if (checkEntered()) { + skipFunctionEntered.set(1 + skipFunctionEntered.get()) + return + } + try { + GlobalContext.lockTryLock(l) + } finally { + entered.set(false) + skipFunctionEntered.set(skipFunctionEntered.get() + 1) + } + } + + override fun onLockLock(l: Lock) { if (checkEntered()) { skipFunctionEntered.set(1 + skipFunctionEntered.get()) return @@ -127,7 +140,7 @@ class RuntimeDelegate : Delegate() { } } - override fun onLockLockDone(l: ReentrantLock?) { + override fun onLockLockDone(l: Lock?) { skipFunctionEntered.set(skipFunctionEntered.get() - 1) } @@ -140,7 +153,7 @@ class RuntimeDelegate : Delegate() { } } - override fun onLockUnlock(l: ReentrantLock) { + override fun onLockUnlock(l: Lock) { if (checkEntered()) { skipFunctionEntered.set(1 + skipFunctionEntered.get()) return @@ -150,7 +163,7 @@ class RuntimeDelegate : Delegate() { skipFunctionEntered.set(1 + skipFunctionEntered.get()) } - override fun onLockUnlockDone(l: ReentrantLock) { + override fun onLockUnlockDone(l: Lock) { skipFunctionEntered.set(skipFunctionEntered.get() - 1) if (checkEntered()) return GlobalContext.lockUnlockDone(l) @@ -178,7 +191,7 @@ class RuntimeDelegate : Delegate() { entered.set(false) } - override fun onLockNewCondition(c: Condition, l: ReentrantLock): Condition { + override fun onLockNewCondition(c: Condition, l: Lock): Condition { if (checkEntered()) return c GlobalContext.lockNewCondition(c, l) entered.set(false) @@ -283,7 +296,7 @@ class RuntimeDelegate : Delegate() { override fun onYield() { if (checkEntered()) return try { - GlobalContext.scheduleNextOperation(true) + GlobalContext.yield() } finally { entered.set(false) } diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/TestRunner.kt b/core/src/main/kotlin/cmu/pasta/fray/core/TestRunner.kt index ed11a2d..eb1a359 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/TestRunner.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/TestRunner.kt @@ -1,8 +1,6 @@ package cmu.pasta.fray.core import cmu.pasta.fray.core.logger.ConsoleLogger -import cmu.pasta.fray.core.runtime.AnalysisResult -import cmu.pasta.fray.runtime.Delegate import cmu.pasta.fray.runtime.Runtime import java.nio.file.Paths import kotlin.io.path.ExperimentalPathApi @@ -39,12 +37,9 @@ class TestRunner(val config: Configuration) { config.exec() Runtime.onMainExit() } catch (e: Throwable) { - GlobalContext.errorFound = true + Runtime.onReportError(e) Runtime.onMainExit() - GlobalContext.log("Error found: $e") } - Runtime.DELEGATE = Delegate() - GlobalContext.done(AnalysisResult.COMPLETE) if (GlobalContext.errorFound) { println("Error found at iter: $i") break diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/logger/ConsoleLogger.kt b/core/src/main/kotlin/cmu/pasta/fray/core/logger/ConsoleLogger.kt index 89dd544..72b740e 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/logger/ConsoleLogger.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/logger/ConsoleLogger.kt @@ -1,7 +1,6 @@ package cmu.pasta.fray.core.logger import cmu.pasta.fray.core.concurrency.operations.Operation -import cmu.pasta.fray.core.runtime.AnalysisResult import cmu.pasta.fray.core.scheduler.Choice class ConsoleLogger : LoggerBase { @@ -9,7 +8,7 @@ class ConsoleLogger : LoggerBase { override fun newOperationScheduled(op: Operation, choice: Choice) {} - override fun executionDone(result: AnalysisResult) {} + override fun executionDone() {} override fun applicationEvent(event: String) { println(event) diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/logger/CsvLogger.kt b/core/src/main/kotlin/cmu/pasta/fray/core/logger/CsvLogger.kt index 22ac6d4..c921403 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/logger/CsvLogger.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/logger/CsvLogger.kt @@ -1,7 +1,6 @@ package cmu.pasta.fray.core.logger import cmu.pasta.fray.core.concurrency.operations.Operation -import cmu.pasta.fray.core.runtime.AnalysisResult import cmu.pasta.fray.core.scheduler.Choice import java.io.File @@ -20,7 +19,7 @@ class CsvLogger(private val baseFolder: String, private val fullSchedule: Boolea "${choice.selected},${choice.threadId},${choice.enabled},${op.javaClass.name}\n") } - override fun executionDone(result: AnalysisResult) { + override fun executionDone() { index += 1 } diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/logger/JsonLogger.kt b/core/src/main/kotlin/cmu/pasta/fray/core/logger/JsonLogger.kt index 1c9a562..0784e63 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/logger/JsonLogger.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/logger/JsonLogger.kt @@ -1,7 +1,6 @@ package cmu.pasta.fray.core.logger import cmu.pasta.fray.core.concurrency.operations.Operation -import cmu.pasta.fray.core.runtime.AnalysisResult import cmu.pasta.fray.core.scheduler.Choice import cmu.pasta.fray.core.scheduler.Schedule import java.io.File @@ -13,7 +12,6 @@ import kotlinx.serialization.json.Json data class Record( val timeline: MutableList, val schedule: Schedule, - val result: AnalysisResult ) class JsonLogger(val base: String, val fullSchedule: Boolean) : LoggerBase { @@ -33,8 +31,8 @@ class JsonLogger(val base: String, val fullSchedule: Boolean) : LoggerBase { schedule.choices.add(choice) } - override fun executionDone(result: AnalysisResult) { - executions.add(Record(currentTimeline, schedule, result)) + override fun executionDone() { + executions.add(Record(currentTimeline, schedule)) // if (result != AnalysisResult.COMPLETE) { // // File("$base/schedule_${savedSchedule++}.json").writeText(json.encodeToString(schedule)) diff --git a/core/src/main/kotlin/cmu/pasta/fray/core/logger/LoggerBase.kt b/core/src/main/kotlin/cmu/pasta/fray/core/logger/LoggerBase.kt index db092e3..b42f9fb 100644 --- a/core/src/main/kotlin/cmu/pasta/fray/core/logger/LoggerBase.kt +++ b/core/src/main/kotlin/cmu/pasta/fray/core/logger/LoggerBase.kt @@ -1,7 +1,6 @@ package cmu.pasta.fray.core.logger import cmu.pasta.fray.core.concurrency.operations.Operation -import cmu.pasta.fray.core.runtime.AnalysisResult import cmu.pasta.fray.core.scheduler.Choice interface LoggerBase { @@ -9,7 +8,7 @@ interface LoggerBase { fun newOperationScheduled(op: Operation, choice: Choice) - fun executionDone(result: AnalysisResult) + fun executionDone() // fun logError(error: String) diff --git a/integration-tests/build.gradle.kts b/integration-tests/build.gradle.kts index 1164f64..3f269ff 100644 --- a/integration-tests/build.gradle.kts +++ b/integration-tests/build.gradle.kts @@ -25,4 +25,5 @@ tasks.test { executable("${jdk.layout.buildDirectory.get().asFile}/java-inst/bin/java") jvmArgs("-agentpath:$agentPath") jvmArgs("-javaagent:${instrumentation.layout.buildDirectory.get().asFile}/libs/${instrumentation.name}-${instrumentation.version}-all.jar") + jvmArgs("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005") } diff --git a/integration-tests/src/test/java/cmu/pasta/fray/it/EventLogger.java b/integration-tests/src/test/java/cmu/pasta/fray/it/EventLogger.java index 8901802..627cafb 100644 --- a/integration-tests/src/test/java/cmu/pasta/fray/it/EventLogger.java +++ b/integration-tests/src/test/java/cmu/pasta/fray/it/EventLogger.java @@ -17,7 +17,7 @@ public void newOperationScheduled(Operation op, Choice choice) { } @Override - public void executionDone(AnalysisResult result) { + public void executionDone() { } diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..d11385e --- /dev/null +++ b/run.sh @@ -0,0 +1,4 @@ +while true +do + ./gradlew cleanTest :integration-tests:test --tests "cmu.pasta.fray.it.lincheck.LogicalOrderingAVLTest.testConcurrentInsertRemove" +done diff --git a/runtime/src/main/java/cmu/pasta/fray/runtime/Delegate.java b/runtime/src/main/java/cmu/pasta/fray/runtime/Delegate.java index ed69779..2ec41e7 100644 --- a/runtime/src/main/java/cmu/pasta/fray/runtime/Delegate.java +++ b/runtime/src/main/java/cmu/pasta/fray/runtime/Delegate.java @@ -3,6 +3,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -32,27 +33,27 @@ public void onObjectNotify(Object o) { public void onObjectNotifyAll(Object o) { } - public void onReentrantLockTryLock(ReentrantLock l) { + public void onLockTryLock(Lock l) { } - public void onLockLock(ReentrantLock l) { + public void onLockLock(Lock l) { } - public void onLockLockInterruptibly(ReentrantLock l) { + public void onLockLockInterruptibly(Lock l) { } - public void onLockLockDone(ReentrantLock l) { + public void onLockLockDone(Lock l) { } - public void onLockUnlock(ReentrantLock l) { + public void onLockUnlock(Lock l) { } - public void onLockUnlockDone(ReentrantLock l) { + public void onLockUnlockDone(Lock l) { } public void onAtomicOperation(Object o, MemoryOpType type) { } - public Condition onLockNewCondition(Condition c, ReentrantLock l) { + public Condition onLockNewCondition(Condition c, Lock l) { return c; } diff --git a/runtime/src/main/java/cmu/pasta/fray/runtime/Runtime.java b/runtime/src/main/java/cmu/pasta/fray/runtime/Runtime.java index 6d61852..50d9598 100644 --- a/runtime/src/main/java/cmu/pasta/fray/runtime/Runtime.java +++ b/runtime/src/main/java/cmu/pasta/fray/runtime/Runtime.java @@ -3,6 +3,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -28,27 +29,27 @@ public static void onThreadRun() { DELEGATE.onThreadRun(); } - public static void onLockTryLock(ReentrantLock l) { - DELEGATE.onReentrantLockTryLock(l); + public static void onLockTryLock(Lock l) { + DELEGATE.onLockTryLock(l); } - public static void onLockLock(ReentrantLock l) { + public static void onLockLock(Lock l) { DELEGATE.onLockLock(l); } - public static void onLockLockDone(ReentrantLock l) { + public static void onLockLockDone(Lock l) { DELEGATE.onLockLockDone(l); } - public static void onLockUnlock(ReentrantLock l) { + public static void onLockUnlock(Lock l) { DELEGATE.onLockUnlock(l); } - public static void onLockUnlockDone(ReentrantLock l) { + public static void onLockUnlockDone(Lock l) { DELEGATE.onLockUnlockDone(l); } - public static Condition onLockNewCondition(Condition c, ReentrantLock l) { + public static Condition onLockNewCondition(Condition c, Lock l) { return DELEGATE.onLockNewCondition(c, l); }