mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 15:24:46 -05:00
fix: subprocess kill support on windows (#12134)
This commit is contained in:
parent
0964685486
commit
ff3a17b72d
3 changed files with 46 additions and 36 deletions
|
@ -114,8 +114,6 @@ unitTest(
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
{
|
{
|
||||||
// No signals on windows.
|
|
||||||
ignore: Deno.build.os === "windows",
|
|
||||||
permissions: { run: true, read: true },
|
permissions: { run: true, read: true },
|
||||||
},
|
},
|
||||||
async function runCommandFailedWithSignal() {
|
async function runCommandFailedWithSignal() {
|
||||||
|
@ -129,8 +127,13 @@ unitTest(
|
||||||
});
|
});
|
||||||
const status = await p.status();
|
const status = await p.status();
|
||||||
assertEquals(status.success, false);
|
assertEquals(status.success, false);
|
||||||
|
if (Deno.build.os === "windows") {
|
||||||
|
assertEquals(status.code, 1);
|
||||||
|
assertEquals(status.signal, undefined);
|
||||||
|
} else {
|
||||||
assertEquals(status.code, 128 + 9);
|
assertEquals(status.code, 128 + 9);
|
||||||
assertEquals(status.signal, 9);
|
assertEquals(status.signal, 9);
|
||||||
|
}
|
||||||
p.close();
|
p.close();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -448,9 +451,11 @@ unitTest(
|
||||||
|
|
||||||
assert(
|
assert(
|
||||||
error instanceof Deno.errors.NotFound ||
|
error instanceof Deno.errors.NotFound ||
|
||||||
// This is not yet implemented on Windows
|
// On Windows, the underlying Windows API may return
|
||||||
|
// `ERROR_ACCESS_DENIED` when the process has exited, but hasn't been
|
||||||
|
// completely cleaned up yet and its `pid` is still valid.
|
||||||
(Deno.build.os === "windows" &&
|
(Deno.build.os === "windows" &&
|
||||||
error instanceof Error && error.message === "not implemented"),
|
error instanceof Deno.errors.PermissionDenied),
|
||||||
);
|
);
|
||||||
|
|
||||||
p.close();
|
p.close();
|
||||||
|
@ -467,6 +472,24 @@ unitTest(function killPermissions() {
|
||||||
}, Deno.errors.PermissionDenied);
|
}, Deno.errors.PermissionDenied);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ ignore: Deno.build.os !== "windows", permissions: { run: true } },
|
||||||
|
function negativePidInvalidWindows() {
|
||||||
|
assertThrows(() => {
|
||||||
|
Deno.kill(-1, "SIGINT");
|
||||||
|
}, TypeError);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
unitTest(
|
||||||
|
{ ignore: Deno.build.os !== "windows", permissions: { run: true } },
|
||||||
|
function invalidSignalNameWindows() {
|
||||||
|
assertThrows(() => {
|
||||||
|
Deno.kill(Deno.pid, "SIGUSR1");
|
||||||
|
}, TypeError);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
unitTest(
|
unitTest(
|
||||||
{ permissions: { run: true, read: true } },
|
{ permissions: { run: true, read: true } },
|
||||||
async function killSuccess() {
|
async function killSuccess() {
|
||||||
|
@ -475,16 +498,14 @@ unitTest(
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (Deno.build.os === "windows") {
|
|
||||||
// currently not implemented
|
|
||||||
assertThrows(() => {
|
|
||||||
Deno.kill(p.pid, "SIGINT");
|
|
||||||
}, Error);
|
|
||||||
} else {
|
|
||||||
Deno.kill(p.pid, "SIGINT");
|
Deno.kill(p.pid, "SIGINT");
|
||||||
const status = await p.status();
|
const status = await p.status();
|
||||||
|
|
||||||
assertEquals(status.success, false);
|
assertEquals(status.success, false);
|
||||||
|
if (Deno.build.os === "windows") {
|
||||||
|
assertEquals(status.code, 1);
|
||||||
|
assertEquals(status.signal, undefined);
|
||||||
|
} else {
|
||||||
assertEquals(status.code, 130);
|
assertEquals(status.code, 130);
|
||||||
assertEquals(status.signal, 2);
|
assertEquals(status.signal, 2);
|
||||||
}
|
}
|
||||||
|
@ -501,11 +522,10 @@ unitTest({ permissions: { run: true, read: true } }, function killFailed() {
|
||||||
assert(!p.stdin);
|
assert(!p.stdin);
|
||||||
assert(!p.stdout);
|
assert(!p.stdout);
|
||||||
|
|
||||||
// windows is currently not implemented so it throws a regular Error saying so
|
|
||||||
assertThrows(() => {
|
assertThrows(() => {
|
||||||
// @ts-expect-error testing runtime error of bad signal
|
// @ts-expect-error testing runtime error of bad signal
|
||||||
Deno.kill(p.pid, "foobar");
|
Deno.kill(p.pid, "foobar");
|
||||||
}, Deno.build.os === "windows" ? Error : TypeError);
|
}, TypeError);
|
||||||
|
|
||||||
p.close();
|
p.close();
|
||||||
});
|
});
|
||||||
|
|
|
@ -257,7 +257,8 @@ async fn op_run_status(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn kill(pid: i32, signo: i32) -> Result<(), AnyError> {
|
pub fn kill(pid: i32, signal: &str) -> Result<(), AnyError> {
|
||||||
|
let signo = super::signal::signal_str_to_int(signal)?;
|
||||||
use nix::sys::signal::{kill as unix_kill, Signal};
|
use nix::sys::signal::{kill as unix_kill, Signal};
|
||||||
use nix::unistd::Pid;
|
use nix::unistd::Pid;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
@ -266,7 +267,7 @@ pub fn kill(pid: i32, signo: i32) -> Result<(), AnyError> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
pub fn kill(pid: i32, signal: i32) -> Result<(), AnyError> {
|
pub fn kill(pid: i32, signal: &str) -> Result<(), AnyError> {
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
use std::io::ErrorKind::NotFound;
|
use std::io::ErrorKind::NotFound;
|
||||||
use winapi::shared::minwindef::DWORD;
|
use winapi::shared::minwindef::DWORD;
|
||||||
|
@ -279,14 +280,10 @@ pub fn kill(pid: i32, signal: i32) -> Result<(), AnyError> {
|
||||||
use winapi::um::processthreadsapi::TerminateProcess;
|
use winapi::um::processthreadsapi::TerminateProcess;
|
||||||
use winapi::um::winnt::PROCESS_TERMINATE;
|
use winapi::um::winnt::PROCESS_TERMINATE;
|
||||||
|
|
||||||
const SIGINT: i32 = 2;
|
if !matches!(signal, "SIGINT" | "SIGKILL" | "SIGTERM") {
|
||||||
const SIGKILL: i32 = 9;
|
Err(type_error(format!("Invalid signal: {}", signal)))
|
||||||
const SIGTERM: i32 = 15;
|
|
||||||
|
|
||||||
if !matches!(signal, SIGINT | SIGKILL | SIGTERM) {
|
|
||||||
Err(type_error("unsupported signal"))
|
|
||||||
} else if pid <= 0 {
|
} else if pid <= 0 {
|
||||||
Err(type_error("unsupported pid"))
|
Err(type_error("Invalid pid"))
|
||||||
} else {
|
} else {
|
||||||
let handle = unsafe { OpenProcess(PROCESS_TERMINATE, FALSE, pid as DWORD) };
|
let handle = unsafe { OpenProcess(PROCESS_TERMINATE, FALSE, pid as DWORD) };
|
||||||
if handle.is_null() {
|
if handle.is_null() {
|
||||||
|
@ -310,12 +307,10 @@ pub fn kill(pid: i32, signal: i32) -> Result<(), AnyError> {
|
||||||
fn op_kill(
|
fn op_kill(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
pid: i32,
|
pid: i32,
|
||||||
signo: String,
|
signal: String,
|
||||||
) -> Result<(), AnyError> {
|
) -> Result<(), AnyError> {
|
||||||
super::check_unstable(state, "Deno.kill");
|
super::check_unstable(state, "Deno.kill");
|
||||||
state.borrow_mut::<Permissions>().run.check_all()?;
|
state.borrow_mut::<Permissions>().run.check_all()?;
|
||||||
|
kill(pid, &signal)?;
|
||||||
let signo = super::signal::signal_str_to_int(&signo)?;
|
|
||||||
kill(pid, signo)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,11 +173,6 @@ pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, AnyError> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
pub fn signal_str_to_int(_s: &str) -> Result<libc::c_int, AnyError> {
|
|
||||||
Err(generic_error("not implemented"))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn op_signal_bind(
|
fn op_signal_bind(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
|
|
Loading…
Reference in a new issue