diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/deno.ts | 9 | ||||
-rw-r--r-- | js/process.ts | 89 | ||||
-rw-r--r-- | js/process_test.ts | 68 |
3 files changed, 164 insertions, 2 deletions
diff --git a/js/deno.ts b/js/deno.ts index 51cc0791a..46f018afc 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -68,7 +68,14 @@ export { FileInfo } from "./file_info"; export { connect, dial, listen, Listener, Conn } from "./net"; export { metrics, Metrics } from "./metrics"; export { resources } from "./resources"; -export { run, RunOptions, Process, ProcessStatus } from "./process"; +export { + kill, + run, + RunOptions, + Process, + ProcessStatus, + Signal +} from "./process"; export { inspect } from "./console"; export { build, platform, OperatingSystem, Arch } from "./build"; export { version } from "./version"; diff --git a/js/process.ts b/js/process.ts index a0eef63dd..c0a66f311 100644 --- a/js/process.ts +++ b/js/process.ts @@ -7,6 +7,7 @@ import { File, close } from "./files"; import { ReadCloser, WriteCloser } from "./io"; import { readAll } from "./buffer"; import { assert, unreachable } from "./util"; +import { platform } from "./build"; /** How to handle subprocess stdio. * @@ -51,6 +52,16 @@ async function runStatus(rid: number): Promise<ProcessStatus> { } } +/** Send a signal to process under given PID. Unix only at this moment. + * If pid is negative, the signal will be sent to the process group identified + * by -pid. + */ +export function kill(pid: number, signo: number): void { + const builder = flatbuffers.createBuilder(); + const inner = msg.Kill.createKill(builder, pid, signo); + dispatch.sendSync(builder, msg.Any.Kill, inner); +} + export class Process { readonly rid: number; readonly pid: number; @@ -113,6 +124,10 @@ export class Process { close(): void { close(this.rid); } + + kill(signo: number): void { + kill(this.pid, signo); + } } export interface ProcessStatus { @@ -179,3 +194,77 @@ export function run(opt: RunOptions): Process { return new Process(res); } + +// From `kill -l` +enum LinuxSignal { + SIGHUP = 1, + SIGINT = 2, + SIGQUIT = 3, + SIGILL = 4, + SIGTRAP = 5, + SIGABRT = 6, + SIGBUS = 7, + SIGFPE = 8, + SIGKILL = 9, + SIGUSR1 = 10, + SIGSEGV = 11, + SIGUSR2 = 12, + SIGPIPE = 13, + SIGALRM = 14, + SIGTERM = 15, + SIGSTKFLT = 16, + SIGCHLD = 17, + SIGCONT = 18, + SIGSTOP = 19, + SIGTSTP = 20, + SIGTTIN = 21, + SIGTTOU = 22, + SIGURG = 23, + SIGXCPU = 24, + SIGXFSZ = 25, + SIGVTALRM = 26, + SIGPROF = 27, + SIGWINCH = 28, + SIGIO = 29, + SIGPWR = 30, + SIGSYS = 31 +} + +// From `kill -l` +enum MacOSSignal { + SIGHUP = 1, + SIGINT = 2, + SIGQUIT = 3, + SIGILL = 4, + SIGTRAP = 5, + SIGABRT = 6, + SIGEMT = 7, + SIGFPE = 8, + SIGKILL = 9, + SIGBUS = 10, + SIGSEGV = 11, + SIGSYS = 12, + SIGPIPE = 13, + SIGALRM = 14, + SIGTERM = 15, + SIGURG = 16, + SIGSTOP = 17, + SIGTSTP = 18, + SIGCONT = 19, + SIGCHLD = 20, + SIGTTIN = 21, + SIGTTOU = 22, + SIGIO = 23, + SIGXCPU = 24, + SIGXFSZ = 25, + SIGVTALRM = 26, + SIGPROF = 27, + SIGWINCH = 28, + SIGINFO = 29, + SIGUSR1 = 30, + SIGUSR2 = 31 +} + +/** Signals numbers. This is platform dependent. + */ +export const Signal = platform.os === "mac" ? MacOSSignal : LinuxSignal; diff --git a/js/process_test.ts b/js/process_test.ts index c89e1cae7..8d266617a 100644 --- a/js/process_test.ts +++ b/js/process_test.ts @@ -1,6 +1,6 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. import { test, testPerm, assert, assertEquals } from "./test_util.ts"; -const { run, DenoError, ErrorKind } = Deno; +const { kill, run, DenoError, ErrorKind } = Deno; test(function runPermissions(): void { let caughtError = false; @@ -223,3 +223,69 @@ testPerm({ run: true }, async function runEnv(): Promise<void> { assertEquals(s, "01234567"); p.close(); }); + +testPerm({ run: true }, async function runClose(): Promise<void> { + const p = run({ + args: [ + "python", + "-c", + "from time import sleep; import sys; sleep(10000); sys.stderr.write('error')" + ], + stderr: "piped" + }); + assert(!p.stdin); + assert(!p.stdout); + + p.close(); + + const data = new Uint8Array(10); + let r = await p.stderr.read(data); + assertEquals(r.nread, 0); + assertEquals(r.eof, true); +}); + +test(function signalNumbers(): void { + if (Deno.platform.os === "mac") { + assertEquals(Deno.Signal.SIGSTOP, 17); + } else if (Deno.platform.os === "linux") { + assertEquals(Deno.Signal.SIGSTOP, 19); + } +}); + +// Ignore signal tests on windows for now... +if (Deno.platform.os !== "win") { + testPerm({ run: true }, async function killSuccess(): Promise<void> { + const p = run({ + args: ["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(status.success, false); + assertEquals(status.code, undefined); + assertEquals(status.signal, Deno.Signal.SIGINT); + }); + + testPerm({ run: true }, async function killFailed(): Promise<void> { + const p = run({ + args: ["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); + assertEquals(err.kind, Deno.ErrorKind.InvalidInput); + assertEquals(err.name, "InvalidInput"); + + p.close(); + }); +} |