Skip to content

Commit

Permalink
Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
aoli-al committed Aug 13, 2024
1 parent 6a5e483 commit 0b461fe
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 6 deletions.
8 changes: 8 additions & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,18 @@ dependencies {
testImplementation("org.jetbrains.kotlin:kotlin-test")
implementation("org.apache.logging.log4j:log4j-core:2.23.1")
implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.23.1")
testCompileOnly(project(":runtime"))
}

tasks.test {
useJUnitPlatform()
val jvmti = project(":jvmti")
val jdk = project(":instrumentation:jdk")
val agent = project(":instrumentation:agent")
executable("${jdk.layout.buildDirectory.get().asFile}/java-inst/bin/java")
jvmArgs("-agentpath:${jvmti.layout.buildDirectory.get().asFile}/native-libs/libjvmti.so")
jvmArgs("-javaagent:${agent.layout.buildDirectory.get().asFile}/libs/" +
"${agent.name}-${agent.version}-shadow.jar")
}

tasks.named("build") {
Expand Down
13 changes: 9 additions & 4 deletions core/src/main/kotlin/org/pastalab/fray/core/RunContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -281,14 +281,19 @@ class RunContext(val config: Configuration) {
context.pendingOperation = ObjectWaitOperation(objId)
context.state = ThreadState.Enabled
scheduleNextOperation(true)
// If we resume executing, the Object.wait is executed. We should update the
// state of current thread.

// First we need to check if current thread is interrupted.
if (canInterrupt) {
context.checkInterrupt()
}
// No matter if an interrupt is signaled, we need to enter the `wait` method
// first which will unlock the reentrant lock and tries to reacquire it.

// We also need to check if current thread holds the monitor lock.
if (!lockManager.getLockContext(lockObject).isLockHolder(lockObject, t)) {
// If current thread is not lock holder, we should just continue because
// JVM will throw IllegalMonitorStateException.
return
}

if (lockObject == waitingObject) {
context.pendingOperation = ObjectWaitBlocking(waitingObject)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ interface LockContext : Interruptible {
fun hasQueuedThread(tid: Long): Boolean

fun isEmpty(): Boolean

fun isLockHolder(lock: Any, tid: Long): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.pastalab.fray.core.ThreadState
import org.pastalab.fray.core.concurrency.operations.ThreadResumeOperation

class ReentrantLockContext : LockContext {
private var lockHolder: Long? = null
var lockHolder: Long? = null
private val lockTimes = mutableMapOf<Long, Int>()
// Mapping from thread id to whether the thread is interruptible.
private val lockWaiters = mutableMapOf<Long, LockWaiter>()
Expand Down Expand Up @@ -102,4 +102,8 @@ class ReentrantLockContext : LockContext {
lockWaiters.remove(tid)
}
}

override fun isLockHolder(lock: Any, tid: Long): Boolean {
return lockHolder == tid
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,12 @@ class ReentrantReadWriteLockContext : LockContext {
unlockReadWaiters()
unlockWriteWaiters()
}

override fun isLockHolder(lock: Any, tid: Long): Boolean {
return if (lock is ReadLock) {
readLockHolder.contains(tid)
} else {
writeLockHolder == tid
}
}
}
45 changes: 45 additions & 0 deletions core/src/test/java/org/pastalab/fray/core/test/FrayRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.pastalab.fray.core.test;

import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import org.pastalab.fray.core.TestRunner;
import org.pastalab.fray.core.command.Configuration;
import org.pastalab.fray.core.command.ExecutionInfo;
import org.pastalab.fray.core.command.LambdaExecutor;
import org.pastalab.fray.core.randomness.ControlledRandom;
import org.pastalab.fray.core.scheduler.FifoScheduler;
import org.pastalab.fray.core.scheduler.Scheduler;


public class FrayRunner {
public Throwable runTest(Function0<Unit> exec) {
return runTest(exec, new FifoScheduler(), 1);
}

public Throwable runTest(Function0<Unit> exec, Scheduler scheduler, int iter) {
String testName = this.getClass().getSimpleName();
Configuration config = new Configuration(
new ExecutionInfo(
new LambdaExecutor(() -> {
exec.invoke();
return null;
}),
false,
true,
false,
10000
),
"/tmp/report",
iter,
scheduler,
new ControlledRandom(),
true,
false,
true,
false,
false
);
TestRunner runner = new TestRunner(config);
return runner.run();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.pastalab.fray.core.test.primitives;

import org.junit.jupiter.api.Test;
import org.pastalab.fray.core.test.FrayRunner;
import org.pastalab.fray.runtime.DeadlockException;

import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class WaitTest extends FrayRunner {

@Test
public void testWaitWithoutMonitorLock() {
Throwable result = runTest(() -> {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return null;
});
assertTrue(result instanceof IllegalMonitorStateException);
}

@Test
public void testWaitWithMonitorLock() {
Throwable result = runTest(() -> {
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return null;
});
assertTrue(result instanceof DeadlockException);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class ApplicationCodeTransformer : ClassFileTransformer {
dotClassName.startsWith("com.github.ajalt") ||
(dotClassName.startsWith("org.pastalab.fray") &&
!dotClassName.startsWith("org.pastalab.fray.benchmark") &&
!dotClassName.startsWith("org.pastalab.fray.it"))) {
!dotClassName.startsWith("org.pastalab.fray.core.test"))) {
// This is likely a JDK class, so skip transformation
return classfileBuffer
}
Expand Down

0 comments on commit 0b461fe

Please sign in to comment.