Skip to content

Java 8 RDgen fix #824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions utbot-core/src/main/kotlin/org/utbot/common/JvmUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.utbot.common

private val javaSpecificationVersion = System.getProperty("java.specification.version")
val isJvm8 = javaSpecificationVersion.equals("1.8")
val isJvm9Plus = !javaSpecificationVersion.contains(".") && javaSpecificationVersion.toInt() >= 9
8 changes: 8 additions & 0 deletions utbot-core/src/main/kotlin/org/utbot/common/OsUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.utbot.common

import java.util.*

private val os = System.getProperty("os.name").lowercase(Locale.getDefault())
val isWindows = os.startsWith("windows")
val isUnix = !isWindows
val isMac = os.startsWith("mac")
70 changes: 70 additions & 0 deletions utbot-core/src/main/kotlin/org/utbot/common/ProcessUtil.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.utbot.common

import com.sun.jna.Library
import com.sun.jna.Native
import com.sun.jna.Pointer
import com.sun.jna.platform.win32.Kernel32
import com.sun.jna.platform.win32.WinNT

/**
* working pid for jvm 8 and 9+
*/
val Process.getPid: Long
get() = try {
if (isJvm9Plus) {
// because we cannot reference Java9+ API here
ClassLoader.getSystemClassLoader().loadClass("java.lang.Process").getDeclaredMethod("pid").invoke(this) as Long
} else {
when (javaClass.name) {
"java.lang.UNIXProcess" -> {
val fPid = javaClass.getDeclaredField("pid")
fPid.withAccessibility { fPid.getLong(this) }

}

"java.lang.Win32Process", "java.lang.ProcessImpl" -> {
val fHandle = javaClass.getDeclaredField("handle")
fHandle.withAccessibility {
val handle = fHandle.getLong(this)
val winntHandle = WinNT.HANDLE()
winntHandle.pointer = Pointer.createConstant(handle)
Kernel32.INSTANCE.GetProcessId(winntHandle).toLong()
}
}

else -> -2
}
}
} catch (e: Exception) {
-1
}

private interface CLibrary : Library {
fun getpid(): Int

companion object {
val INSTANCE = Native.load("c", CLibrary::class.java) as CLibrary
}
}

/**
* working for jvm 8 and 9+
*/
val currentProcessPid: Long
get() =
try {
if (isJvm9Plus) {
ClassLoader.getSystemClassLoader().loadClass("java.lang.ProcessHandle").let {
val handle = it.getDeclaredMethod("current").invoke(it)
it.getDeclaredMethod("pid").invoke(handle) as Long
}
} else {
if (isWindows) {
Kernel32.INSTANCE.GetCurrentProcessId()
} else {
CLibrary.INSTANCE.getpid()
}.toLong()
}
} catch (e: Throwable) {
-1
}
1 change: 1 addition & 0 deletions utbot-instrumentation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies {

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


// TODO: this is necessary for inline classes mocking in UtExecutionInstrumentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.jetbrains.rd.util.lifetime.plusAssign
import com.jetbrains.rd.util.threading.SingleThreadScheduler
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import org.utbot.common.scanForClasses
import org.utbot.common.*
import org.utbot.framework.plugin.api.util.UtContext
import org.utbot.instrumentation.agent.Agent
import org.utbot.instrumentation.instrumentation.Instrumentation
Expand Down Expand Up @@ -64,7 +64,7 @@ private object HandlerClassesLoader : URLClassLoader(emptyArray()) {

private typealias ChildProcessLogLevel = LogLevel

private val logLevel = ChildProcessLogLevel.Trace
private val logLevel = ChildProcessLogLevel.Info

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

val pid = ProcessHandle.current().pid().toInt()
val pid = currentProcessPid.toInt()
val def = LifetimeDefinition()

SingleThreadScheduler(Lifetime.Eternal, "")
Expand Down Expand Up @@ -146,6 +146,7 @@ suspend fun main(args: Array<String>) = runBlocking {
lifetime += { logInfo { "lifetime terminated" } }
try {
logInfo {"pid - $pid"}
logInfo {"isJvm8 - $isJvm8, isJvm9Plus - $isJvm9Plus, isWindows - $isWindows"}
initiate(lifetime, port, pid)
} finally {
val syncFile = File(processSyncDirectory, childCreatedFileName(pid))
Expand Down Expand Up @@ -264,11 +265,6 @@ private suspend fun initiate(lifetime: Lifetime, port: Int, pid: Int) {
SocketWire.Client(lifetime, scheduler, port),
lifetime
)
logInfo {
"heartbeatAlive - ${clientProtocol.wire.heartbeatAlive.value}, connected - ${
clientProtocol.wire.connected.value
}"
}
val (sync, protocolModel) = obtainClientIO(lifetime, clientProtocol)

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

val answerFromMainProcess = sync.adviseForConditionAsync(lifetime) {
if (it == "main") {
logTrace { "received from main" }
measureExecutionForTermination {
sync.fire("child")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class ChildProcessRunner {
.directory(directory)

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

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

ChildProcessRunner::class.java.classLoader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.jetbrains.rd.util.lifetime.Lifetime
import com.jetbrains.rd.util.lifetime.isAlive
import kotlinx.coroutines.delay
import mu.KotlinLogging
import org.utbot.common.getPid
import org.utbot.instrumentation.instrumentation.Instrumentation
import org.utbot.instrumentation.process.ChildProcessRunner
import org.utbot.instrumentation.rd.generated.AddPathsParams
Expand Down Expand Up @@ -53,7 +54,7 @@ class UtInstrumentationProcess private constructor(
// 1. child process will create file "${processId}.created" - this indicates that child process is ready to receive messages
// 2. we will test the connection via sync RdSignal
// only then we can successfully start operating
val pid = process.toHandle().pid().toInt()
val pid = process.getPid.toInt()
val syncFile = File(processSyncDirectory, childCreatedFileName(pid))

while (lifetime.isAlive) {
Expand Down