Skip to content

Commit 2f54e9f

Browse files
authored
Fix process dying in dumb mode (#1536)
[utbot-rd] Fix process dying in dumb mode Fix #1433 Fix #1118
1 parent 82c0351 commit 2f54e9f

File tree

6 files changed

+43
-16
lines changed

6 files changed

+43
-16
lines changed

utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt

+3-4
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,9 @@ val currentProcessPid: Long
5454
get() =
5555
try {
5656
if (isJvm9Plus) {
57-
ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessHandle").let {
58-
val handle = it.getDeclaredMethod("current").invoke(it)
59-
it.getDeclaredMethod("pid").invoke(handle) as Long
60-
}
57+
val handleClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessHandle")
58+
val handle = handleClass.getDeclaredMethod("current").invoke(handleClass)
59+
handleClass.getDeclaredMethod("pid").invoke(handle) as Long
6160
} else {
6261
if (isWindows) {
6362
Kernel32.INSTANCE.GetCurrentProcessId()

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/UtTestsDialogProcessor.kt

+9-4
Original file line numberDiff line numberDiff line change
@@ -191,14 +191,15 @@ object UtTestsDialogProcessor {
191191
}
192192
}
193193

194-
val (methods, className) = DumbService.getInstance(project)
194+
val (methods, className) = process.executeWithTimeoutSuspended {
195+
DumbService.getInstance(project)
195196
.runReadActionInSmartMode(Computable {
196197
val canonicalName = srcClass.canonicalName
197198
val classId = process.obtainClassId(canonicalName)
198199
psi2KClass[srcClass] = classId
199-
200200
val srcMethods = if (model.extractMembersFromSrcClasses) {
201-
val chosenMethods = model.selectedMembers.filter { it.member is PsiMethod }
201+
val chosenMethods =
202+
model.selectedMembers.filter { it.member is PsiMethod }
202203
val chosenNestedClasses =
203204
model.selectedMembers.mapNotNull { it.member as? PsiClass }
204205
chosenMethods + chosenNestedClasses.flatMap {
@@ -207,8 +208,12 @@ object UtTestsDialogProcessor {
207208
} else {
208209
srcClass.extractClassMethodsIncludingNested(false)
209210
}
210-
process.findMethodsInClassMatchingSelected(classId, srcMethods) to srcClass.name
211+
process.findMethodsInClassMatchingSelected(
212+
classId,
213+
srcMethods
214+
) to srcClass.name
211215
})
216+
}
212217

213218
if (methods.isEmpty()) {
214219
logger.error { "No methods matching selected found in class $className." }

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt

+11
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import org.utbot.rd.exceptions.InstantProcessDeathException
3838
import org.utbot.rd.generated.SettingForResult
3939
import org.utbot.rd.generated.SettingsModel
4040
import org.utbot.rd.generated.settingsModel
41+
import org.utbot.rd.generated.synchronizationModel
4142
import org.utbot.rd.loggers.UtRdKLoggerFactory
4243
import org.utbot.sarif.SourceFindingStrategy
4344
import java.io.File
@@ -407,4 +408,14 @@ class EngineProcess private constructor(val project: Project, rdProcess: Process
407408
}
408409
initSourceFindingStrategies()
409410
}
411+
412+
fun <T> executeWithTimeoutSuspended(block: () -> T): T {
413+
try {
414+
protocol.synchronizationModel.suspendTimeoutTimer.startBlocking(true)
415+
return block()
416+
}
417+
finally {
418+
protocol.synchronizationModel.suspendTimeoutTimer.startBlocking(false)
419+
}
420+
}
410421
}

utbot-rd/src/main/kotlin/org/utbot/rd/ClientProcessUtil.kt

+10-6
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class IdleWatchdog(private val ldef: LifetimeDefinition, val timeout: Duration)
7171
ldef.onTermination { synchronizer.close(CancellationException("Client terminated")) }
7272
}
7373

74+
var suspendTimeout = false
75+
7476
/**
7577
* Execute block indicating that during this activity process should not die.
7678
* After block ended - idle timer restarts
@@ -105,7 +107,7 @@ class IdleWatchdog(private val ldef: LifetimeDefinition, val timeout: Duration)
105107
synchronizer.receive()
106108
}
107109
if (current == null) {
108-
if (lastState == State.ENDED) {
110+
if (lastState == State.ENDED && !suspendTimeout) {
109111
// process is waiting for command more than expected, better die
110112
logger.info { "terminating lifetime by timeout" }
111113
stopProtocol()
@@ -153,12 +155,14 @@ class ClientProtocolBuilder {
153155
SocketWire.Client(ldef, rdClientProtocolScheduler, port),
154156
ldef
155157
)
156-
val synchronizer = IdleWatchdog(ldef, timeout)
158+
val watchdog = IdleWatchdog(ldef, timeout)
157159

158-
synchronizer.setupTimeout()
160+
watchdog.setupTimeout()
159161
rdClientProtocolScheduler.pump(ldef) {
160-
clientProtocol.synchronizationModel
161-
clientProtocol.block(synchronizer)
162+
clientProtocol.synchronizationModel.suspendTimeoutTimer.set { param ->
163+
watchdog.suspendTimeout = param
164+
}
165+
clientProtocol.block(watchdog)
162166
}
163167

164168
signalProcessReady(port)
@@ -167,7 +171,7 @@ class ClientProtocolBuilder {
167171
val answerFromMainProcess = sync.adviseForConditionAsync(ldef) {
168172
if (it == "main") {
169173
logger.trace { "received from main" }
170-
synchronizer.wrapActive {
174+
watchdog.wrapActive {
171175
sync.fire("child")
172176
}
173177
true

utbot-rd/src/main/kotlin/org/utbot/rd/generated/SynchronizationModel.Generated.kt

+9-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ import kotlin.jvm.JvmStatic
1515

1616

1717
/**
18-
* #### Generated from [SynchronizationModel.kt:7]
18+
* #### Generated from [SynchronizationModel.kt:8]
1919
*/
2020
class SynchronizationModel private constructor(
21+
private val _suspendTimeoutTimer: RdCall<Boolean, Unit>,
2122
private val _synchronizationSignal: RdSignal<String>
2223
) : RdExtBase() {
2324
//companion
@@ -48,27 +49,31 @@ class SynchronizationModel private constructor(
4849
}
4950

5051

51-
const val serializationHash = -6677090974058917499L
52+
const val serializationHash = 3813608056984691311L
5253

5354
}
5455
override val serializersOwner: ISerializersOwner get() = SynchronizationModel
5556
override val serializationHash: Long get() = SynchronizationModel.serializationHash
5657

5758
//fields
59+
val suspendTimeoutTimer: RdCall<Boolean, Unit> get() = _suspendTimeoutTimer
5860
val synchronizationSignal: IAsyncSignal<String> get() = _synchronizationSignal
5961
//methods
6062
//initializer
6163
init {
64+
_suspendTimeoutTimer.async = true
6265
_synchronizationSignal.async = true
6366
}
6467

6568
init {
69+
bindableChildren.add("suspendTimeoutTimer" to _suspendTimeoutTimer)
6670
bindableChildren.add("synchronizationSignal" to _synchronizationSignal)
6771
}
6872

6973
//secondary constructor
7074
private constructor(
7175
) : this(
76+
RdCall<Boolean, Unit>(FrameworkMarshallers.Bool, FrameworkMarshallers.Void),
7277
RdSignal<String>(FrameworkMarshallers.String)
7378
)
7479

@@ -78,13 +83,15 @@ class SynchronizationModel private constructor(
7883
override fun print(printer: PrettyPrinter) {
7984
printer.println("SynchronizationModel (")
8085
printer.indent {
86+
print("suspendTimeoutTimer = "); _suspendTimeoutTimer.print(printer); println()
8187
print("synchronizationSignal = "); _synchronizationSignal.print(printer); println()
8288
}
8389
printer.print(")")
8490
}
8591
//deepClone
8692
override fun deepClone(): SynchronizationModel {
8793
return SynchronizationModel(
94+
_suspendTimeoutTimer.deepClonePolymorphic(),
8895
_synchronizationSignal.deepClonePolymorphic()
8996
)
9097
}

utbot-rd/src/main/rdgen/org/utbot/rd/models/SynchronizationModel.kt

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ object SynchronizationRoot: Root()
77

88
object SynchronizationModel: Ext(SynchronizationRoot) {
99
init {
10+
call("suspendTimeoutTimer", PredefinedType.bool, PredefinedType.void).async
1011
signal("synchronizationSignal", PredefinedType.string).async
1112
}
1213
}

0 commit comments

Comments
 (0)