diff options
author | Divy Srivastava <dj.srivastava23@gmail.com> | 2024-04-20 18:55:07 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-04-20 18:55:07 +0530 |
commit | c0f40ed81a1c932f804ba62e635249cd43c31273 (patch) | |
tree | a8ce324f17f819eb62fe93199664886b769d9c5f | |
parent | 04c6785faecdef37b3d4eefb61c0a18ff1cbdec0 (diff) |
fix(ext/node): implement process.kill in Rust (#23130)
Closes https://github.com/denoland/deno/issues/23056
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | ext/node/Cargo.toml | 1 | ||||
-rw-r--r-- | ext/node/lib.rs | 3 | ||||
-rw-r--r-- | ext/node/ops/mod.rs | 1 | ||||
-rw-r--r-- | ext/node/ops/os/mod.rs | 5 | ||||
-rw-r--r-- | ext/node/ops/process.rs | 64 | ||||
-rw-r--r-- | ext/node/polyfills/process.ts | 57 | ||||
-rw-r--r-- | tests/unit_node/process_test.ts | 12 |
8 files changed, 94 insertions, 50 deletions
diff --git a/Cargo.lock b/Cargo.lock index c6748e5b4..9f499aa2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1684,6 +1684,7 @@ dependencies = [ "deno_fs", "deno_media_type", "deno_net", + "deno_permissions", "deno_whoami", "digest", "dsa", diff --git a/ext/node/Cargo.toml b/ext/node/Cargo.toml index 928968a9e..c4fcbd3ac 100644 --- a/ext/node/Cargo.toml +++ b/ext/node/Cargo.toml @@ -26,6 +26,7 @@ deno_fetch.workspace = true deno_fs.workspace = true deno_media_type.workspace = true deno_net.workspace = true +deno_permissions.workspace = true deno_whoami = "0.1.0" digest = { version = "0.10.5", features = ["core-api", "std"] } dsa = "0.6.1" diff --git a/ext/node/lib.rs b/ext/node/lib.rs index f91ed0b1a..c99467d23 100644 --- a/ext/node/lib.rs +++ b/ext/node/lib.rs @@ -307,7 +307,6 @@ deno_core::extension!(deno_node, ops::os::op_node_os_username<P>, ops::os::op_geteuid<P>, ops::os::op_cpus<P>, - ops::os::op_process_abort, op_node_build_os, op_node_is_promise_rejected, op_npm_process_state, @@ -340,6 +339,8 @@ deno_core::extension!(deno_node, ops::ipc::op_node_child_ipc_pipe, ops::ipc::op_node_ipc_write, ops::ipc::op_node_ipc_read, + ops::process::op_node_process_kill, + ops::process::op_process_abort, ], esm_entry_point = "ext:deno_node/02_init.js", esm = [ diff --git a/ext/node/ops/mod.rs b/ext/node/ops/mod.rs index c14b63bf4..6381530dd 100644 --- a/ext/node/ops/mod.rs +++ b/ext/node/ops/mod.rs @@ -7,6 +7,7 @@ pub mod http2; pub mod idna; pub mod ipc; pub mod os; +pub mod process; pub mod require; pub mod util; pub mod v8; diff --git a/ext/node/ops/os/mod.rs b/ext/node/ops/os/mod.rs index 1d3de797b..603f678e0 100644 --- a/ext/node/ops/os/mod.rs +++ b/ext/node/ops/os/mod.rs @@ -75,11 +75,6 @@ where Ok(euid) } -#[op2(fast)] -pub fn op_process_abort() { - std::process::abort(); -} - #[op2] #[serde] pub fn op_cpus<P>(state: &mut OpState) -> Result<Vec<cpus::CpuInfo>, AnyError> diff --git a/ext/node/ops/process.rs b/ext/node/ops/process.rs new file mode 100644 index 000000000..0992c46c6 --- /dev/null +++ b/ext/node/ops/process.rs @@ -0,0 +1,64 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use deno_core::error::AnyError; +use deno_core::op2; +use deno_core::OpState; +use deno_permissions::PermissionsContainer; + +#[cfg(unix)] +fn kill(pid: i32, sig: i32) -> i32 { + // SAFETY: FFI call to libc + if unsafe { libc::kill(pid, sig) } < 0 { + std::io::Error::last_os_error().raw_os_error().unwrap() + } else { + 0 + } +} + +#[cfg(not(unix))] +fn kill(pid: i32, _sig: i32) -> i32 { + use winapi::shared::minwindef::DWORD; + use winapi::shared::minwindef::FALSE; + use winapi::shared::minwindef::TRUE; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::processthreadsapi::GetCurrentProcess; + use winapi::um::processthreadsapi::OpenProcess; + use winapi::um::processthreadsapi::TerminateProcess; + use winapi::um::winnt::PROCESS_TERMINATE; + + // SAFETY: FFI call to winapi + unsafe { + let p_hnd = if pid == 0 { + GetCurrentProcess() + } else { + OpenProcess(PROCESS_TERMINATE, FALSE, pid as DWORD) + }; + + if p_hnd.is_null() { + return GetLastError() as i32; + } + + if TerminateProcess(p_hnd, 1) == TRUE { + return 0; + } + + GetLastError() as i32 + } +} + +#[op2(fast)] +pub fn op_node_process_kill( + state: &mut OpState, + #[smi] pid: i32, + #[smi] sig: i32, +) -> Result<i32, AnyError> { + state + .borrow_mut::<PermissionsContainer>() + .check_run_all("process.kill")?; + Ok(kill(pid, sig)) +} + +#[op2(fast)] +pub fn op_process_abort() { + std::process::abort(); +} diff --git a/ext/node/polyfills/process.ts b/ext/node/polyfills/process.ts index b89b7af52..7f522386c 100644 --- a/ext/node/polyfills/process.ts +++ b/ext/node/polyfills/process.ts @@ -5,9 +5,14 @@ // deno-lint-ignore-file prefer-primordials import { core, internals } from "ext:core/mod.js"; -import { op_geteuid, op_process_abort, op_set_exit_code } from "ext:core/ops"; +import { + op_geteuid, + op_node_process_kill, + op_process_abort, + op_set_exit_code, +} from "ext:core/ops"; -import { notImplemented, warnNotImplemented } from "ext:deno_node/_utils.ts"; +import { warnNotImplemented } from "ext:deno_node/_utils.ts"; import { EventEmitter } from "node:events"; import Module from "node:module"; import { report } from "ext:deno_node/internal/process/report.ts"; @@ -43,7 +48,6 @@ import { } from "ext:deno_node/_next_tick.ts"; import { isWindows } from "ext:deno_node/_util/os.ts"; import * as io from "ext:deno_io/12_io.js"; -import { Command } from "ext:runtime/40_process.js"; export let argv0 = ""; @@ -254,49 +258,14 @@ memoryUsage.rss = function (): number { // Returns a negative error code than can be recognized by errnoException function _kill(pid: number, sig: number): number { - let errCode; - - if (sig === 0) { - let status; - if (Deno.build.os === "windows") { - status = (new Command("powershell.exe", { - args: ["Get-Process", "-pid", pid], - })).outputSync(); - } else { - status = (new Command("kill", { - args: ["-0", pid], - })).outputSync(); - } - - if (!status.success) { - errCode = uv.codeMap.get("ESRCH"); - } - } else { - // Reverse search the shortname based on the numeric code - const maybeSignal = Object.entries(constants.os.signals).find(( - [_, numericCode], - ) => numericCode === sig); + const maybeSignal = Object.entries(constants.os.signals).find(( + [_, numericCode], + ) => numericCode === sig); - if (!maybeSignal) { - errCode = uv.codeMap.get("EINVAL"); - } else { - try { - Deno.kill(pid, maybeSignal[0] as Deno.Signal); - } catch (e) { - if (e instanceof TypeError) { - throw notImplemented(maybeSignal[0]); - } - - throw e; - } - } - } - - if (!errCode) { - return 0; - } else { - return errCode; + if (!maybeSignal) { + return uv.codeMap.get("EINVAL"); } + return op_node_process_kill(pid, sig); } export function dlopen(module, filename, _flags) { diff --git a/tests/unit_node/process_test.ts b/tests/unit_node/process_test.ts index f32303002..0ae0c2a7a 100644 --- a/tests/unit_node/process_test.ts +++ b/tests/unit_node/process_test.ts @@ -235,6 +235,18 @@ Deno.test({ }, }); +Deno.test( + { permissions: { run: true, read: true } }, + async function processKill() { + const p = new Deno.Command(Deno.execPath(), { + args: ["eval", "setTimeout(() => {}, 10000)"], + }).spawn(); + + process.kill(p.pid); + await p.status; + }, +); + Deno.test({ name: "process.off signal", ignore: Deno.build.os == "windows", |