summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/js/deno.ts1
-rw-r--r--cli/js/dispatch.ts3
-rw-r--r--cli/js/lib.deno_runtime.d.ts74
-rw-r--r--cli/js/process.ts2
-rw-r--r--cli/js/signal_test.ts185
-rw-r--r--cli/js/signals.ts148
-rw-r--r--cli/js/unit_tests.ts1
-rw-r--r--cli/lib.rs2
-rw-r--r--cli/ops/mod.rs1
-rw-r--r--cli/ops/signal.rs146
-rw-r--r--cli/signal.rs1
-rw-r--r--cli/worker.rs1
-rw-r--r--std/manual.md33
13 files changed, 596 insertions, 2 deletions
diff --git a/cli/js/deno.ts b/cli/js/deno.ts
index e53f9a63a..2d20ae811 100644
--- a/cli/js/deno.ts
+++ b/cli/js/deno.ts
@@ -101,6 +101,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[] = [];
diff --git a/cli/js/dispatch.ts b/cli/js/dispatch.ts
index f5049cca8..aa6696fa2 100644
--- a/cli/js/dispatch.ts
+++ b/cli/js/dispatch.ts
@@ -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_SIGNAL_BIND: number;
+export let OP_SIGNAL_UNBIND: number;
+export let OP_SIGNAL_POLL: number;
/** **WARNING:** This is only available during the snapshotting process and is
* unavailable at runtime. */
diff --git a/cli/js/lib.deno_runtime.d.ts b/cli/js/lib.deno_runtime.d.ts
index efdf06347..1dfa3209f 100644
--- a/cli/js/lib.deno_runtime.d.ts
+++ b/cli/js/lib.deno_runtime.d.ts
@@ -2130,6 +2130,80 @@ declare namespace Deno {
*/
export const args: string[];
+ /** SignalStream represents the stream of signals, implements both
+ * AsyncIterator and PromiseLike */
+ 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 shorthand for Deno.signal(Deno.Signal.SIGALRM). */
+ alarm: () => SignalStream;
+ /** Returns the stream of SIGCHLD signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGCHLD). */
+ child: () => SignalStream;
+ /** Returns the stream of SIGHUP signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGHUP). */
+ hungup: () => SignalStream;
+ /** Returns the stream of SIGINT signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGINT). */
+ interrupt: () => SignalStream;
+ /** Returns the stream of SIGIO signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGIO). */
+ io: () => SignalStream;
+ /** Returns the stream of SIGPIPE signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGPIPE). */
+ pipe: () => SignalStream;
+ /** Returns the stream of SIGQUIT signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGQUIT). */
+ quit: () => SignalStream;
+ /** Returns the stream of SIGTERM signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGTERM). */
+ terminate: () => SignalStream;
+ /** Returns the stream of SIGUSR1 signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGUSR1). */
+ userDefined1: () => SignalStream;
+ /** Returns the stream of SIGUSR2 signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGUSR2). */
+ userDefined2: () => SignalStream;
+ /** Returns the stream of SIGWINCH signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGWINCH). */
+ windowChange: () => SignalStream;
+ };
+
/** UNSTABLE: new API. Maybe move EOF here.
*
* Special Deno related symbols.
diff --git a/cli/js/process.ts b/cli/js/process.ts
index 8ad6384b7..5267763c1 100644
--- a/cli/js/process.ts
+++ b/cli/js/process.ts
@@ -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") {
diff --git a/cli/js/signal_test.ts b/cli/js/signal_test.ts
new file mode 100644
index 000000000..06457314c
--- /dev/null
+++ b/cli/js/signal_test.ts
@@ -0,0 +1,185 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+import {
+ test,
+ 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") {
+ test(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.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, net: true }, async function signalStreamTest(): Promise<
+ void
+ > {
+ // This prevents the program from exiting.
+ const t = setInterval(() => {}, 1000);
+
+ 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);
+
+ clearTimeout(t);
+ });
+
+ testPerm(
+ { run: true, net: true },
+ async function signalPromiseTest(): Promise<void> {
+ // This prevents the program from exiting.
+ const t = setInterval(() => {}, 1000);
+
+ const sig = Deno.signal(Deno.Signal.SIGUSR1);
+ setTimeout(() => {
+ Deno.kill(Deno.pid, Deno.Signal.SIGUSR1);
+ }, 20);
+ await sig;
+ sig.dispose();
+
+ clearTimeout(t);
+ }
+ );
+
+ 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.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();
+ });
+}
diff --git a/cli/js/signals.ts b/cli/js/signals.ts
new file mode 100644
index 000000000..02d52bc2f
--- /dev/null
+++ b/cli/js/signals.ts
@@ -0,0 +1,148 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+import { Signal } from "./process.ts";
+import * as dispatch from "./dispatch.ts";
+import { sendSync, sendAsync } from "./dispatch_json.ts";
+import { build } from "./build.ts";
+
+/**
+ * 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 {
+ if (build.os === "win") {
+ throw new Error("not implemented!");
+ }
+ return new SignalStream(signo);
+}
+
+export const signals = {
+ /** Returns the stream of SIGALRM signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGALRM). */
+ alarm(): SignalStream {
+ return signal(Signal.SIGALRM);
+ },
+ /** Returns the stream of SIGCHLD signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGCHLD). */
+ child(): SignalStream {
+ return signal(Signal.SIGCHLD);
+ },
+ /** Returns the stream of SIGHUP signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGHUP). */
+ hungup(): SignalStream {
+ return signal(Signal.SIGHUP);
+ },
+ /** Returns the stream of SIGINT signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGINT). */
+ interrupt(): SignalStream {
+ return signal(Signal.SIGINT);
+ },
+ /** Returns the stream of SIGIO signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGIO). */
+ io(): SignalStream {
+ return signal(Signal.SIGIO);
+ },
+ /** Returns the stream of SIGPIPE signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGPIPE). */
+ pipe(): SignalStream {
+ return signal(Signal.SIGPIPE);
+ },
+ /** Returns the stream of SIGQUIT signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGQUIT). */
+ quit(): SignalStream {
+ return signal(Signal.SIGQUIT);
+ },
+ /** Returns the stream of SIGTERM signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGTERM). */
+ terminate(): SignalStream {
+ return signal(Signal.SIGTERM);
+ },
+ /** Returns the stream of SIGUSR1 signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGUSR1). */
+ userDefined1(): SignalStream {
+ return signal(Signal.SIGUSR1);
+ },
+ /** Returns the stream of SIGUSR2 signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGUSR2). */
+ userDefined2(): SignalStream {
+ return signal(Signal.SIGUSR2);
+ },
+ /** Returns the stream of SIGWINCH signals.
+ * This method is the shorthand for Deno.signal(Deno.Signal.SIGWINCH). */
+ windowChange(): SignalStream {
+ return signal(Signal.SIGWINCH);
+ }
+};
+
+/** SignalStream represents the stream of signals, implements both
+ * AsyncIterator and PromiseLike */
+export class SignalStream implements AsyncIterator<void>, PromiseLike<void> {
+ private rid: number;
+ /** The promise of polling the signal,
+ * resolves with false when it receives signal,
+ * Resolves with true when the signal stream is disposed. */
+ private pollingPromise: Promise<boolean> = Promise.resolve(false);
+ /** The flag, which is true when the stream is disposed. */
+ private disposed = false;
+ constructor(signo: number) {
+ this.rid = sendSync(dispatch.OP_SIGNAL_BIND, { signo }).rid;
+ this.loop();
+ }
+
+ private async pollSignal(): Promise<boolean> {
+ return (
+ await sendAsync(dispatch.OP_SIGNAL_POLL, {
+ rid: this.rid
+ })
+ ).done;
+ }
+
+ private async loop(): Promise<void> {
+ do {
+ this.pollingPromise = this.pollSignal();
+ } while (!(await this.pollingPromise) && !this.disposed);
+ }
+
+ then<T, S>(
+ f: (v: void) => T | Promise<T>,
+ g?: (v: Error) => S | Promise<S>
+ ): Promise<T | S> {
+ return this.pollingPromise.then((_): void => {}).then(f, g);
+ }
+
+ async next(): Promise<IteratorResult<void>> {
+ return { done: await this.pollingPromise, value: undefined };
+ }
+
+ [Symbol.asyncIterator](): AsyncIterator<void> {
+ return this;
+ }
+
+ dispose(): void {
+ if (this.disposed) {
+ throw new Error("The stream has already been disposed.");
+ }
+ this.disposed = true;
+ sendSync(dispatch.OP_SIGNAL_UNBIND, { rid: this.rid });
+ }
+}
diff --git a/cli/js/unit_tests.ts b/cli/js/unit_tests.ts
index 084661ab8..47ae06b19 100644
--- a/cli/js/unit_tests.ts
+++ b/cli/js/unit_tests.ts
@@ -42,6 +42,7 @@ import "./read_link_test.ts";
import "./rename_test.ts";
import "./request_test.ts";
import "./resources_test.ts";
+import "./signal_test.ts";
import "./stat_test.ts";
import "./symbols_test.ts";
import "./symlink_test.ts";
diff --git a/cli/lib.rs b/cli/lib.rs
index 9753e4c4c..4a08f40c6 100644
--- a/cli/lib.rs
+++ b/cli/lib.rs
@@ -44,7 +44,7 @@ mod progress;
mod repl;
pub mod resolve_addr;
mod shell;
-mod signal;
+pub mod signal;
pub mod source_maps;
mod startup_data;
pub mod state;
diff --git a/cli/ops/mod.rs b/cli/ops/mod.rs
index 81f95ffb9..4306e25e2 100644
--- a/cli/ops/mod.rs
+++ b/cli/ops/mod.rs
@@ -22,6 +22,7 @@ pub mod random;
pub mod repl;
pub mod resources;
pub mod runtime_compiler;
+pub mod signal;
pub mod timers;
pub mod tls;
pub mod web_worker;
diff --git a/cli/ops/signal.rs b/cli/ops/signal.rs
new file mode 100644
index 000000000..5fef02013
--- /dev/null
+++ b/cli/ops/signal.rs
@@ -0,0 +1,146 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
+use super::dispatch_json::{JsonOp, Value};
+use crate::ops::json_op;
+use crate::state::ThreadSafeState;
+use deno_core::*;
+
+#[cfg(unix)]
+use super::dispatch_json::Deserialize;
+#[cfg(unix)]
+use crate::deno_error::bad_resource;
+#[cfg(unix)]
+use deno_core::Resource;
+#[cfg(unix)]
+use futures::future::{poll_fn, FutureExt};
+#[cfg(unix)]
+use serde_json;
+#[cfg(unix)]
+use std::task::Waker;
+#[cfg(unix)]
+use tokio::signal::unix::{signal, Signal, SignalKind};
+
+pub fn init(i: &mut Isolate, s: &ThreadSafeState) {
+ i.register_op(
+ "signal_bind",
+ s.core_op(json_op(s.stateful_op(op_signal_bind))),
+ );
+ i.register_op(
+ "signal_unbind",
+ s.core_op(json_op(s.stateful_op(op_signal_unbind))),
+ );
+ i.register_op(
+ "signal_poll",
+ s.core_op(json_op(s.stateful_op(op_signal_poll))),
+ );
+}
+
+#[cfg(unix)]
+/// The resource for signal stream.
+/// The second element is the waker of polling future.
+pub struct SignalStreamResource(pub Signal, pub Option<Waker>);
+
+#[cfg(unix)]
+impl Resource for SignalStreamResource {}
+
+#[cfg(unix)]
+#[derive(Deserialize)]
+struct BindSignalArgs {
+ signo: i32,
+}
+
+#[cfg(unix)]
+#[derive(Deserialize)]
+struct SignalArgs {
+ rid: i32,
+}
+
+#[cfg(unix)]
+fn op_signal_bind(
+ state: &ThreadSafeState,
+ args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ let args: BindSignalArgs = serde_json::from_value(args)?;
+ let mut table = state.lock_resource_table();
+ let rid = table.add(
+ "signal",
+ Box::new(SignalStreamResource(
+ signal(SignalKind::from_raw(args.signo)).expect(""),
+ None,
+ )),
+ );
+ Ok(JsonOp::Sync(json!({
+ "rid": rid,
+ })))
+}
+
+#[cfg(unix)]
+fn op_signal_poll(
+ state: &ThreadSafeState,
+ args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ let args: SignalArgs = serde_json::from_value(args)?;
+ let rid = args.rid as u32;
+ let state_ = state.clone();
+
+ let future = poll_fn(move |cx| {
+ let mut table = state_.lock_resource_table();
+ if let Some(mut signal) = table.get_mut::<SignalStreamResource>(rid) {
+ signal.1 = Some(cx.waker().clone());
+ return signal.0.poll_recv(cx);
+ }
+ std::task::Poll::Ready(None)
+ })
+ .then(|result| async move { Ok(json!({ "done": result.is_none() })) });
+
+ Ok(JsonOp::AsyncUnref(future.boxed()))
+}
+
+#[cfg(unix)]
+pub fn op_signal_unbind(
+ state: &ThreadSafeState,
+ args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ let args: SignalArgs = serde_json::from_value(args)?;
+ let rid = args.rid as u32;
+ let mut table = state.lock_resource_table();
+ let resource = table.get::<SignalStreamResource>(rid);
+ if let Some(signal) = resource {
+ if let Some(waker) = &signal.1 {
+ // Wakes up the pending poll if exists.
+ // This prevents the poll future from getting stuck forever.
+ waker.clone().wake();
+ }
+ }
+ table.close(rid).ok_or_else(bad_resource)?;
+ Ok(JsonOp::Sync(json!({})))
+}
+
+#[cfg(not(unix))]
+pub fn op_signal_bind(
+ _state: &ThreadSafeState,
+ _args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ unimplemented!();
+}
+
+#[cfg(not(unix))]
+fn op_signal_unbind(
+ _state: &ThreadSafeState,
+ _args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ unimplemented!();
+}
+
+#[cfg(not(unix))]
+fn op_signal_poll(
+ _state: &ThreadSafeState,
+ _args: Value,
+ _zero_copy: Option<PinnedBuf>,
+) -> Result<JsonOp, ErrBox> {
+ unimplemented!();
+}
diff --git a/cli/signal.rs b/cli/signal.rs
index 57f2d0d3d..6f150aeab 100644
--- a/cli/signal.rs
+++ b/cli/signal.rs
@@ -1,3 +1,4 @@
+// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
use deno_core::ErrBox;
#[cfg(unix)]
diff --git a/cli/worker.rs b/cli/worker.rs
index ef72602d4..9fd70eedc 100644
--- a/cli/worker.rs
+++ b/cli/worker.rs
@@ -200,6 +200,7 @@ impl MainWorker {
ops::random::init(&mut isolate, &state);
ops::repl::init(&mut isolate, &state);
ops::resources::init(&mut isolate, &state);
+ ops::signal::init(&mut isolate, &state);
ops::timers::init(&mut isolate, &state);
ops::worker_host::init(&mut isolate, &state);
ops::web_worker::init(&mut isolate, &state);
diff --git a/std/manual.md b/std/manual.md
index ece5a755b..204701566 100644
--- a/std/manual.md
+++ b/std/manual.md
@@ -428,6 +428,39 @@ Uncaught NotFound: No such file or directory (os error 2)
at handleAsyncMsgFromRust (deno/js/dispatch.ts:27:17)
```
+### Handle OS Signals
+
+[API Reference](https://deno.land/typedoc/index.html#signal)
+
+You can use `Deno.signal()` function for handling OS signals.
+
+```
+for await (const _ of Deno.signal(Deno.Signal.SIGINT)) {
+ console.log("interrupted!");
+}
+```
+
+`Deno.signal()` also works as a promise.
+
+```
+await Deno.signal(Deno.Singal.SIGINT);
+console.log("interrupted!");
+```
+
+If you want to stop watching the signal, you can use `dispose()` method of the
+signal object.
+
+```
+const sig = Deno.signal(Deno.Signal.SIGINT);
+setTimeout(() => { sig.dispose(); }, 5000);
+
+for await (const _ of sig) {
+ console.log("interrupted");
+}
+```
+
+The above for-await loop exits after 5 seconds when sig.dispose() is called.
+
### Linking to third party code
In the above examples, we saw that Deno could execute scripts from URLs. Like