Skip to content

Commit

Permalink
Fix memory leaks caused by circular referencing. (#85)
Browse files Browse the repository at this point in the history
* Fix memory leaks caused by circurlar referencing.

* Revert test changes.
  • Loading branch information
aoli-al authored Jan 6, 2025
1 parent c3dae54 commit ed28773
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 18 deletions.
5 changes: 2 additions & 3 deletions core/src/main/kotlin/org/pastalab/fray/core/RunContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ class RunContext(val config: Configuration) {
var bugFound: Throwable? = null
var mainExiting = false
var nanoTime = System.nanoTime()
val terminatingThread = mutableSetOf<Int>()
val hashCodeMapper = ReferencedContextManager<Int>({ config.randomnessProvider.nextInt() })
var forkJoinPool: ForkJoinPool? = null
private val semaphoreManager = ReferencedContextManager {
Expand Down Expand Up @@ -215,7 +214,7 @@ class RunContext(val config: Configuration) {

fun done() {
verifyOrReport(syncManager.synchronizationPoints.isEmpty())
lockManager.done()
lockManager.done(false)
signalManager.done()
stampedLockManager.done()
semaphoreManager.done()
Expand Down Expand Up @@ -1012,7 +1011,7 @@ class RunContext(val config: Configuration) {
}

fun nanoTime(): Long {
nanoTime += TimeUnit.MILLISECONDS.convert(100, TimeUnit.NANOSECONDS)
nanoTime += TimeUnit.MILLISECONDS.convert(10000, TimeUnit.NANOSECONDS)
return nanoTime
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,9 +491,7 @@ class RuntimeDelegate(val context: RunContext) : org.pastalab.fray.runtime.Deleg
}

override fun onReentrantReadWriteLockInit(lock: ReentrantReadWriteLock) {
if (checkEntered()) return
context.reentrantReadWriteLockInit(lock.readLock(), lock.writeLock())
entered.set(false)
}

override fun onSemaphoreInit(sem: Semaphore) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import java.nio.file.Paths
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteRecursively
import kotlin.io.path.exists
import kotlin.time.TimeSource
import kotlinx.serialization.Polymorphic
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -247,7 +248,7 @@ data class Configuration(
val frayLogger = FrayLogger("$report/fray.log")

init {
if (!isReplay) {
if (!isReplay || !Paths.get(report).exists()) {
prepareReportPath(report)
}
if (System.getProperty("fray.recordSchedule", "false").toBoolean()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package org.pastalab.fray.core.concurrency.primitives

import java.lang.ref.WeakReference
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.Lock
import org.pastalab.fray.core.ThreadContext
import org.pastalab.fray.core.concurrency.operations.ConditionAwaitBlocked
import org.pastalab.fray.core.concurrency.operations.ConditionWakeBlocked
import org.pastalab.fray.rmi.ThreadState

class ConditionSignalContext(lockContext: LockContext, val lock: Lock, val condition: Condition) :
class ConditionSignalContext(lockContext: LockContext, lock: Lock, val condition: Condition) :
SignalContext(lockContext) {
val lockReference = WeakReference(lock)

override fun sendSignalToObject() {
lock.lock()
lockReference.get()?.lock()
try {
condition.signalAll()
} finally {
lock.unlock()
lockReference.get()?.unlock()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.pastalab.fray.core.concurrency.primitives

import java.lang.ref.WeakReference
import java.util.concurrent.CountDownLatch
import org.pastalab.fray.core.ThreadContext
import org.pastalab.fray.core.concurrency.SynchronizationManager
Expand All @@ -12,10 +13,11 @@ import org.pastalab.fray.rmi.ThreadState
* Context for a [CountDownLatch]. We have to pass syncManager here because we need to create a
* synchronization point when we unblock a thread forcefully.
*/
class CountDownLatchContext(val latch: CountDownLatch, val syncManager: SynchronizationManager) :
class CountDownLatchContext(latch: CountDownLatch, val syncManager: SynchronizationManager) :
InterruptibleContext {
var count = latch.count
val latchWaiters = mutableMapOf<Long, LockWaiter>()
val latchReference = WeakReference(latch)

fun await(canInterrupt: Boolean, thread: ThreadContext): Boolean {
if (count > 0) {
Expand Down Expand Up @@ -59,12 +61,14 @@ class CountDownLatchContext(val latch: CountDownLatch, val syncManager: Synchron
if (type == InterruptionType.FORCE) {
while (count != 0L) {
val unblockedThreads = countDown()
if (unblockedThreads > 0) {
syncManager.createWait(latch, unblockedThreads)
latch.countDown()
syncManager.wait(latch)
} else {
latch.countDown()
latchReference.get()?.let { latch ->
if (unblockedThreads > 0) {
syncManager.createWait(latch, unblockedThreads)
latch.countDown()
syncManager.wait(latch)
} else {
latch.countDown()
}
}
}
return false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package org.pastalab.fray.core.concurrency.primitives

import java.lang.ref.WeakReference
import org.pastalab.fray.core.ThreadContext
import org.pastalab.fray.core.concurrency.operations.ObjectWaitBlock
import org.pastalab.fray.core.concurrency.operations.ObjectWakeBlocked
import org.pastalab.fray.rmi.ThreadState

class ObjectNotifyContext(lockContext: LockContext, val obj: Any) : SignalContext(lockContext) {
class ObjectNotifyContext(lockContext: LockContext, obj: Any) : SignalContext(lockContext) {
val objReference = WeakReference(obj)

override fun sendSignalToObject() {
synchronized(obj) { (obj as Object).notifyAll() }
objReference.get()?.let { obj -> synchronized(obj) { (obj as Object).notifyAll() } }
}

override fun updatedThreadContextDueToUnblock(
Expand Down

0 comments on commit ed28773

Please sign in to comment.