1
0
Fork 0
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:
Luca Casonato 2021-09-27 12:18:02 +02:00 committed by GitHub
parent 0964685486
commit ff3a17b72d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 36 deletions

View file

@ -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();
}); });

View file

@ -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(())
} }

View file

@ -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,