mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -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);
|
* Deno.kill(p.pid, Deno.Signal.SIGINT);
|
||||||
*
|
*
|
||||||
* Throws Error (not yet implemented) on Windows
|
|
||||||
*
|
|
||||||
* Requires `allow-run` permission. */
|
* Requires `allow-run` permission. */
|
||||||
export function kill(pid: number, signo: number): void;
|
export function kill(pid: number, signo: number): void;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
import { sendSync, sendAsync } from "./dispatch_json.ts";
|
import { sendSync, sendAsync } from "./dispatch_json.ts";
|
||||||
import { assert } from "../util.ts";
|
import { assert } from "../util.ts";
|
||||||
import { build } from "../build.ts";
|
|
||||||
|
|
||||||
export function kill(pid: number, signo: number): void {
|
export function kill(pid: number, signo: number): void {
|
||||||
if (build.os === "windows") {
|
|
||||||
throw new Error("Not yet implemented");
|
|
||||||
}
|
|
||||||
sendSync("op_kill", { pid, signo });
|
sendSync("op_kill", { pid, signo });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,20 @@ import {
|
||||||
assertStrContains,
|
assertStrContains,
|
||||||
unitTest,
|
unitTest,
|
||||||
} from "./test_util.ts";
|
} 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 {
|
unitTest(function runPermissions(): void {
|
||||||
let caughtError = false;
|
let caughtError = false;
|
||||||
try {
|
try {
|
||||||
Deno.run({ cmd: ["python", "-c", "print('hello world')"] });
|
run({ cmd: ["python", "-c", "print('hello world')"] });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
caughtError = true;
|
caughtError = true;
|
||||||
assert(e instanceof Deno.errors.PermissionDenied);
|
assert(e instanceof Deno.errors.PermissionDenied);
|
||||||
|
@ -99,7 +107,7 @@ while True:
|
||||||
pass
|
pass
|
||||||
`;
|
`;
|
||||||
|
|
||||||
Deno.writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram));
|
writeFileSync(`${cwd}/${pyProgramFile}.py`, enc.encode(pyProgram));
|
||||||
const p = run({
|
const p = run({
|
||||||
cwd,
|
cwd,
|
||||||
cmd: ["python", `${pyProgramFile}.py`],
|
cmd: ["python", `${pyProgramFile}.py`],
|
||||||
|
@ -108,7 +116,7 @@ while True:
|
||||||
// Write the expected exit code *after* starting python.
|
// Write the expected exit code *after* starting python.
|
||||||
// This is how we verify that `run()` is actually asynchronous.
|
// This is how we verify that `run()` is actually asynchronous.
|
||||||
const code = 84;
|
const code = 84;
|
||||||
Deno.writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
|
writeFileSync(`${cwd}/${exitCodeFile}`, enc.encode(`${code}`));
|
||||||
|
|
||||||
const status = await p.status();
|
const status = await p.status();
|
||||||
assertEquals(status.success, false);
|
assertEquals(status.success, false);
|
||||||
|
@ -325,8 +333,6 @@ unitTest(function signalNumbers(): void {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ignore signal tests on windows for now...
|
|
||||||
if (Deno.build.os !== "windows") {
|
|
||||||
unitTest(function killPermissions(): void {
|
unitTest(function killPermissions(): void {
|
||||||
let caughtError = false;
|
let caughtError = false;
|
||||||
try {
|
try {
|
||||||
|
@ -334,7 +340,7 @@ if (Deno.build.os !== "windows") {
|
||||||
// subprocess we can safely kill. Instead we send SIGCONT to the current
|
// 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
|
// process - assuming that Deno does not have a special handler set for it
|
||||||
// and will just continue even if a signal is erroneously sent.
|
// and will just continue even if a signal is erroneously sent.
|
||||||
Deno.kill(Deno.pid, Deno.Signal.SIGCONT);
|
kill(Deno.pid, Deno.Signal.SIGCONT);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
caughtError = true;
|
caughtError = true;
|
||||||
assert(e instanceof Deno.errors.PermissionDenied);
|
assert(e instanceof Deno.errors.PermissionDenied);
|
||||||
|
@ -342,9 +348,7 @@ if (Deno.build.os !== "windows") {
|
||||||
assert(caughtError);
|
assert(caughtError);
|
||||||
});
|
});
|
||||||
|
|
||||||
unitTest({ perms: { run: true } }, async function killSuccess(): Promise<
|
unitTest({ perms: { run: true } }, async function killSuccess(): Promise<void> {
|
||||||
void
|
|
||||||
> {
|
|
||||||
const p = run({
|
const p = run({
|
||||||
cmd: ["python", "-c", "from time import sleep; sleep(10000)"],
|
cmd: ["python", "-c", "from time import sleep; sleep(10000)"],
|
||||||
});
|
});
|
||||||
|
@ -375,10 +379,8 @@ if (Deno.build.os !== "windows") {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = e;
|
err = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!!err);
|
assert(!!err);
|
||||||
assert(err instanceof TypeError);
|
assert(err instanceof TypeError);
|
||||||
|
|
||||||
p.close();
|
p.close();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,23 @@
|
||||||
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::op_error::OpError;
|
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)]
|
#[cfg(unix)]
|
||||||
pub fn kill(pid: i32, signo: i32) -> Result<(), OpError> {
|
pub fn kill(pid: i32, signo: i32) -> Result<(), OpError> {
|
||||||
use nix::sys::signal::{kill as unix_kill, Signal};
|
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))]
|
#[cfg(not(unix))]
|
||||||
pub fn kill(_pid: i32, _signal: i32) -> Result<(), OpError> {
|
pub fn kill(pid: i32, signal: i32) -> Result<(), OpError> {
|
||||||
// TODO: implement this for windows
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,12 +351,15 @@ test("requestBodyReaderWithTransferEncoding", async function (): Promise<void> {
|
||||||
|
|
||||||
test({
|
test({
|
||||||
name: "destroyed connection",
|
name: "destroyed connection",
|
||||||
// FIXME(bartlomieju): hangs on windows, cause can't do `Deno.kill`
|
|
||||||
ignore: true,
|
|
||||||
fn: async (): Promise<void> => {
|
fn: async (): Promise<void> => {
|
||||||
// Runs a simple server as another process
|
// Runs a simple server as another process
|
||||||
const p = Deno.run({
|
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",
|
stdout: "piped",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -392,13 +395,12 @@ test({
|
||||||
|
|
||||||
test({
|
test({
|
||||||
name: "serveTLS",
|
name: "serveTLS",
|
||||||
// FIXME(bartlomieju): hangs on windows, cause can't do `Deno.kill`
|
|
||||||
ignore: true,
|
|
||||||
fn: async (): Promise<void> => {
|
fn: async (): Promise<void> => {
|
||||||
// Runs a simple server as another process
|
// Runs a simple server as another process
|
||||||
const p = Deno.run({
|
const p = Deno.run({
|
||||||
cmd: [
|
cmd: [
|
||||||
Deno.execPath(),
|
Deno.execPath(),
|
||||||
|
"run",
|
||||||
"--allow-net",
|
"--allow-net",
|
||||||
"--allow-read",
|
"--allow-read",
|
||||||
"http/testdata/simple_https_server.ts",
|
"http/testdata/simple_https_server.ts",
|
||||||
|
|
Loading…
Add table
Reference in a new issue