deno/cli/js/signals.ts

173 lines
3.4 KiB
TypeScript

// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { bindSignal, pollSignal, unbindSignal } from "./ops/signal.ts";
import { build } from "./build.ts";
// 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,
}
export const Signal: { [key: string]: number } = {};
export function setSignals(): void {
if (build.os === "mac") {
Object.assign(Signal, MacOSSignal);
} else {
Object.assign(Signal, LinuxSignal);
}
}
export function signal(signo: number): SignalStream {
if (build.os === "win") {
throw new Error("not implemented!");
}
return new SignalStream(signo);
}
export const signals = {
alarm(): SignalStream {
return signal(Signal.SIGALRM);
},
child(): SignalStream {
return signal(Signal.SIGCHLD);
},
hungup(): SignalStream {
return signal(Signal.SIGHUP);
},
interrupt(): SignalStream {
return signal(Signal.SIGINT);
},
io(): SignalStream {
return signal(Signal.SIGIO);
},
pipe(): SignalStream {
return signal(Signal.SIGPIPE);
},
quit(): SignalStream {
return signal(Signal.SIGQUIT);
},
terminate(): SignalStream {
return signal(Signal.SIGTERM);
},
userDefined1(): SignalStream {
return signal(Signal.SIGUSR1);
},
userDefined2(): SignalStream {
return signal(Signal.SIGUSR2);
},
windowChange(): SignalStream {
return signal(Signal.SIGWINCH);
},
};
export class SignalStream
implements AsyncIterableIterator<void>, PromiseLike<void> {
#disposed = false;
#pollingPromise: Promise<boolean> = Promise.resolve(false);
#rid: number;
constructor(signo: number) {
this.#rid = bindSignal(signo).rid;
this.#loop();
}
#pollSignal = async (): Promise<boolean> => {
const res = await pollSignal(this.#rid);
return res.done;
};
#loop = async (): 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(() => {}).then(f, g);
}
async next(): Promise<IteratorResult<void>> {
return { done: await this.#pollingPromise, value: undefined };
}
[Symbol.asyncIterator](): AsyncIterableIterator<void> {
return this;
}
dispose(): void {
if (this.#disposed) {
throw new Error("The stream has already been disposed.");
}
this.#disposed = true;
unbindSignal(this.#rid);
}
}