Skip to content

Commit

Permalink
Fix bad windows libuv 1.48.0 implementation for Node.js (#111)
Browse files Browse the repository at this point in the history
  • Loading branch information
05nelsonm authored Jun 17, 2024
1 parent 6800f2b commit 6919b64
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ package io.matthewnelson.kmp.process.internal
/** [docs](https://nodejs.org/api/process.html#processpid) */
@JsName("pid")
internal external val process_pid: Int

/** [docs](https://nodejs.org/api/process.html#processversions) */
@JsName("versions")
internal external val process_versions: dynamic
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ internal open external class stream_Readable {
eventName: String,
listener: Function<R>,
): stream_Readable

internal fun destroy()
}

/** [docs](https://nodejs.org/api/stream.html#class-streamwritable) */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package io.matthewnelson.kmp.process.internal

import io.matthewnelson.kmp.file.File
import io.matthewnelson.kmp.file.errorCodeOrNull
import io.matthewnelson.kmp.process.*

internal class NodeJsProcess internal constructor(
Expand All @@ -39,33 +40,90 @@ internal class NodeJsProcess internal constructor(
INIT,
) {

private var _exitCode: Int? = null

override fun destroy(): Process {
val wasDestroyed = !isDestroyed
isDestroyed = true

if (!jsProcess.killed && isAlive) {
// TODO: check result. check error
jsProcess.kill(destroySignal.name)
@Suppress("UNUSED_VARIABLE")
val error: Throwable? = if (!jsProcess.killed && isAlive) {
try {
jsProcess.kill(destroySignal.name)
null
} catch (t: Throwable) {
val code = t.errorCodeOrNull
var destroySelfIfAlive = false

// https://github.com/05nelsonm/kmp-process/issues/108
run {
if (!IsWindows) return@run
if (code != "EPERM") return@run

val (major, minor, patch) = try {
val split = (process_versions["uv"] as String).split('.')
Triple(split[0].toInt(), split[1].toInt(), split[2].toInt())
} catch (_: Throwable) {
return@run
}

// libuv 1.48.0 bad windows implementation
if (major == 1 && minor == 48 && patch == 0) {
destroySelfIfAlive = true
}
}

if (code == "ESRCH") {
destroySelfIfAlive = true
}

var error: Throwable? = t

if (destroySelfIfAlive && isAlive) {
// Still registering as "alive" w/o exit code, but no process
// found with our PID. Unable to kill b/c no process, it's just
// gone... Self-assign exit code and move on.
_exitCode = destroySignal.code
jsProcess.stdin?.end()
jsProcess.stdout?.destroy()
jsProcess.stderr?.destroy()
error = null
}

error
}
} else {
null
}

if (wasDestroyed) jsProcess.unref()

// TODO: Handle errors Issue #109

return this
}

// @Throws(IllegalStateException::class)
override fun exitCode(): Int {
jsProcess.exitCode?.toInt()?.let { return it }
_exitCode?.let { return it }

jsProcess.exitCode?.toInt()?.let {
_exitCode = it
return it
}

jsProcess.signalCode?.let { signal ->
return try {
val code = try {
Signal.valueOf(signal)
} catch (_: IllegalArgumentException) {
destroySignal
}.code

_exitCode = code
return code
}

throw IllegalStateException("Process hasn't exited")
return _exitCode ?: throw IllegalStateException("Process hasn't exited")
}

override fun pid(): Int {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,36 @@ internal constructor(
val hasBeenDestroyed = isDestroyed
isDestroyed = true

if (isAlive) {
val s = when (destroySignal) {
@Suppress("UNUSED_VARIABLE")
val killErrno = if (isAlive) {
val sig = when (destroySignal) {
Signal.SIGTERM -> SIGTERM
Signal.SIGKILL -> SIGKILL
}

kill(pid, s)
var errno = if (kill(pid, sig) == -1) {
errno
} else {
null
}

// Always call isAlive whether there was an error
// or not to ensure _exitCode is set.
if (!isAlive) {
errno = null
}

isAlive
errno
} else {
null
}

try {
@Suppress("UNUSED_VARIABLE")
val closeError = try {
handle.close()
} catch (_: IOException) {
// TODO: exception handler
null
} catch (t: IOException) {
t
}

if (!hasBeenDestroyed) {
Expand All @@ -109,6 +124,8 @@ internal constructor(
?.result
}

// TODO: Handle errors Issue #109

this
}

Expand Down

0 comments on commit 6919b64

Please sign in to comment.