Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix process dying in dumb mode #1536

Merged
merged 1 commit into from
Dec 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ val currentProcessPid: Long
get() =
try {
if (isJvm9Plus) {
ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessHandle").let {
val handle = it.getDeclaredMethod("current").invoke(it)
it.getDeclaredMethod("pid").invoke(handle) as Long
}
val handleClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessHandle")
val handle = handleClass.getDeclaredMethod("current").invoke(handleClass)
handleClass.getDeclaredMethod("pid").invoke(handle) as Long
} else {
if (isWindows) {
Kernel32.INSTANCE.GetCurrentProcessId()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,14 +191,15 @@ object UtTestsDialogProcessor {
}
}

val (methods, className) = DumbService.getInstance(project)
val (methods, className) = process.executeWithTimeoutSuspended {
DumbService.getInstance(project)
.runReadActionInSmartMode(Computable {
val canonicalName = srcClass.canonicalName
val classId = process.obtainClassId(canonicalName)
psi2KClass[srcClass] = classId

val srcMethods = if (model.extractMembersFromSrcClasses) {
val chosenMethods = model.selectedMembers.filter { it.member is PsiMethod }
val chosenMethods =
model.selectedMembers.filter { it.member is PsiMethod }
val chosenNestedClasses =
model.selectedMembers.mapNotNull { it.member as? PsiClass }
chosenMethods + chosenNestedClasses.flatMap {
Expand All @@ -207,8 +208,12 @@ object UtTestsDialogProcessor {
} else {
srcClass.extractClassMethodsIncludingNested(false)
}
process.findMethodsInClassMatchingSelected(classId, srcMethods) to srcClass.name
process.findMethodsInClassMatchingSelected(
classId,
srcMethods
) to srcClass.name
})
}

if (methods.isEmpty()) {
logger.error { "No methods matching selected found in class $className." }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import org.utbot.rd.exceptions.InstantProcessDeathException
import org.utbot.rd.generated.SettingForResult
import org.utbot.rd.generated.SettingsModel
import org.utbot.rd.generated.settingsModel
import org.utbot.rd.generated.synchronizationModel
import org.utbot.rd.loggers.UtRdKLoggerFactory
import org.utbot.sarif.SourceFindingStrategy
import java.io.File
Expand Down Expand Up @@ -407,4 +408,14 @@ class EngineProcess private constructor(val project: Project, rdProcess: Process
}
initSourceFindingStrategies()
}

fun <T> executeWithTimeoutSuspended(block: () -> T): T {
try {
protocol.synchronizationModel.suspendTimeoutTimer.startBlocking(true)
return block()
}
finally {
protocol.synchronizationModel.suspendTimeoutTimer.startBlocking(false)
}
}
}
16 changes: 10 additions & 6 deletions utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class IdleWatchdog(private val ldef: LifetimeDefinition, val timeout: Duration)
ldef.onTermination { synchronizer.close(CancellationException("Client terminated")) }
}

var suspendTimeout = false

/**
* Execute block indicating that during this activity process should not die.
* After block ended - idle timer restarts
Expand Down Expand Up @@ -105,7 +107,7 @@ class IdleWatchdog(private val ldef: LifetimeDefinition, val timeout: Duration)
synchronizer.receive()
}
if (current == null) {
if (lastState == State.ENDED) {
if (lastState == State.ENDED && !suspendTimeout) {
// process is waiting for command more than expected, better die
logger.info { "terminating lifetime by timeout" }
stopProtocol()
Expand Down Expand Up @@ -153,12 +155,14 @@ class ClientProtocolBuilder {
SocketWire.Client(ldef, rdClientProtocolScheduler, port),
ldef
)
val synchronizer = IdleWatchdog(ldef, timeout)
val watchdog = IdleWatchdog(ldef, timeout)

synchronizer.setupTimeout()
watchdog.setupTimeout()
rdClientProtocolScheduler.pump(ldef) {
clientProtocol.synchronizationModel
clientProtocol.block(synchronizer)
clientProtocol.synchronizationModel.suspendTimeoutTimer.set { param ->
watchdog.suspendTimeout = param
}
clientProtocol.block(watchdog)
}

signalProcessReady(port)
Expand All @@ -167,7 +171,7 @@ class ClientProtocolBuilder {
val answerFromMainProcess = sync.adviseForConditionAsync(ldef) {
if (it == "main") {
logger.trace { "received from main" }
synchronizer.wrapActive {
watchdog.wrapActive {
sync.fire("child")
}
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import kotlin.jvm.JvmStatic


/**
* #### Generated from [SynchronizationModel.kt:7]
* #### Generated from [SynchronizationModel.kt:8]
*/
class SynchronizationModel private constructor(
private val _suspendTimeoutTimer: RdCall<Boolean, Unit>,
private val _synchronizationSignal: RdSignal<String>
) : RdExtBase() {
//companion
Expand Down Expand Up @@ -48,27 +49,31 @@ class SynchronizationModel private constructor(
}


const val serializationHash = -6677090974058917499L
const val serializationHash = 3813608056984691311L

}
override val serializersOwner: ISerializersOwner get() = SynchronizationModel
override val serializationHash: Long get() = SynchronizationModel.serializationHash

//fields
val suspendTimeoutTimer: RdCall<Boolean, Unit> get() = _suspendTimeoutTimer
val synchronizationSignal: IAsyncSignal<String> get() = _synchronizationSignal
//methods
//initializer
init {
_suspendTimeoutTimer.async = true
_synchronizationSignal.async = true
}

init {
bindableChildren.add("suspendTimeoutTimer" to _suspendTimeoutTimer)
bindableChildren.add("synchronizationSignal" to _synchronizationSignal)
}

//secondary constructor
private constructor(
) : this(
RdCall<Boolean, Unit>(FrameworkMarshallers.Bool, FrameworkMarshallers.Void),
RdSignal<String>(FrameworkMarshallers.String)
)

Expand All @@ -78,13 +83,15 @@ class SynchronizationModel private constructor(
override fun print(printer: PrettyPrinter) {
printer.println("SynchronizationModel (")
printer.indent {
print("suspendTimeoutTimer = "); _suspendTimeoutTimer.print(printer); println()
print("synchronizationSignal = "); _synchronizationSignal.print(printer); println()
}
printer.print(")")
}
//deepClone
override fun deepClone(): SynchronizationModel {
return SynchronizationModel(
_suspendTimeoutTimer.deepClonePolymorphic(),
_synchronizationSignal.deepClonePolymorphic()
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ object SynchronizationRoot: Root()

object SynchronizationModel: Ext(SynchronizationRoot) {
init {
call("suspendTimeoutTimer", PredefinedType.bool, PredefinedType.void).async
signal("synchronizationSignal", PredefinedType.string).async
}
}