From 11ed7726a287bf11f9e82d63674a23824230967e Mon Sep 17 00:00:00 2001 From: "Artemii.Kononov" Date: Fri, 16 Dec 2022 10:45:48 +0300 Subject: [PATCH] [utbot-rd] Fix process dying in dumb mode Fix #1433 Fix #1118 --- .../main/kotlin/org/utbot/common/ProcessUtil.kt | 7 +++---- .../plugin/generator/UtTestsDialogProcessor.kt | 13 +++++++++---- .../intellij/plugin/process/EngineProcess.kt | 11 +++++++++++ .../kotlin/org/utbot/rd/ClientProcessUtil.kt | 16 ++++++++++------ .../generated/SynchronizationModel.Generated.kt | 11 +++++++++-- .../org/utbot/rd/models/SynchronizationModel.kt | 1 + 6 files changed, 43 insertions(+), 16 deletions(-) diff --git a/utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt b/utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt index a0a4b136c3..3371fe29c8 100644 --- a/utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt +++ b/utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt @@ -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() diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt index b82a895c1f..7f62ca55cf 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt @@ -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 { @@ -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." } diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt index 0fa7d119b8..f533110457 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt @@ -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 @@ -407,4 +408,14 @@ class EngineProcess private constructor(val project: Project, rdProcess: Process } initSourceFindingStrategies() } + + fun executeWithTimeoutSuspended(block: () -> T): T { + try { + protocol.synchronizationModel.suspendTimeoutTimer.startBlocking(true) + return block() + } + finally { + protocol.synchronizationModel.suspendTimeoutTimer.startBlocking(false) + } + } } \ No newline at end of file diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt index 8c80d4ce9b..fb35913d02 100644 --- a/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt +++ b/utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt @@ -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 @@ -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() @@ -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) @@ -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 diff --git a/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt index ed8c4e51b0..066be03fb1 100644 --- a/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt +++ b/utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt @@ -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, private val _synchronizationSignal: RdSignal ) : RdExtBase() { //companion @@ -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 get() = _suspendTimeoutTimer val synchronizationSignal: IAsyncSignal 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(FrameworkMarshallers.Bool, FrameworkMarshallers.Void), RdSignal(FrameworkMarshallers.String) ) @@ -78,6 +83,7 @@ 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(")") @@ -85,6 +91,7 @@ class SynchronizationModel private constructor( //deepClone override fun deepClone(): SynchronizationModel { return SynchronizationModel( + _suspendTimeoutTimer.deepClonePolymorphic(), _synchronizationSignal.deepClonePolymorphic() ) } diff --git a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt index 388297d9c6..15fa71a260 100644 --- a/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt +++ b/utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt @@ -7,6 +7,7 @@ object SynchronizationRoot: Root() object SynchronizationModel: Ext(SynchronizationRoot) { init { + call("suspendTimeoutTimer", PredefinedType.bool, PredefinedType.void).async signal("synchronizationSignal", PredefinedType.string).async } } \ No newline at end of file