Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Try adding signal handler ops #3610

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cli/js/deno.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export {
} from "./process.ts";
export { transpileOnly, compile, bundle } from "./compiler_api.ts";
export { inspect } from "./console.ts";
export { signal, signals, SignalStream } from "./signals.ts";
export { build, OperatingSystem, Arch } from "./build.ts";
export { version } from "./version.ts";
export const args: string[] = [];
Expand Down
3 changes: 3 additions & 0 deletions cli/js/dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export let OP_HOSTNAME: number;
export let OP_OPEN_PLUGIN: number;
export let OP_COMPILE: number;
export let OP_TRANSPILE: number;
export let OP_BIND_SIGNAL: number;
export let OP_UNBIND_SIGNAL: number;
export let OP_POLL_SIGNAL: number;

/** **WARNING:** This is only available during the snapshotting process and is
* unavailable at runtime. */
Expand Down
4 changes: 3 additions & 1 deletion cli/js/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,7 @@ export enum ErrorKind {
TypeError = 51,

/** TODO this is a DomException type, and should be moved out of here when possible */
DataCloneError = 52
DataCloneError = 52,

StreamDisposed = 53
}
100 changes: 100 additions & 0 deletions cli/js/lib.deno_runtime.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2106,6 +2106,106 @@ declare namespace Deno {
*/
export const args: string[];

// @url js/signal.d.ts
export class SignalStream implements AsyncIterator<void>, PromiseLike<void> {
constructor(signal: typeof Deno.Signal);
then<T, S>(
f: (v: void) => T | Promise<T>,
g?: (v: void) => S | Promise<S>
): Promise<T | S>;
next(): Promise<IteratorResult<void>>;
[Symbol.asyncIterator](): AsyncIterator<void>;
dispose(): void;
}
/**
* Returns the stream of the given signal number. You can use it as an async
* iterator.
*
* for await (const _ of Deno.signal(Deno.Signal.SIGTERM)) {
* console.log("got SIGTERM!");
* }
*
* You can also use it as a promise. In this case you can only receive the
* first one.
*
* await Deno.signal(Deno.Signal.SIGTERM);
* console.log("SIGTERM received!")
*
* If you want to stop receiving the signals, you can use .dispose() method
* of the signal stream object.
*
* const sig = Deno.signal(Deno.Signal.SIGTERM);
* setTimeout(() => { sig.dispose(); }, 5000);
* for await (const _ of sig) {
* console.log("SIGTERM!")
* }
*
* The above for-await loop exits after 5 seconds when sig.dispose() is called.
*/
export function signal(signo: number): SignalStream;
export const signals: {
/**
* Returns the stream of SIGALRM signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGALRM).
*/
alarm: () => SignalStream;
/**
* Returns the stream of SIGCHLD signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGCHLD).
*/
child: () => SignalStream;
/**
* Returns the stream of SIGHUP signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGHUP).
*/
hungup: () => SignalStream;
/**
* Returns the stream of SIGINFO signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGINFO).
*/
info: () => SignalStream;
/**
* Returns the stream of SIGINT signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGINT).
*/
interrupt: () => SignalStream;
/**
* Returns the stream of SIGIO signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGIO).
*/
io: () => SignalStream;
/**
* Returns the stream of SIGPIPE signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGPIPE).
*/
pipe: () => SignalStream;
/**
* Returns the stream of SIGQUIT signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGQUIT).
*/
quit: () => SignalStream;
/**
* Returns the stream of SIGTERM signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGTERM).
*/
terminate: () => SignalStream;
/**
* Returns the stream of SIGUSR1 signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGUSR1).
*/
userDefined1: () => SignalStream;
/**
* Returns the stream of SIGUSR2 signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGUSR2).
*/
userDefined2: () => SignalStream;
/**
* Returns the stream of SIGWINCH signals.
* This method is the short hand for Deno.signal(Deno.Signal.SIGWINCH).
*/
windowChange: () => SignalStream;
};

/** UNSTABLE: new API. Maybe move EOF here.
*
* Special Deno related symbols.
Expand Down
2 changes: 1 addition & 1 deletion cli/js/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ enum MacOSSignal {

/** Signals numbers. This is platform dependent.
*/
export const Signal = {};
export const Signal: { [key: string]: number } = {};

export function setSignals(): void {
if (build.os === "mac") {
Expand Down
174 changes: 174 additions & 0 deletions cli/js/signal_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { testPerm, assert, assertEquals, assertThrows } from "./test_util.ts";

function defer(n: number): Promise<void> {
return new Promise((resolve, _) => {
setTimeout(resolve, n);
});
}

if (Deno.build.os === "win") {
testPerm({ run: true }, async function signalsNotImplemented(): Promise<void> {
assertThrows(
() => {
Deno.signal(1);
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.alarm(); // for SIGALRM
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.child(); // for SIGCHLD
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.hungup(); // for SIGHUP
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.info(); // for SIGINFO
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.interrupt(); // for SIGINT
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.io(); // for SIGIO
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.pipe(); // for SIGPIPE
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.quit(); // for SIGQUIT
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.terminate(); // for SIGTERM
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.userDefined1(); // for SIGUSR1
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.userDefined2(); // for SIGURS2
},
Error,
"not implemented"
);
assertThrows(
() => {
Deno.signals.windowChange(); // for SIGWINCH
},
Error,
"not implemented"
);
});
} else {
testPerm({ run: true }, async function signalStreamTest(): Promise<void> {
let c = 0;
const sig = Deno.signal(Deno.Signal.SIGUSR1);

setTimeout(async () => {
await defer(20);
for (const _ of Array(3)) {
// Sends SIGUSR1 3 times.
Deno.kill(Deno.pid, Deno.Signal.SIGUSR1);
await defer(20);
}
sig.dispose();
});

for await (const _ of sig) {
c += 1;
}

assertEquals(c, 3);
});

testPerm({ run: true }, async function signalPromiseTest(): Promise<void> {
const sig = Deno.signal(Deno.Signal.SIGUSR1);
setTimeout(() => {
Deno.kill(Deno.pid, Deno.Signal.SIGUSR1);
}, 20);
await sig;
sig.dispose();
});

testPerm({ run: true }, async function signalShorthandsTest(): Promise<void> {
let s: Deno.SignalStream;
s = Deno.signals.alarm(); // for SIGALRM
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.child(); // for SIGCHLD
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.hungup(); // for SIGHUP
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.info(); // for SIGINFO
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.interrupt(); // for SIGINT
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.io(); // for SIGIO
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.pipe(); // for SIGPIPE
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.quit(); // for SIGQUIT
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.terminate(); // for SIGTERM
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.userDefined1(); // for SIGUSR1
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.userDefined2(); // for SIGURS2
assert(s instanceof Deno.SignalStream);
s.dispose();
s = Deno.signals.windowChange(); // for SIGWINCH
assert(s instanceof Deno.SignalStream);
s.dispose();
});
}
Loading