1
1
package org.utbot.instrumentation.process
2
2
3
3
import com.jetbrains.rd.framework.*
4
+ import com.jetbrains.rd.framework.impl.RdCall
4
5
import com.jetbrains.rd.framework.util.launchChild
5
6
import com.jetbrains.rd.util.ILoggerFactory
6
7
import com.jetbrains.rd.util.LogLevel
@@ -24,23 +25,22 @@ import org.utbot.instrumentation.rd.processSyncDirectory
24
25
import org.utbot.instrumentation.rd.signalChildReady
25
26
import org.utbot.instrumentation.util.KryoHelper
26
27
import org.utbot.rd.UtSingleThreadScheduler
28
+ import org.utbot.rd.adviseForConditionAsync
27
29
import java.io.File
28
30
import java.io.OutputStream
29
31
import java.io.PrintStream
30
32
import java.net.URLClassLoader
31
33
import java.security.AllPermission
32
34
import java.time.LocalDateTime
33
35
import java.time.format.DateTimeFormatter
34
- import java.util.concurrent.CountDownLatch
35
- import java.util.concurrent.TimeUnit
36
36
import java.util.concurrent.atomic.AtomicLong
37
37
import kotlin.system.measureTimeMillis
38
38
39
39
/* *
40
40
* We use this ClassLoader to separate user's classes and our dependency classes.
41
41
* Our classes won't be instrumented.
42
42
*/
43
- internal object HandlerClassesLoader : URLClassLoader(emptyArray()) {
43
+ private object HandlerClassesLoader : URLClassLoader(emptyArray()) {
44
44
fun addUrls (urls : Iterable <String >) {
45
45
urls.forEach { super .addURL(File (it).toURI().toURL()) }
46
46
}
@@ -59,7 +59,7 @@ internal object HandlerClassesLoader : URLClassLoader(emptyArray()) {
59
59
}
60
60
}
61
61
62
- typealias ChildProcessLogLevel = LogLevel
62
+ private typealias ChildProcessLogLevel = LogLevel
63
63
64
64
private val logLevel = ChildProcessLogLevel .Trace
65
65
@@ -142,7 +142,7 @@ suspend fun main(args: Array<String>) {
142
142
}
143
143
}
144
144
145
- fun <T > measureExecutionForTermination (block : () -> T ): T {
145
+ private fun <T > measureExecutionForTermination (block : () -> T ): T {
146
146
try {
147
147
executionStart.set(System .currentTimeMillis())
148
148
return block()
@@ -156,63 +156,58 @@ private lateinit var pathsToUserClasses: Set<String>
156
156
private lateinit var pathsToDependencyClasses: Set <String >
157
157
private lateinit var instrumentation: Instrumentation <* >
158
158
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)
166
163
}
167
164
}
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
180
171
}
172
+ logInfo { " warmup finished in $time ms" }
181
173
}
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))
189
185
}
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.
197
198
198
- logTrace { " User classes:" + pathsToUserClasses.joinToString() }
199
+ logTrace { " User classes:" + pathsToUserClasses.joinToString() }
199
200
200
- UtContext .setUtContext(UtContext (HandlerClassesLoader ))
201
- }
201
+ UtContext .setUtContext(UtContext (HandlerClassesLoader ))
202
202
}
203
- stopProcess.set { _ ->
204
- measureExecutionForTermination {
205
- onStop()
206
- }
203
+ stopProcess.measureExecutionForTermination {
204
+ onStop()
207
205
}
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))
214
210
}
215
-
216
211
}
217
212
218
213
private suspend fun initiate (lifetime : Lifetime , port : Int , pid : Int ) {
@@ -264,20 +259,22 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
264
259
signalChildReady(pid)
265
260
logInfo { " IO obtained" }
266
261
267
- val latch = CountDownLatch (1 )
268
- sync.advise(lifetime) {
262
+ val answerFromMainProcess = sync.adviseForConditionAsync(lifetime) {
269
263
if (it == " main" ) {
270
- sync.fire(" child" )
271
- latch.countDown()
264
+ measureExecutionForTermination {
265
+ sync.fire(" child" )
266
+ }
267
+ true
268
+ } else {
269
+ false
272
270
}
273
271
}
274
272
275
- if (latch.await(messageFromMainTimeoutMillis.toLong(), TimeUnit .MILLISECONDS )) {
273
+ try {
274
+ answerFromMainProcess.await()
276
275
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()} " }
282
279
}
283
280
}
0 commit comments