summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Hasani <a.hassssani@gmail.com>2020-05-17 21:41:24 +0430
committerGitHub <noreply@github.com>2020-05-17 19:11:24 +0200
commiteddb916883901385233bea24313e2920fcac5388 (patch)
tree0dbde6a34037b1c2b2459077731cb9afdc5b3a35
parenta054250a2cd709f74a3c9984af0cb74b7adde3bd (diff)
Implement Deno.kill for windows (#5347)
-rw-r--r--cli/js/lib.deno.unstable.d.ts2
-rw-r--r--cli/js/ops/process.ts4
-rw-r--r--cli/js/tests/process_test.ts110
-rw-r--r--cli/signal.rs43
-rw-r--r--std/http/server_test.ts12
5 files changed, 104 insertions, 67 deletions
diff --git a/cli/js/lib.deno.unstable.d.ts b/cli/js/lib.deno.unstable.d.ts
index a166cb1c0..d34d86636 100644
--- a/cli/js/lib.deno.unstable.d.ts
+++ b/cli/js/lib.deno.unstable.d.ts
@@ -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;
diff --git a/cli/js/ops/process.ts b/cli/js/ops/process.ts
index 4fba4d2de..39c6eb8b7 100644
--- a/cli/js/ops/process.ts
+++ b/cli/js/ops/process.ts
@@ -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 });
}
diff --git a/cli/js/tests/process_test.ts b/cli/js/tests/process_test.ts
index b70ce8307..1ea6f95b7 100644
--- a/cli/js/tests/process_test.ts
+++ b/cli/js/tests/process_test.ts
@@ -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();
+});
diff --git a/cli/signal.rs b/cli/signal.rs
index 6be588b84..f74f9ab26 100644
--- a/cli/signal.rs
+++ b/cli/signal.rs
@@ -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(())
}
diff --git a/std/http/server_test.ts b/std/http/server_test.ts
index 807695c6b..0560f7f8d 100644
--- a/std/http/server_test.ts
+++ b/std/http/server_test.ts
@@ -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",