Skip to content

Commit 248c196

Browse files
authored
Java 8 RDgen fix (#824)
Fix for java 8 after rdgen
1 parent 54337ca commit 248c196

File tree

7 files changed

+93
-11
lines changed

7 files changed

+93
-11
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package org.utbot.common
2+
3+
private val javaSpecificationVersion = System.getProperty("java.specification.version")
4+
val isJvm8 = javaSpecificationVersion.equals("1.8")
5+
val isJvm9Plus = !javaSpecificationVersion.contains(".") && javaSpecificationVersion.toInt() >= 9
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.utbot.common
2+
3+
import java.util.*
4+
5+
private val os = System.getProperty("os.name").lowercase(Locale.getDefault())
6+
val isWindows = os.startsWith("windows")
7+
val isUnix = !isWindows
8+
val isMac = os.startsWith("mac")
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package org.utbot.common
2+
3+
import com.sun.jna.Library
4+
import com.sun.jna.Native
5+
import com.sun.jna.Pointer
6+
import com.sun.jna.platform.win32.Kernel32
7+
import com.sun.jna.platform.win32.WinNT
8+
9+
/**
10+
* working pid for jvm 8 and 9+
11+
*/
12+
val Process.getPid: Long
13+
get() = try {
14+
if (isJvm9Plus) {
15+
// because we cannot reference Java9+ API here
16+
ClassLoader.getSystemClassLoader().loadClass("java.lang.Process").getDeclaredMethod("pid").invoke(this) as Long
17+
} else {
18+
when (javaClass.name) {
19+
"java.lang.UNIXProcess" -> {
20+
val fPid = javaClass.getDeclaredField("pid")
21+
fPid.withAccessibility { fPid.getLong(this) }
22+
23+
}
24+
25+
"java.lang.Win32Process", "java.lang.ProcessImpl" -> {
26+
val fHandle = javaClass.getDeclaredField("handle")
27+
fHandle.withAccessibility {
28+
val handle = fHandle.getLong(this)
29+
val winntHandle = WinNT.HANDLE()
30+
winntHandle.pointer = Pointer.createConstant(handle)
31+
Kernel32.INSTANCE.GetProcessId(winntHandle).toLong()
32+
}
33+
}
34+
35+
else -> -2
36+
}
37+
}
38+
} catch (e: Exception) {
39+
-1
40+
}
41+
42+
private interface CLibrary : Library {
43+
fun getpid(): Int
44+
45+
companion object {
46+
val INSTANCE = Native.load("c", CLibrary::class.java) as CLibrary
47+
}
48+
}
49+
50+
/**
51+
* working for jvm 8 and 9+
52+
*/
53+
val currentProcessPid: Long
54+
get() =
55+
try {
56+
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+
}
61+
} else {
62+
if (isWindows) {
63+
Kernel32.INSTANCE.GetCurrentProcessId()
64+
} else {
65+
CLibrary.INSTANCE.getpid()
66+
}.toLong()
67+
}
68+
} catch (e: Throwable) {
69+
-1
70+
}

