Skip to content

Commit a2ef81a

Browse files
committed
[instrumentation-rd]
removed count down latches
1 parent 5d77c28 commit a2ef81a

File tree

7 files changed

+196
-191
lines changed

7 files changed

+196
-191
lines changed

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/ConcreteExecutor.kt

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import org.utbot.instrumentation.rd.UtInstrumentationProcess
1919
import org.utbot.instrumentation.rd.UtRdLoggerFactory
2020
import org.utbot.instrumentation.rd.generated.InvokeMethodCommandParams
2121
import org.utbot.instrumentation.util.ChildProcessError
22-
import org.utbot.rd.terminateOnException
2322
import java.io.Closeable
2423
import java.util.concurrent.atomic.AtomicLong
2524
import kotlin.concurrent.thread
@@ -101,7 +100,7 @@ class ConcreteExecutor<TIResult, TInstrumentation : Instrumentation<TIResult>> p
101100
internal val pathsToUserClasses: String,
102101
internal val pathsToDependencyClasses: String
103102
) : Closeable, Executor<TIResult> {
104-
private val def: LifetimeDefinition = LifetimeDefinition()
103+
private val ldef: LifetimeDefinition = LifetimeDefinition()
105104
private val childProcessRunner: ChildProcessRunner = ChildProcessRunner()
106105

107106
companion object {
@@ -141,32 +140,30 @@ class ConcreteExecutor<TIResult, TInstrumentation : Instrumentation<TIResult>> p
141140

142141
//property that signals to executors pool whether it can reuse this executor or not
143142
val alive: Boolean
144-
get() = def.isAlive
143+
get() = ldef.isAlive
145144

146145
private val corMutex = Mutex()
147146
private var processInstance: UtInstrumentationProcess? = null
148147

149148
// this function is intended to be called under corMutex
150149
private suspend fun regenerate(): UtInstrumentationProcess {
150+
ldef.throwIfNotAlive()
151151

152-
def.throwIfNotAlive()
153-
var proc : UtInstrumentationProcess? = processInstance
152+
var proc: UtInstrumentationProcess? = processInstance
154153

155154
if (proc == null || !proc.lifetime.isAlive) {
156-
def.createNested().terminateOnException {
157-
proc = UtInstrumentationProcess(
158-
it,
159-
childProcessRunner,
160-
instrumentation,
161-
pathsToUserClasses,
162-
pathsToDependencyClasses,
163-
classLoader
164-
)
165-
processInstance = proc
166-
}
155+
proc = UtInstrumentationProcess(
156+
ldef,
157+
childProcessRunner,
158+
instrumentation,
159+
pathsToUserClasses,
160+
pathsToDependencyClasses,
161+
classLoader
162+
)
163+
processInstance = proc
167164
}
168165

169-
return proc!!
166+
return proc
170167
}
171168

172169
/**
@@ -271,7 +268,7 @@ class ConcreteExecutor<TIResult, TInstrumentation : Instrumentation<TIResult>> p
271268
} catch (_: Exception) {}
272269
processInstance = null
273270
}
274-
def.terminate()
271+
ldef.terminate()
275272
}
276273
}
277274
}

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/process/ChildProcess.kt

Lines changed: 59 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.utbot.instrumentation.process
22

33
import com.jetbrains.rd.framework.*
4+
import com.jetbrains.rd.framework.impl.RdCall
45
import com.jetbrains.rd.framework.util.launchChild
56
import com.jetbrains.rd.util.ILoggerFactory
67
import com.jetbrains.rd.util.LogLevel
@@ -24,23 +25,22 @@ import org.utbot.instrumentation.rd.processSyncDirectory
2425
import org.utbot.instrumentation.rd.signalChildReady
2526
import org.utbot.instrumentation.util.KryoHelper
2627
import org.utbot.rd.UtSingleThreadScheduler
28+
import org.utbot.rd.adviseForConditionAsync
2729
import java.io.File
2830
import java.io.OutputStream
2931
import java.io.PrintStream
3032
import java.net.URLClassLoader
3133
import java.security.AllPermission
3234
import java.time.LocalDateTime
3335
import java.time.format.DateTimeFormatter
34-
import java.util.concurrent.CountDownLatch
35-
import java.util.concurrent.TimeUnit
3636
import java.util.concurrent.atomic.AtomicLong
3737
import kotlin.system.measureTimeMillis
3838

3939
/**
4040
* We use this ClassLoader to separate user's classes and our dependency classes.
4141
* Our classes won't be instrumented.
4242
*/
43-
internal object HandlerClassesLoader : URLClassLoader(emptyArray()) {
43+
private object HandlerClassesLoader : URLClassLoader(emptyArray()) {
4444
fun addUrls(urls: Iterable<String>) {
4545
urls.forEach { super.addURL(File(it).toURI().toURL()) }
4646
}
@@ -59,7 +59,7 @@ internal object HandlerClassesLoader : URLClassLoader(emptyArray()) {
5959
}
6060
}
6161

62-
typealias ChildProcessLogLevel = LogLevel
62+
private typealias ChildProcessLogLevel = LogLevel
6363

6464
private val logLevel = ChildProcessLogLevel.Trace
6565

@@ -142,7 +142,7 @@ suspend fun main(args: Array<String>) {
142142
}
143143
}
144144

145-
fun <T> measureExecutionForTermination(block: () -> T): T {
145+
private fun <T> measureExecutionForTermination(block: () -> T): T {
146146
try {
147147
executionStart.set(System.currentTimeMillis())
148148
return block()
@@ -156,63 +156,58 @@ private lateinit var pathsToUserClasses: Set<String>
156156
private lateinit var pathsToDependencyClasses: Set<String>
157157
private lateinit var instrumentation: Instrumentation<*>
158158

159-
fun ProtocolModel.setup(kryoHelper: KryoHelper, onStop: () -> Unit) {
160-
warmup.set { _ ->
161-
measureExecutionForTermination {
162-
val time = measureTimeMillis {
163-
HandlerClassesLoader.scanForClasses("").toList() // here we transform classes
164-
}
165-
logInfo { "warmup finished in $time ms" }
159+
private fun <T, R> RdCall<T, R>.measureExecutionForTermination(block: (T) -> R) {
160+
this.set { it ->
161+
measureExecutionForTermination<R> {
162+
block(it)
166163
}
167164
}
168-
invokeMethodCommand.set { params ->
169-
measureExecutionForTermination {
170-
val clazz = HandlerClassesLoader.loadClass(params.classname)
171-
val res = instrumentation.invoke(
172-
clazz,
173-
params.signature,
174-
kryoHelper.readObject(params.arguments),
175-
kryoHelper.readObject(params.parameters)
176-
)
177-
178-
logInfo { "sent cmd: $res" }
179-
InvokeMethodCommandResult(kryoHelper.writeObject(res))
165+
}
166+
167+
private fun ProtocolModel.setup(kryoHelper: KryoHelper, onStop: () -> Unit) {
168+
warmup.measureExecutionForTermination {
169+
val time = measureTimeMillis {
170+
HandlerClassesLoader.scanForClasses("").toList() // here we transform classes
180171
}
172+
logInfo { "warmup finished in $time ms" }
181173
}
182-
setInstrumentation.set { params ->
183-
measureExecutionForTermination {
184-
instrumentation = kryoHelper.readObject(params.instrumentation)
185-
Agent.dynamicClassTransformer.transformer = instrumentation // classTransformer is set
186-
Agent.dynamicClassTransformer.addUserPaths(pathsToUserClasses)
187-
instrumentation.init(pathsToUserClasses)
188-
}
174+
invokeMethodCommand.measureExecutionForTermination { params ->
175+
val clazz = HandlerClassesLoader.loadClass(params.classname)
176+
val res = instrumentation.invoke(
177+
clazz,
178+
params.signature,
179+
kryoHelper.readObject(params.arguments),
180+
kryoHelper.readObject(params.parameters)
181+
)
182+
183+
logInfo { "sent cmd: $res" }
184+
InvokeMethodCommandResult(kryoHelper.writeObject(res))
189185
}
190-
addPaths.set { params ->
191-
measureExecutionForTermination {
192-
pathsToUserClasses = params.pathsToUserClasses.split(File.pathSeparatorChar).toSet()
193-
pathsToDependencyClasses = params.pathsToDependencyClasses.split(File.pathSeparatorChar).toSet()
194-
HandlerClassesLoader.addUrls(pathsToUserClasses)
195-
HandlerClassesLoader.addUrls(pathsToDependencyClasses)
196-
kryoHelper.setKryoClassLoader(HandlerClassesLoader) // Now kryo will use our classloader when it encounters unregistered class.
186+
setInstrumentation.measureExecutionForTermination { params ->
187+
instrumentation = kryoHelper.readObject(params.instrumentation)
188+
Agent.dynamicClassTransformer.transformer = instrumentation // classTransformer is set
189+
Agent.dynamicClassTransformer.addUserPaths(pathsToUserClasses)
190+
instrumentation.init(pathsToUserClasses)
191+
}
192+
addPaths.measureExecutionForTermination { params ->
193+
pathsToUserClasses = params.pathsToUserClasses.split(File.pathSeparatorChar).toSet()
194+
pathsToDependencyClasses = params.pathsToDependencyClasses.split(File.pathSeparatorChar).toSet()
195+
HandlerClassesLoader.addUrls(pathsToUserClasses)
196+
HandlerClassesLoader.addUrls(pathsToDependencyClasses)
197+
kryoHelper.setKryoClassLoader(HandlerClassesLoader) // Now kryo will use our classloader when it encounters unregistered class.
197198

198-
logTrace { "User classes:" + pathsToUserClasses.joinToString() }
199+
logTrace { "User classes:" + pathsToUserClasses.joinToString() }
199200

200-
UtContext.setUtContext(UtContext(HandlerClassesLoader))
201-
}
201+
UtContext.setUtContext(UtContext(HandlerClassesLoader))
202202
}
203-
stopProcess.set { _ ->
204-
measureExecutionForTermination {
205-
onStop()
206-
}
203+
stopProcess.measureExecutionForTermination {
204+
onStop()
207205
}
208-
collectCoverage.set { params ->
209-
measureExecutionForTermination {
210-
val anyClass: Class<*> = kryoHelper.readObject(params.clazz)
211-
val result = (instrumentation as CoverageInstrumentation).collectCoverageInfo(anyClass)
212-
CollectCoverageResult(kryoHelper.writeObject(result))
213-
}
206+
collectCoverage.measureExecutionForTermination { params ->
207+
val anyClass: Class<*> = kryoHelper.readObject(params.clazz)
208+
val result = (instrumentation as CoverageInstrumentation).collectCoverageInfo(anyClass)
209+
CollectCoverageResult(kryoHelper.writeObject(result))
214210
}
215-
216211
}
217212

218213
private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
@@ -264,20 +259,22 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
264259
signalChildReady(pid)
265260
logInfo { "IO obtained" }
266261

267-
val latch = CountDownLatch(1)
268-
sync.advise(lifetime) {
262+
val answerFromMainProcess = sync.adviseForConditionAsync(lifetime) {
269263
if (it == "main") {
270-
sync.fire("child")
271-
latch.countDown()
264+
measureExecutionForTermination {
265+
sync.fire("child")
266+
}
267+
true
268+
} else {
269+
false
272270
}
273271
}
274272

275-
if (latch.await(messageFromMainTimeoutMillis.toLong(), TimeUnit.MILLISECONDS)) {
273+
try {
274+
answerFromMainProcess.await()
276275
logInfo { "starting instrumenting" }
277-
try {
278-
deferred.await()
279-
} catch (e: Throwable) {
280-
logError { "Terminating process because exception occurred: ${e.stackTraceToString()}" }
281-
}
276+
deferred.await()
277+
} catch (e: Throwable) {
278+
logError { "Terminating process because exception occurred: ${e.stackTraceToString()}" }
282279
}
283280
}

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/rd/InstrumentationIO.kt

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,20 @@ import com.jetbrains.rd.util.lifetime.Lifetime
77
import org.utbot.common.utBotTempDirectory
88
import org.utbot.instrumentation.rd.generated.ProtocolModel
99
import org.utbot.instrumentation.rd.generated.protocolModel
10+
import org.utbot.rd.pump
1011
import java.io.File
11-
import java.util.concurrent.CountDownLatch
12-
import java.util.concurrent.TimeUnit
1312

1413
const val rdProcessDirName = "rdProcessSync"
1514
val processSyncDirectory = File(utBotTempDirectory.toFile(), rdProcessDirName)
16-
private val awaitTimeoutMillis: Long = 120 * 1000
1715

18-
internal fun obtainClientIO(lifetime: Lifetime, protocol: Protocol): Pair<RdSignal<String>, ProtocolModel> {
19-
val latch = CountDownLatch(2)
20-
val sync = RdSignal<String>().static(1).init(lifetime, protocol, latch)
21-
22-
protocol.scheduler.invokeOrQueue {
23-
protocol.protocolModel
24-
latch.countDown()
16+
internal suspend fun obtainClientIO(lifetime: Lifetime, protocol: Protocol): Pair<RdSignal<String>, ProtocolModel> {
17+
return protocol.scheduler.pump(lifetime) {
18+
val sync = RdSignal<String>().static(1).apply {
19+
async = true
20+
bind(lifetime, protocol, rdid.toString())
21+
}
22+
sync to protocol.protocolModel
2523
}
26-
27-
if (!latch.await(awaitTimeoutMillis, TimeUnit.MILLISECONDS))
28-
throw IllegalStateException("Cannot bind signals")
29-
30-
return sync to protocol.protocolModel
3124
}
3225

3326
internal fun childCreatedFileName(pid: Int): String {
@@ -48,14 +41,4 @@ internal fun signalChildReady(pid: Int) {
4841
if (!created) {
4942
throw IllegalStateException("cannot create signal file")
5043
}
51-
}
52-
53-
private fun <T> RdSignal<T>.init(lifetime: Lifetime, protocol: Protocol, latch: CountDownLatch): RdSignal<T> {
54-
return this.apply {
55-
async = true
56-
protocol.scheduler.invokeOrQueue {
57-
this.bind(lifetime, protocol, rdid.toString())
58-
latch.countDown()
59-
}
60-
}
6144
}

0 commit comments

Comments
 (0)