mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
Implement Deno.kill for windows (#5347)
This commit is contained in:
parent
a054250a2c
commit
eddb916883
5 changed files with 104 additions and 67 deletions
2
cli/js/lib.deno.unstable.d.ts
vendored
2
cli/js/lib.deno.unstable.d.ts
vendored
|
@ -1120,8 +1120,6 @@ declare namespace Deno {
|
|||
*
|
||||
* Deno.kill(p.pid, Deno.Signal.SIGINT);
|
||||
*
|
||||
* Throws Error (not yet implemented) on Windows
|
||||
*
|
||||
* Requires `allow-run` permission. */
|
||||
export function kill(pid: number, signo: number): void;
|
||||
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
import { sendSync, sendAsync } from "./dispatch_json.ts";
|
||||
import { assert } from "../util.ts";
|
||||
import { build } from "../build.ts";
|
||||
|
||||
export function kill(pid: number, signo: number): void {
|
||||
if (build.os === "windows") {
|
||||
throw new Error("Not yet implemented");
|
||||
}
|
||||
sendSync("op_kill", { pid, signo });
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,20 @@ import {
|
|||
assertStrContains,
|
||||
unitTest,
|
||||
} from "./test_util.ts";
|
||||
const { kill, run, readFile, open, makeTempDir, writeFile } = Deno;
|
||||
const {
|
||||
kill,
|
||||
run,
|
||||
readFile,
|
||||
open,
|
||||
makeTempDir,
|
||||
writeFile,
|
||||
writeFileSync,
|
||||
} = Deno;
|
||||
|
||||
unitTest(function runPermissions(): void {
|
||||
let caughtError = false;
|
||||
try {
|
||||
Deno.run({ cmd: ["python", "-c", "print('hello world')"] });
|
||||
run({ cmd: ["python", "-c", "print('hello world')"] });
|
||||
} catch (e) {
|
||||
caughtError = true;
|
||||
assert(e instanceof Deno.errors.PermissionDenied);
|
||||
|
@ -99,7 +107,7 @@ while True:
|
|||
pass
|
||||
`;
|
||||
|
||||
Deno.writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram));
|
||||
writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram));
|
||||
const p = run({
|
||||
cwd,
|
||||
cmd: ["python", `${pyProgramFile}.py`],
|
||||
|
@ -108,7 +116,7 @@ while True:
|
|||
// Write the expected exit code *after* starting python.
|
||||
// This is how we verify that `run()` is actually asynchronous.
|
||||
const code = 84;
|
||||
Deno.writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
|
||||
writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
|
||||
|
||||
const status = await p.status();
|
||||
assertEquals(status.success, false);
|
||||
|
@ -325,60 +333,54 @@ unitTest(function signalNumbers(): void {
|
|||
}
|
||||
});
|
||||
|
||||
// Ignore signal tests on windows for now...
|
||||
if (Deno.build.os !== "windows") {
|
||||
unitTest(function killPermissions(): void {
|
||||
let caughtError = false;
|
||||
try {
|
||||
// Unlike the other test cases, we don't have permission to spawn a
|
||||
// subprocess we can safely kill. Instead we send SIGCONT to the current
|
||||
// process - assuming that Deno does not have a special handler set for it
|
||||
// and will just continue even if a signal is erroneously sent.
|
||||
Deno.kill(Deno.pid, Deno.Signal.SIGCONT);
|
||||
} catch (e) {
|
||||
caughtError = true;
|
||||
assert(e instanceof Deno.errors.PermissionDenied);
|
||||
}
|
||||
assert(caughtError);
|
||||
unitTest(function killPermissions(): void {
|
||||
let caughtError = false;
|
||||
try {
|
||||
// Unlike the other test cases, we don't have permission to spawn a
|
||||
// subprocess we can safely kill. Instead we send SIGCONT to the current
|
||||
// process - assuming that Deno does not have a special handler set for it
|
||||
// and will just continue even if a signal is erroneously sent.
|
||||
kill(Deno.pid, Deno.Signal.SIGCONT);
|
||||
} catch (e) {
|
||||
caughtError = true;
|
||||
assert(e instanceof Deno.errors.PermissionDenied);
|
||||
}
|
||||
assert(caughtError);
|
||||
});
|
||||
|
||||
unitTest({ perms: { run: true } }, async function killSuccess(): Promise<void> {
|
||||
const p = run({
|
||||
cmd: ["python", "-c", "from time import sleep; sleep(10000)"],
|
||||
});
|
||||
|
||||
unitTest({ perms: { run: true } }, async function killSuccess(): Promise<
|
||||
void
|
||||
> {
|
||||
const p = run({
|
||||
cmd: ["python", "-c", "from time import sleep; sleep(10000)"],
|
||||
});
|
||||
assertEquals(Deno.Signal.SIGINT, 2);
|
||||
kill(p.pid, Deno.Signal.SIGINT);
|
||||
const status = await p.status();
|
||||
|
||||
assertEquals(Deno.Signal.SIGINT, 2);
|
||||
kill(p.pid, Deno.Signal.SIGINT);
|
||||
const status = await p.status();
|
||||
assertEquals(status.success, false);
|
||||
// TODO(ry) On Linux, status.code is sometimes undefined and sometimes 1.
|
||||
// The following assert is causing this test to be flaky. Investigate and
|
||||
// re-enable when it can be made deterministic.
|
||||
// assertEquals(status.code, 1);
|
||||
// assertEquals(status.signal, Deno.Signal.SIGINT);
|
||||
p.close();
|
||||
});
|
||||
|
||||
assertEquals(status.success, false);
|
||||
// TODO(ry) On Linux, status.code is sometimes undefined and sometimes 1.
|
||||
// The following assert is causing this test to be flaky. Investigate and
|
||||
// re-enable when it can be made deterministic.
|
||||
// assertEquals(status.code, 1);
|
||||
// assertEquals(status.signal, Deno.Signal.SIGINT);
|
||||
p.close();
|
||||
unitTest({ perms: { run: true } }, function killFailed(): void {
|
||||
const p = run({
|
||||
cmd: ["python", "-c", "from time import sleep; sleep(10000)"],
|
||||
});
|
||||
assert(!p.stdin);
|
||||
assert(!p.stdout);
|
||||
|
||||
unitTest({ perms: { run: true } }, function killFailed(): void {
|
||||
const p = run({
|
||||
cmd: ["python", "-c", "from time import sleep; sleep(10000)"],
|
||||
});
|
||||
assert(!p.stdin);
|
||||
assert(!p.stdout);
|
||||
let err;
|
||||
try {
|
||||
kill(p.pid, 12345);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
assert(!!err);
|
||||
assert(err instanceof TypeError);
|
||||
|
||||
let err;
|
||||
try {
|
||||
kill(p.pid, 12345);
|
||||
} catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assert(!!err);
|
||||
assert(err instanceof TypeError);
|
||||
|
||||
p.close();
|
||||
});
|
||||
}
|
||||
p.close();
|
||||
});
|
||||
|
|
|
@ -1,6 +1,23 @@
|
|||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||
use crate::op_error::OpError;
|
||||
|
||||
#[cfg(not(unix))]
|
||||
const SIGINT: i32 = 2;
|
||||
#[cfg(not(unix))]
|
||||
const SIGKILL: i32 = 9;
|
||||
#[cfg(not(unix))]
|
||||
const SIGTERM: i32 = 15;
|
||||
|
||||
#[cfg(not(unix))]
|
||||
use winapi::{
|
||||
shared::minwindef::DWORD,
|
||||
um::{
|
||||
handleapi::CloseHandle,
|
||||
processthreadsapi::{OpenProcess, TerminateProcess},
|
||||
winnt::PROCESS_TERMINATE,
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn kill(pid: i32, signo: i32) -> Result<(), OpError> {
|
||||
use nix::sys::signal::{kill as unix_kill, Signal};
|
||||
|
@ -11,7 +28,29 @@ pub fn kill(pid: i32, signo: i32) -> Result<(), OpError> {
|
|||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn kill(_pid: i32, _signal: i32) -> Result<(), OpError> {
|
||||
// TODO: implement this for windows
|
||||
pub fn kill(pid: i32, signal: i32) -> Result<(), OpError> {
|
||||
match signal {
|
||||
SIGINT | SIGKILL | SIGTERM => {
|
||||
if pid <= 0 {
|
||||
return Err(OpError::type_error("unsupported pid".to_string()));
|
||||
}
|
||||
unsafe {
|
||||
let handle = OpenProcess(PROCESS_TERMINATE, 0, pid as DWORD);
|
||||
if handle.is_null() {
|
||||
return Err(OpError::from(std::io::Error::last_os_error()));
|
||||
}
|
||||
if TerminateProcess(handle, 1) == 0 {
|
||||
CloseHandle(handle);
|
||||
return Err(OpError::from(std::io::Error::last_os_error()));
|
||||
}
|
||||
if CloseHandle(handle) == 0 {
|
||||
return Err(OpError::from(std::io::Error::last_os_error()));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return Err(OpError::type_error("unsupported signal".to_string()));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -351,12 +351,15 @@ test("requestBodyReaderWithTransferEncoding", async function (): Promise<void> {
|
|||
|
||||
test({
|
||||
name: "destroyed connection",
|
||||
// FIXME(bartlomieju): hangs on windows, cause can't do `Deno.kill`
|
||||
ignore: true,
|
||||
fn: async (): Promise<void> => {
|
||||
// Runs a simple server as another process
|
||||
const p = Deno.run({
|
||||
cmd: [Deno.execPath(), "--allow-net", "http/testdata/simple_server.ts"],
|
||||
cmd: [
|
||||
Deno.execPath(),
|
||||
"run",
|
||||
"--allow-net",
|
||||
"http/testdata/simple_server.ts",
|
||||
],
|
||||
stdout: "piped",
|
||||
});
|
||||
|
||||
|
@ -392,13 +395,12 @@ test({
|
|||
|
||||
test({
|
||||
name: "serveTLS",
|
||||
// FIXME(bartlomieju): hangs on windows, cause can't do `Deno.kill`
|
||||
ignore: true,
|
||||
fn: async (): Promise<void> => {
|
||||
// Runs a simple server as another process
|
||||
const p = Deno.run({
|
||||
cmd: [
|
||||
Deno.execPath(),
|
||||
"run",
|
||||
"--allow-net",
|
||||
"--allow-read",
|
||||
"http/testdata/simple_https_server.ts",
|
||||
|
|
Loading…
Reference in a new issue