utbot-instrumentation/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies {
1313

1414
implementation group: 'com.jetbrains.rd', name: 'rd-framework', version: '2022.3.1'
1515
implementation group: 'com.jetbrains.rd', name: 'rd-core', version: '2022.3.1'
16+
implementation group: 'net.java.dev.jna', name: 'jna-platform', version: '5.5.0'
1617

1718

1819
// TODO: this is necessary for inline classes mocking in UtExecutionInstrumentation

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import com.jetbrains.rd.util.lifetime.plusAssign
1313
import com.jetbrains.rd.util.threading.SingleThreadScheduler
1414
import kotlinx.coroutines.*
1515
import kotlinx.coroutines.channels.Channel
16-
import org.utbot.common.scanForClasses
16+
import org.utbot.common.*
1717
import org.utbot.framework.plugin.api.util.UtContext
1818
import org.utbot.instrumentation.agent.Agent
1919
import org.utbot.instrumentation.instrumentation.Instrumentation
@@ -64,7 +64,7 @@ private object HandlerClassesLoader : URLClassLoader(emptyArray()) {
6464

6565
private typealias ChildProcessLogLevel = LogLevel
6666

67-
private val logLevel = ChildProcessLogLevel.Trace
67+
private val logLevel = ChildProcessLogLevel.Info
6868

6969
// Logging
7070
private val dateFormatter: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss.SSS")
@@ -116,7 +116,7 @@ suspend fun main(args: Array<String>) = runBlocking {
116116
?.run { split("=").last().toInt().coerceIn(1..65535) }
117117
?: throw IllegalArgumentException("No port provided")
118118

119-
val pid = ProcessHandle.current().pid().toInt()
119+
val pid = currentProcessPid.toInt()
120120
val def = LifetimeDefinition()
121121

122122
SingleThreadScheduler(Lifetime.Eternal, "")
@@ -146,6 +146,7 @@ suspend fun main(args: Array<String>) = runBlocking {
146146
lifetime += { logInfo { "lifetime terminated" } }
147147
try {
148148
logInfo {"pid - $pid"}
149+
logInfo {"isJvm8 - $isJvm8, isJvm9Plus - $isJvm9Plus, isWindows - $isWindows"}
149150
initiate(lifetime, port, pid)
150151
} finally {
151152
val syncFile = File(processSyncDirectory, childCreatedFileName(pid))
@@ -264,11 +265,6 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
264265
SocketWire.Client(lifetime, scheduler, port),
265266
lifetime
266267
)
267-
logInfo {
268-
"heartbeatAlive - ${clientProtocol.wire.heartbeatAlive.value}, connected - ${
269-
clientProtocol.wire.connected.value
270-
}"
271-
}
272268
val (sync, protocolModel) = obtainClientIO(lifetime, clientProtocol)
273269

274270
protocolModel.setup(kryoHelper) {
@@ -279,6 +275,7 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
279275

280276
val answerFromMainProcess = sync.adviseForConditionAsync(lifetime) {
281277
if (it == "main") {
278+
logTrace { "received from main" }
282279
measureExecutionForTermination {
283280
sync.fire("child")
284281
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class ChildProcessRunner {
6262
.directory(directory)
6363

6464
return processBuilder.start().also {
65-
logger.debug { "Process started with PID=${it.pid()}" }
65+
logger.debug { "Process started with PID=${it.getPid}" }
6666

6767
if (UtSettings.logConcreteExecutionErrors) {
6868
logger.debug { "Child process error log: ${errorLogFile.absolutePath}" }
@@ -99,7 +99,7 @@ class ChildProcessRunner {
9999
run {
100100
logger.debug("Trying to find jar in the resources.")
101101
val tempDir = utBotTempDirectory.toFile()
102-
val unzippedJarName = "$UTBOT_INSTRUMENTATION-${ProcessHandle.current().pid()}.jar"
102+
val unzippedJarName = "$UTBOT_INSTRUMENTATION-${currentProcessPid}.jar"
103103
val instrumentationJarFile = File(tempDir, unzippedJarName)
104104

105105
ChildProcessRunner::class.java.classLoader

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.jetbrains.rd.util.lifetime.Lifetime
66
import com.jetbrains.rd.util.lifetime.isAlive
77
import kotlinx.coroutines.delay
88
import mu.KotlinLogging
9+
import org.utbot.common.getPid
910
import org.utbot.instrumentation.instrumentation.Instrumentation
1011
import org.utbot.instrumentation.process.ChildProcessRunner
1112
import org.utbot.instrumentation.rd.generated.AddPathsParams
@@ -53,7 +54,7 @@ class UtInstrumentationProcess private constructor(
5354
// 1. child process will create file "${processId}.created" - this indicates that child process is ready to receive messages
5455
// 2. we will test the connection via sync RdSignal
5556
// only then we can successfully start operating
56-
val pid = process.toHandle().pid().toInt()
57+
val pid = process.getPid.toInt()
5758
val syncFile = File(processSyncDirectory, childCreatedFileName(pid))
5859

5960
while (lifetime.isAlive) {

0 commit comments

Comments
 (0)