1
1
package org.utbot.instrumentation.process
2
2
3
+ import com.jetbrains.rd.framework.*
3
4
import com.jetbrains.rd.framework.util.launchChild
4
5
import com.jetbrains.rd.util.ILoggerFactory
5
6
import com.jetbrains.rd.util.LogLevel
@@ -17,11 +18,11 @@ import org.utbot.instrumentation.instrumentation.coverage.CoverageInstrumentatio
17
18
import org.utbot.instrumentation.rd.childCreatedFileName
18
19
import org.utbot.instrumentation.rd.generated.CollectCoverageResult
19
20
import org.utbot.instrumentation.rd.generated.InvokeMethodCommandResult
21
+ import org.utbot.instrumentation.rd.generated.ProtocolModel
20
22
import org.utbot.instrumentation.rd.obtainClientIO
21
23
import org.utbot.instrumentation.rd.processSyncDirectory
22
24
import org.utbot.instrumentation.rd.signalChildReady
23
25
import org.utbot.instrumentation.util.KryoHelper
24
- import org.utbot.rd.UtRdUtil
25
26
import org.utbot.rd.UtSingleThreadScheduler
26
27
import java.io.File
27
28
import java.io.OutputStream
@@ -86,6 +87,7 @@ private fun logTrace(any: () -> Any?) {
86
87
private val executionStart = AtomicLong (1 )
87
88
private val executionEnd = AtomicLong (0 )
88
89
private const val messageFromMainTimeoutMillis = 120 * 1000
90
+ private const val delayTimeoutMillis = 1000L
89
91
90
92
/* *
91
93
* It should be compiled into separate jar file (child_process.jar) and be run with an agent (agent.jar) option.
@@ -111,7 +113,7 @@ suspend fun main(args: Array<String>) {
111
113
val end = executionEnd.get()
112
114
113
115
if (start > end) { // process is doing something
114
- delay(1000 )
116
+ delay(delayTimeoutMillis )
115
117
} else { // process is waiting for message
116
118
if (now - end > messageFromMainTimeoutMillis) {
117
119
logInfo { " terminating lifetime" }
@@ -154,49 +156,16 @@ private lateinit var pathsToUserClasses: Set<String>
154
156
private lateinit var pathsToDependencyClasses: Set <String >
155
157
private lateinit var instrumentation: Instrumentation <* >
156
158
157
- private suspend fun initiate (lifetime : Lifetime , port : Int , pid : Int ) {
158
- // We don't want user code to litter the standard output, so we redirect it.
159
- val tmpStream = PrintStream (object : OutputStream () {
160
- override fun write (b : Int ) {}
161
- })
162
- System .setOut(tmpStream)
163
-
164
- Logger .set(lifetime, object : ILoggerFactory {
165
- override fun getLogger (category : String ) = object : Logger {
166
- override fun isEnabled (level : LogLevel ): Boolean {
167
- return level >= logLevel
168
- }
169
-
170
- override fun log (level : LogLevel , message : Any? , throwable : Throwable ? ) {
171
- val msg = defaultLogFormat(category, level, message, throwable)
172
-
173
- log(logLevel) { msg }
174
- }
175
-
176
- }
177
- })
178
-
179
- val def = CompletableDeferred <Unit >()
180
- lifetime.onTermination { def.complete(Unit ) }
181
- val kryoHelper = KryoHelper (lifetime)
182
- logInfo { " kryo created" }
183
-
184
- val clientProtocol = UtRdUtil .createUtClientProtocol(lifetime, port, UtSingleThreadScheduler { logInfo(it) })
185
- logInfo {
186
- " heartbeatAlive - ${clientProtocol.wire.heartbeatAlive.value} , connected - ${
187
- clientProtocol.wire.connected.value
188
- } "
189
- }
190
- val (sync, protocolModel) = obtainClientIO(lifetime, clientProtocol)
191
- protocolModel.warmup.set { _ ->
159
+ fun ProtocolModel.setup (kryoHelper : KryoHelper , onStop : () -> Unit ) {
160
+ warmup.set { _ ->
192
161
measureExecutionForTermination {
193
162
val time = measureTimeMillis {
194
163
HandlerClassesLoader .scanForClasses(" " ).toList() // here we transform classes
195
164
}
196
165
logInfo { " warmup finished in $time ms" }
197
166
}
198
167
}
199
- protocolModel. invokeMethodCommand.set { params ->
168
+ invokeMethodCommand.set { params ->
200
169
measureExecutionForTermination {
201
170
val clazz = HandlerClassesLoader .loadClass(params.classname)
202
171
val res = instrumentation.invoke(
@@ -210,15 +179,15 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
210
179
InvokeMethodCommandResult (kryoHelper.writeObject(res))
211
180
}
212
181
}
213
- protocolModel. setInstrumentation.set { params ->
182
+ setInstrumentation.set { params ->
214
183
measureExecutionForTermination {
215
184
instrumentation = kryoHelper.readObject(params.instrumentation)
216
185
Agent .dynamicClassTransformer.transformer = instrumentation // classTransformer is set
217
186
Agent .dynamicClassTransformer.addUserPaths(pathsToUserClasses)
218
187
instrumentation.init (pathsToUserClasses)
219
188
}
220
189
}
221
- protocolModel. addPaths.set { params ->
190
+ addPaths.set { params ->
222
191
measureExecutionForTermination {
223
192
pathsToUserClasses = params.pathsToUserClasses.split(File .pathSeparatorChar).toSet()
224
193
pathsToDependencyClasses = params.pathsToDependencyClasses.split(File .pathSeparatorChar).toSet()
@@ -231,18 +200,67 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
231
200
UtContext .setUtContext(UtContext (HandlerClassesLoader ))
232
201
}
233
202
}
234
- protocolModel. stopProcess.set { _ ->
203
+ stopProcess.set { _ ->
235
204
measureExecutionForTermination {
236
- def.complete( Unit )
205
+ onStop( )
237
206
}
238
207
}
239
- protocolModel. collectCoverage.set { params ->
208
+ collectCoverage.set { params ->
240
209
measureExecutionForTermination {
241
210
val anyClass: Class <* > = kryoHelper.readObject(params.clazz)
242
211
val result = (instrumentation as CoverageInstrumentation ).collectCoverageInfo(anyClass)
243
212
CollectCoverageResult (kryoHelper.writeObject(result))
244
213
}
245
214
}
215
+
216
+ }
217
+
218
+ private suspend fun initiate (lifetime : Lifetime , port : Int , pid : Int ) {
219
+ // We don't want user code to litter the standard output, so we redirect it.
220
+ val tmpStream = PrintStream (object : OutputStream () {
221
+ override fun write (b : Int ) {}
222
+ })
223
+ System .setOut(tmpStream)
224
+
225
+ Logger .set(lifetime, object : ILoggerFactory {
226
+ override fun getLogger (category : String ) = object : Logger {
227
+ override fun isEnabled (level : LogLevel ): Boolean {
228
+ return level >= logLevel
229
+ }
230
+
231
+ override fun log (level : LogLevel , message : Any? , throwable : Throwable ? ) {
232
+ val msg = defaultLogFormat(category, level, message, throwable)
233
+
234
+ log(logLevel) { msg }
235
+ }
236
+
237
+ }
238
+ })
239
+
240
+ val deferred = CompletableDeferred <Unit >()
241
+ lifetime.onTermination { deferred.complete(Unit ) }
242
+ val kryoHelper = KryoHelper (lifetime)
243
+ logInfo { " kryo created" }
244
+
245
+ val scheduler = UtSingleThreadScheduler { logInfo(it) }
246
+ val clientProtocol = Protocol (
247
+ " ChildProcess" ,
248
+ Serializers (),
249
+ Identities (IdKind .Client ),
250
+ scheduler,
251
+ SocketWire .Client (lifetime, scheduler, port),
252
+ lifetime
253
+ )
254
+ logInfo {
255
+ " heartbeatAlive - ${clientProtocol.wire.heartbeatAlive.value} , connected - ${
256
+ clientProtocol.wire.connected.value
257
+ } "
258
+ }
259
+ val (sync, protocolModel) = obtainClientIO(lifetime, clientProtocol)
260
+
261
+ protocolModel.setup(kryoHelper) {
262
+ deferred.complete(Unit )
263
+ }
246
264
signalChildReady(pid)
247
265
logInfo { " IO obtained" }
248
266
@@ -257,7 +275,7 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
257
275
if (latch.await(messageFromMainTimeoutMillis.toLong(), TimeUnit .MILLISECONDS )) {
258
276
logInfo { " starting instrumenting" }
259
277
try {
260
- def .await()
278
+ deferred .await()
261
279
} catch (e: Throwable ) {
262
280
logError { " Terminating process because exception occurred: ${e.stackTraceToString()} " }
263
281
}
0 commit comments