mirror of
https://github.com/denoland/deno.git
synced 2025-01-03 04:48:52 -05:00
fix(task): forward signals to spawned sub-processes on unix (#27141)
Closes https://github.com/denoland/deno/issues/18445
This commit is contained in:
parent
8626ec7c25
commit
f6248601f4
15 changed files with 590 additions and 288 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -2136,19 +2136,19 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "deno_task_shell"
|
||||
version = "0.18.1"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f444918f7102c1a5a143e9d57809e499fb4d365070519bf2e8bdb16d586af2a"
|
||||
checksum = "01e09966ce29f8d26b652a43355397e1df43b85759e7824196bf0ceaeaa9a2f4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures",
|
||||
"glob",
|
||||
"monch",
|
||||
"nix",
|
||||
"os_pipe",
|
||||
"path-dedot",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -82,7 +82,7 @@ deno_path_util.workspace = true
|
|||
deno_resolver.workspace = true
|
||||
deno_runtime = { workspace = true, features = ["include_js_files_for_snapshotting"] }
|
||||
deno_semver.workspace = true
|
||||
deno_task_shell = "=0.18.1"
|
||||
deno_task_shell = "=0.20.1"
|
||||
deno_telemetry.workspace = true
|
||||
deno_terminal.workspace = true
|
||||
libsui = "0.5.0"
|
||||
|
|
|
@ -1297,16 +1297,10 @@ impl TsServer {
|
|||
{
|
||||
// When an LSP request is cancelled by the client, the future this is being
|
||||
// executed under and any local variables here will be dropped at the next
|
||||
// await point. To pass on that cancellation to the TS thread, we make this
|
||||
// wrapper which cancels the request's token on drop.
|
||||
struct DroppableToken(CancellationToken);
|
||||
impl Drop for DroppableToken {
|
||||
fn drop(&mut self) {
|
||||
self.0.cancel();
|
||||
}
|
||||
}
|
||||
// await point. To pass on that cancellation to the TS thread, we use drop_guard
|
||||
// which cancels the request's token on drop.
|
||||
let token = token.child_token();
|
||||
let droppable_token = DroppableToken(token.clone());
|
||||
let droppable_token = token.clone().drop_guard();
|
||||
let (tx, mut rx) = oneshot::channel::<Result<String, AnyError>>();
|
||||
let change = self.pending_change.lock().take();
|
||||
|
||||
|
@ -1320,7 +1314,7 @@ impl TsServer {
|
|||
tokio::select! {
|
||||
value = &mut rx => {
|
||||
let value = value??;
|
||||
drop(droppable_token);
|
||||
droppable_token.disarm();
|
||||
Ok(serde_json::from_str(&value)?)
|
||||
}
|
||||
_ = token.cancelled() => {
|
||||
|
|
|
@ -9,6 +9,7 @@ use deno_npm::resolution::NpmResolutionSnapshot;
|
|||
use deno_runtime::deno_io::FromRawIoHandle;
|
||||
use deno_semver::package::PackageNv;
|
||||
use deno_semver::Version;
|
||||
use deno_task_shell::KillSignal;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashSet;
|
||||
use std::rc::Rc;
|
||||
|
@ -155,6 +156,29 @@ impl<'a> LifecycleScripts<'a> {
|
|||
packages: &[NpmResolutionPackage],
|
||||
root_node_modules_dir_path: &Path,
|
||||
progress_bar: &ProgressBar,
|
||||
) -> Result<(), AnyError> {
|
||||
let kill_signal = KillSignal::default();
|
||||
let _drop_signal = kill_signal.clone().drop_guard();
|
||||
// we don't run with signals forwarded because once signals
|
||||
// are setup then they're process wide.
|
||||
self
|
||||
.finish_with_cancellation(
|
||||
snapshot,
|
||||
packages,
|
||||
root_node_modules_dir_path,
|
||||
progress_bar,
|
||||
kill_signal,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn finish_with_cancellation(
|
||||
self,
|
||||
snapshot: &NpmResolutionSnapshot,
|
||||
packages: &[NpmResolutionPackage],
|
||||
root_node_modules_dir_path: &Path,
|
||||
progress_bar: &ProgressBar,
|
||||
kill_signal: KillSignal,
|
||||
) -> Result<(), AnyError> {
|
||||
self.warn_not_run_scripts()?;
|
||||
let get_package_path =
|
||||
|
@ -246,6 +270,7 @@ impl<'a> LifecycleScripts<'a> {
|
|||
stderr: TaskStdio::piped(),
|
||||
stdout: TaskStdio::piped(),
|
||||
}),
|
||||
kill_signal: kill_signal.clone(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
|
|
@ -14,6 +14,7 @@ use deno_runtime::deno_node::NodeResolver;
|
|||
use deno_semver::package::PackageNv;
|
||||
use deno_task_shell::ExecutableCommand;
|
||||
use deno_task_shell::ExecuteResult;
|
||||
use deno_task_shell::KillSignal;
|
||||
use deno_task_shell::ShellCommand;
|
||||
use deno_task_shell::ShellCommandContext;
|
||||
use deno_task_shell::ShellPipeReader;
|
||||
|
@ -22,6 +23,7 @@ use lazy_regex::Lazy;
|
|||
use regex::Regex;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::task::LocalSet;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::npm::InnerCliNpmResolverRef;
|
||||
|
@ -45,9 +47,11 @@ impl TaskStdio {
|
|||
pub fn stdout() -> Self {
|
||||
Self(None, ShellPipeWriter::stdout())
|
||||
}
|
||||
|
||||
pub fn stderr() -> Self {
|
||||
Self(None, ShellPipeWriter::stderr())
|
||||
}
|
||||
|
||||
pub fn piped() -> Self {
|
||||
let (r, w) = deno_task_shell::pipe();
|
||||
Self(Some(r), w)
|
||||
|
@ -62,8 +66,8 @@ pub struct TaskIo {
|
|||
impl Default for TaskIo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
stderr: TaskStdio::stderr(),
|
||||
stdout: TaskStdio::stdout(),
|
||||
stderr: TaskStdio::stderr(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +82,7 @@ pub struct RunTaskOptions<'a> {
|
|||
pub custom_commands: HashMap<String, Rc<dyn ShellCommand>>,
|
||||
pub root_node_modules_dir: Option<&'a Path>,
|
||||
pub stdio: Option<TaskIo>,
|
||||
pub kill_signal: KillSignal,
|
||||
}
|
||||
|
||||
pub type TaskCustomCommands = HashMap<String, Rc<dyn ShellCommand>>;
|
||||
|
@ -96,8 +101,12 @@ pub async fn run_task(
|
|||
.with_context(|| format!("Error parsing script '{}'.", opts.task_name))?;
|
||||
let env_vars =
|
||||
prepare_env_vars(opts.env_vars, opts.init_cwd, opts.root_node_modules_dir);
|
||||
let state =
|
||||
deno_task_shell::ShellState::new(env_vars, opts.cwd, opts.custom_commands);
|
||||
let state = deno_task_shell::ShellState::new(
|
||||
env_vars,
|
||||
opts.cwd,
|
||||
opts.custom_commands,
|
||||
opts.kill_signal,
|
||||
);
|
||||
let stdio = opts.stdio.unwrap_or_default();
|
||||
let (
|
||||
TaskStdio(stdout_read, stdout_write),
|
||||
|
@ -537,6 +546,80 @@ fn resolve_managed_npm_commands(
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
/// Runs a deno task future forwarding any signals received
|
||||
/// to the process.
|
||||
///
|
||||
/// Signal listeners and ctrl+c listening will be setup.
|
||||
pub async fn run_future_forwarding_signals<TOutput>(
|
||||
kill_signal: KillSignal,
|
||||
future: impl std::future::Future<Output = TOutput>,
|
||||
) -> TOutput {
|
||||
fn spawn_future_with_cancellation(
|
||||
future: impl std::future::Future<Output = ()> + 'static,
|
||||
token: CancellationToken,
|
||||
) {
|
||||
deno_core::unsync::spawn(async move {
|
||||
tokio::select! {
|
||||
_ = future => {}
|
||||
_ = token.cancelled() => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let token = CancellationToken::new();
|
||||
let _token_drop_guard = token.clone().drop_guard();
|
||||
let _drop_guard = kill_signal.clone().drop_guard();
|
||||
|
||||
spawn_future_with_cancellation(
|
||||
listen_ctrl_c(kill_signal.clone()),
|
||||
token.clone(),
|
||||
);
|
||||
#[cfg(unix)]
|
||||
spawn_future_with_cancellation(
|
||||
listen_and_forward_all_signals(kill_signal),
|
||||
token,
|
||||
);
|
||||
|
||||
future.await
|
||||
}
|
||||
|
||||
async fn listen_ctrl_c(kill_signal: KillSignal) {
|
||||
while let Ok(()) = tokio::signal::ctrl_c().await {
|
||||
kill_signal.send(deno_task_shell::SignalKind::SIGINT)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
async fn listen_and_forward_all_signals(kill_signal: KillSignal) {
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_runtime::signal::SIGNAL_NUMS;
|
||||
|
||||
// listen and forward every signal we support
|
||||
let mut futures = Vec::with_capacity(SIGNAL_NUMS.len());
|
||||
for signo in SIGNAL_NUMS.iter().copied() {
|
||||
if signo == libc::SIGKILL || signo == libc::SIGSTOP {
|
||||
continue; // skip, can't listen to these
|
||||
}
|
||||
|
||||
let kill_signal = kill_signal.clone();
|
||||
futures.push(
|
||||
async move {
|
||||
let Ok(mut stream) = tokio::signal::unix::signal(
|
||||
tokio::signal::unix::SignalKind::from_raw(signo),
|
||||
) else {
|
||||
return;
|
||||
};
|
||||
let signal_kind: deno_task_shell::SignalKind = signo.into();
|
||||
while let Some(()) = stream.recv().await {
|
||||
kill_signal.send(signal_kind);
|
||||
}
|
||||
}
|
||||
.boxed_local(),
|
||||
)
|
||||
}
|
||||
futures::future::join_all(futures).await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ use deno_core::futures::StreamExt;
|
|||
use deno_core::url::Url;
|
||||
use deno_path_util::normalize_path;
|
||||
use deno_runtime::deno_node::NodeResolver;
|
||||
use deno_task_shell::KillSignal;
|
||||
use deno_task_shell::ShellCommand;
|
||||
use indexmap::IndexMap;
|
||||
use regex::Regex;
|
||||
|
@ -37,6 +38,7 @@ use crate::colors;
|
|||
use crate::factory::CliFactory;
|
||||
use crate::npm::CliNpmResolver;
|
||||
use crate::task_runner;
|
||||
use crate::task_runner::run_future_forwarding_signals;
|
||||
use crate::util::fs::canonicalize_path;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -226,28 +228,33 @@ pub async fn execute_script(
|
|||
concurrency: no_of_concurrent_tasks.into(),
|
||||
};
|
||||
|
||||
if task_flags.eval {
|
||||
return task_runner
|
||||
.run_deno_task(
|
||||
&Url::from_directory_path(cli_options.initial_cwd()).unwrap(),
|
||||
"",
|
||||
&TaskDefinition {
|
||||
command: task_flags.task.as_ref().unwrap().to_string(),
|
||||
dependencies: vec![],
|
||||
description: None,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
for task_config in &packages_task_configs {
|
||||
let exit_code = task_runner.run_tasks(task_config).await?;
|
||||
if exit_code > 0 {
|
||||
return Ok(exit_code);
|
||||
let kill_signal = KillSignal::default();
|
||||
run_future_forwarding_signals(kill_signal.clone(), async {
|
||||
if task_flags.eval {
|
||||
return task_runner
|
||||
.run_deno_task(
|
||||
&Url::from_directory_path(cli_options.initial_cwd()).unwrap(),
|
||||
"",
|
||||
&TaskDefinition {
|
||||
command: task_flags.task.as_ref().unwrap().to_string(),
|
||||
dependencies: vec![],
|
||||
description: None,
|
||||
},
|
||||
kill_signal,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
for task_config in &packages_task_configs {
|
||||
let exit_code = task_runner.run_tasks(task_config, &kill_signal).await?;
|
||||
if exit_code > 0 {
|
||||
return Ok(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
struct RunSingleOptions<'a> {
|
||||
|
@ -255,6 +262,7 @@ struct RunSingleOptions<'a> {
|
|||
script: &'a str,
|
||||
cwd: &'a Path,
|
||||
custom_commands: HashMap<String, Rc<dyn ShellCommand>>,
|
||||
kill_signal: KillSignal,
|
||||
}
|
||||
|
||||
struct TaskRunner<'a> {
|
||||
|
@ -270,9 +278,10 @@ impl<'a> TaskRunner<'a> {
|
|||
pub async fn run_tasks(
|
||||
&self,
|
||||
pkg_tasks_config: &PackageTaskInfo,
|
||||
kill_signal: &KillSignal,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
match sort_tasks_topo(pkg_tasks_config) {
|
||||
Ok(sorted) => self.run_tasks_in_parallel(sorted).await,
|
||||
Ok(sorted) => self.run_tasks_in_parallel(sorted, kill_signal).await,
|
||||
Err(err) => match err {
|
||||
TaskError::NotFound(name) => {
|
||||
if self.task_flags.is_run {
|
||||
|
@ -307,6 +316,7 @@ impl<'a> TaskRunner<'a> {
|
|||
async fn run_tasks_in_parallel(
|
||||
&self,
|
||||
tasks: Vec<ResolvedTask<'a>>,
|
||||
kill_signal: &KillSignal,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
struct PendingTasksContext<'a> {
|
||||
completed: HashSet<usize>,
|
||||
|
@ -327,6 +337,7 @@ impl<'a> TaskRunner<'a> {
|
|||
fn get_next_task<'b>(
|
||||
&mut self,
|
||||
runner: &'b TaskRunner<'b>,
|
||||
kill_signal: &KillSignal,
|
||||
) -> Option<
|
||||
LocalBoxFuture<'b, Result<(i32, &'a ResolvedTask<'a>), AnyError>>,
|
||||
>
|
||||
|
@ -349,15 +360,23 @@ impl<'a> TaskRunner<'a> {
|
|||
}
|
||||
|
||||
self.running.insert(task.id);
|
||||
let kill_signal = kill_signal.clone();
|
||||
return Some(
|
||||
async move {
|
||||
match task.task_or_script {
|
||||
TaskOrScript::Task(_, def) => {
|
||||
runner.run_deno_task(task.folder_url, task.name, def).await
|
||||
runner
|
||||
.run_deno_task(task.folder_url, task.name, def, kill_signal)
|
||||
.await
|
||||
}
|
||||
TaskOrScript::Script(scripts, _) => {
|
||||
runner
|
||||
.run_npm_script(task.folder_url, task.name, scripts)
|
||||
.run_npm_script(
|
||||
task.folder_url,
|
||||
task.name,
|
||||
scripts,
|
||||
kill_signal,
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
@ -380,7 +399,7 @@ impl<'a> TaskRunner<'a> {
|
|||
|
||||
while context.has_remaining_tasks() {
|
||||
while queue.len() < self.concurrency {
|
||||
if let Some(task) = context.get_next_task(self) {
|
||||
if let Some(task) = context.get_next_task(self, kill_signal) {
|
||||
queue.push(task);
|
||||
} else {
|
||||
break;
|
||||
|
@ -409,6 +428,7 @@ impl<'a> TaskRunner<'a> {
|
|||
dir_url: &Url,
|
||||
task_name: &str,
|
||||
definition: &TaskDefinition,
|
||||
kill_signal: KillSignal,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
let cwd = match &self.task_flags.cwd {
|
||||
Some(path) => canonicalize_path(&PathBuf::from(path))
|
||||
|
@ -426,6 +446,7 @@ impl<'a> TaskRunner<'a> {
|
|||
script: &definition.command,
|
||||
cwd: &cwd,
|
||||
custom_commands,
|
||||
kill_signal,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
@ -435,6 +456,7 @@ impl<'a> TaskRunner<'a> {
|
|||
dir_url: &Url,
|
||||
task_name: &str,
|
||||
scripts: &IndexMap<String, String>,
|
||||
kill_signal: KillSignal,
|
||||
) -> Result<i32, deno_core::anyhow::Error> {
|
||||
// ensure the npm packages are installed if using a managed resolver
|
||||
if let Some(npm_resolver) = self.npm_resolver.as_managed() {
|
||||
|
@ -466,6 +488,7 @@ impl<'a> TaskRunner<'a> {
|
|||
script,
|
||||
cwd: &cwd,
|
||||
custom_commands: custom_commands.clone(),
|
||||
kill_signal: kill_signal.clone(),
|
||||
})
|
||||
.await?;
|
||||
if exit_code > 0 {
|
||||
|
@ -486,6 +509,7 @@ impl<'a> TaskRunner<'a> {
|
|||
script,
|
||||
cwd,
|
||||
custom_commands,
|
||||
kill_signal,
|
||||
} = opts;
|
||||
|
||||
output_task(
|
||||
|
@ -504,6 +528,7 @@ impl<'a> TaskRunner<'a> {
|
|||
argv: self.cli_options.argv(),
|
||||
root_node_modules_dir: self.npm_resolver.root_node_modules_path(),
|
||||
stdio: None,
|
||||
kill_signal,
|
||||
})
|
||||
.await?
|
||||
.exit_code,
|
||||
|
|
|
@ -34,6 +34,7 @@ pub mod inspector_server;
|
|||
pub mod js;
|
||||
pub mod ops;
|
||||
pub mod permissions;
|
||||
pub mod signal;
|
||||
pub mod snapshot;
|
||||
pub mod sys_info;
|
||||
pub mod tokio_util;
|
||||
|
|
|
@ -256,9 +256,7 @@ impl TryFrom<ExitStatus> for ChildStatus {
|
|||
success: false,
|
||||
code: 128 + signal,
|
||||
#[cfg(unix)]
|
||||
signal: Some(
|
||||
crate::ops::signal::signal_int_to_str(signal)?.to_string(),
|
||||
),
|
||||
signal: Some(crate::signal::signal_int_to_str(signal)?.to_string()),
|
||||
#[cfg(not(unix))]
|
||||
signal: None,
|
||||
}
|
||||
|
@ -1076,7 +1074,8 @@ mod deprecated {
|
|||
|
||||
#[cfg(unix)]
|
||||
pub fn kill(pid: i32, signal: &str) -> Result<(), ProcessError> {
|
||||
let signo = super::super::signal::signal_str_to_int(signal)?;
|
||||
let signo = crate::signal::signal_str_to_int(signal)
|
||||
.map_err(SignalError::InvalidSignalStr)?;
|
||||
use nix::sys::signal::kill as unix_kill;
|
||||
use nix::sys::signal::Signal;
|
||||
use nix::unistd::Pid;
|
||||
|
@ -1099,7 +1098,12 @@ mod deprecated {
|
|||
use winapi::um::winnt::PROCESS_TERMINATE;
|
||||
|
||||
if !matches!(signal, "SIGKILL" | "SIGTERM") {
|
||||
Err(SignalError::InvalidSignalStr(signal.to_string()).into())
|
||||
Err(
|
||||
SignalError::InvalidSignalStr(crate::signal::InvalidSignalStrError(
|
||||
signal.to_string(),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
} else if pid <= 0 {
|
||||
Err(ProcessError::InvalidPid)
|
||||
} else {
|
||||
|
|
|
@ -46,34 +46,10 @@ deno_core::extension!(
|
|||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SignalError {
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "macos",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos"
|
||||
))]
|
||||
#[error("Invalid signal: {0}")]
|
||||
InvalidSignalStr(String),
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "macos",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos"
|
||||
))]
|
||||
#[error("Invalid signal: {0}")]
|
||||
InvalidSignalInt(libc::c_int),
|
||||
#[cfg(target_os = "windows")]
|
||||
#[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")]
|
||||
InvalidSignalStr(String),
|
||||
#[cfg(target_os = "windows")]
|
||||
#[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")]
|
||||
InvalidSignalInt(libc::c_int),
|
||||
#[error(transparent)]
|
||||
InvalidSignalStr(#[from] crate::signal::InvalidSignalStrError),
|
||||
#[error(transparent)]
|
||||
InvalidSignalInt(#[from] crate::signal::InvalidSignalIntError),
|
||||
#[error("Binding to signal '{0}' is not allowed")]
|
||||
SignalNotAllowed(String),
|
||||
#[error("{0}")]
|
||||
|
@ -181,218 +157,6 @@ impl Resource for SignalStreamResource {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! first_literal {
|
||||
($head:literal $(, $tail:literal)*) => {
|
||||
$head
|
||||
};
|
||||
}
|
||||
macro_rules! signal_dict {
|
||||
($(($number:literal, $($name:literal)|+)),*) => {
|
||||
pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, SignalError> {
|
||||
match s {
|
||||
$($($name)|* => Ok($number),)*
|
||||
_ => Err(SignalError::InvalidSignalStr(s.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal_int_to_str(s: libc::c_int) -> Result<&'static str, SignalError> {
|
||||
match s {
|
||||
$($number => Ok(first_literal!($($name),+)),)*
|
||||
_ => Err(SignalError::InvalidSignalInt(s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGURG"),
|
||||
(17, "SIGSTOP"),
|
||||
(18, "SIGTSTP"),
|
||||
(19, "SIGCONT"),
|
||||
(20, "SIGCHLD"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGIO"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGINFO"),
|
||||
(30, "SIGUSR1"),
|
||||
(31, "SIGUSR2"),
|
||||
(32, "SIGTHR"),
|
||||
(33, "SIGLIBRT")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGURG"),
|
||||
(17, "SIGSTOP"),
|
||||
(18, "SIGTSTP"),
|
||||
(19, "SIGCONT"),
|
||||
(20, "SIGCHLD"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGIO"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGINFO"),
|
||||
(30, "SIGUSR1"),
|
||||
(31, "SIGUSR2"),
|
||||
(32, "SIGTHR")
|
||||
);
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGBUS"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGUSR1"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGUSR2"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGSTKFLT"),
|
||||
(17, "SIGCHLD"),
|
||||
(18, "SIGCONT"),
|
||||
(19, "SIGSTOP"),
|
||||
(20, "SIGTSTP"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGURG"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGIO" | "SIGPOLL"),
|
||||
(30, "SIGPWR"),
|
||||
(31, "SIGSYS" | "SIGUNUSED")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGURG"),
|
||||
(17, "SIGSTOP"),
|
||||
(18, "SIGTSTP"),
|
||||
(19, "SIGCONT"),
|
||||
(20, "SIGCHLD"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGIO"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGINFO"),
|
||||
(30, "SIGUSR1"),
|
||||
(31, "SIGUSR2")
|
||||
);
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGUSR1"),
|
||||
(17, "SIGUSR2"),
|
||||
(18, "SIGCHLD"),
|
||||
(19, "SIGPWR"),
|
||||
(20, "SIGWINCH"),
|
||||
(21, "SIGURG"),
|
||||
(22, "SIGPOLL"),
|
||||
(23, "SIGSTOP"),
|
||||
(24, "SIGTSTP"),
|
||||
(25, "SIGCONT"),
|
||||
(26, "SIGTTIN"),
|
||||
(27, "SIGTTOU"),
|
||||
(28, "SIGVTALRM"),
|
||||
(29, "SIGPROF"),
|
||||
(30, "SIGXCPU"),
|
||||
(31, "SIGXFSZ"),
|
||||
(32, "SIGWAITING"),
|
||||
(33, "SIGLWP"),
|
||||
(34, "SIGFREEZE"),
|
||||
(35, "SIGTHAW"),
|
||||
(36, "SIGCANCEL"),
|
||||
(37, "SIGLOST"),
|
||||
(38, "SIGXRES"),
|
||||
(39, "SIGJVM1"),
|
||||
(40, "SIGJVM2")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
signal_dict!((2, "SIGINT"), (21, "SIGBREAK"));
|
||||
|
||||
#[cfg(unix)]
|
||||
#[op2(fast)]
|
||||
#[smi]
|
||||
|
@ -400,7 +164,7 @@ fn op_signal_bind(
|
|||
state: &mut OpState,
|
||||
#[string] sig: &str,
|
||||
) -> Result<ResourceId, SignalError> {
|
||||
let signo = signal_str_to_int(sig)?;
|
||||
let signo = crate::signal::signal_str_to_int(sig)?;
|
||||
if signal_hook_registry::FORBIDDEN.contains(&signo) {
|
||||
return Err(SignalError::SignalNotAllowed(sig.to_string()));
|
||||
}
|
||||
|
@ -437,7 +201,7 @@ fn op_signal_bind(
|
|||
state: &mut OpState,
|
||||
#[string] sig: &str,
|
||||
) -> Result<ResourceId, SignalError> {
|
||||
let signo = signal_str_to_int(sig)?;
|
||||
let signo = crate::signal::signal_str_to_int(sig)?;
|
||||
let resource = SignalStreamResource {
|
||||
signal: AsyncRefCell::new(match signo {
|
||||
// SIGINT
|
||||
|
|
257
runtime/signal.rs
Normal file
257
runtime/signal.rs
Normal file
|
@ -0,0 +1,257 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")]
|
||||
pub struct InvalidSignalStrError(pub String);
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "macos",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos"
|
||||
))]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Invalid signal: {0}")]
|
||||
pub struct InvalidSignalStrError(pub String);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Windows only supports ctrl-c (SIGINT) and ctrl-break (SIGBREAK), but got {0}")]
|
||||
pub struct InvalidSignalIntError(pub libc::c_int);
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd",
|
||||
target_os = "openbsd",
|
||||
target_os = "macos",
|
||||
target_os = "solaris",
|
||||
target_os = "illumos"
|
||||
))]
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[error("Invalid signal: {0}")]
|
||||
pub struct InvalidSignalIntError(pub libc::c_int);
|
||||
|
||||
macro_rules! first_literal {
|
||||
($head:literal $(, $tail:literal)*) => {
|
||||
$head
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! signal_dict {
|
||||
($(($number:literal, $($name:literal)|+)),*) => {
|
||||
|
||||
pub const SIGNAL_NUMS: &'static [libc::c_int] = &[
|
||||
$(
|
||||
$number
|
||||
),*
|
||||
];
|
||||
|
||||
pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, InvalidSignalStrError> {
|
||||
match s {
|
||||
$($($name)|* => Ok($number),)*
|
||||
_ => Err(InvalidSignalStrError(s.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal_int_to_str(s: libc::c_int) -> Result<&'static str, InvalidSignalIntError> {
|
||||
match s {
|
||||
$($number => Ok(first_literal!($($name),+)),)*
|
||||
_ => Err(InvalidSignalIntError(s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "freebsd")]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGURG"),
|
||||
(17, "SIGSTOP"),
|
||||
(18, "SIGTSTP"),
|
||||
(19, "SIGCONT"),
|
||||
(20, "SIGCHLD"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGIO"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGINFO"),
|
||||
(30, "SIGUSR1"),
|
||||
(31, "SIGUSR2"),
|
||||
(32, "SIGTHR"),
|
||||
(33, "SIGLIBRT")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "openbsd")]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGURG"),
|
||||
(17, "SIGSTOP"),
|
||||
(18, "SIGTSTP"),
|
||||
(19, "SIGCONT"),
|
||||
(20, "SIGCHLD"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGIO"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGINFO"),
|
||||
(30, "SIGUSR1"),
|
||||
(31, "SIGUSR2"),
|
||||
(32, "SIGTHR")
|
||||
);
|
||||
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGBUS"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGUSR1"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGUSR2"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGSTKFLT"),
|
||||
(17, "SIGCHLD"),
|
||||
(18, "SIGCONT"),
|
||||
(19, "SIGSTOP"),
|
||||
(20, "SIGTSTP"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGURG"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGIO" | "SIGPOLL"),
|
||||
(30, "SIGPWR"),
|
||||
(31, "SIGSYS" | "SIGUNUSED")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGURG"),
|
||||
(17, "SIGSTOP"),
|
||||
(18, "SIGTSTP"),
|
||||
(19, "SIGCONT"),
|
||||
(20, "SIGCHLD"),
|
||||
(21, "SIGTTIN"),
|
||||
(22, "SIGTTOU"),
|
||||
(23, "SIGIO"),
|
||||
(24, "SIGXCPU"),
|
||||
(25, "SIGXFSZ"),
|
||||
(26, "SIGVTALRM"),
|
||||
(27, "SIGPROF"),
|
||||
(28, "SIGWINCH"),
|
||||
(29, "SIGINFO"),
|
||||
(30, "SIGUSR1"),
|
||||
(31, "SIGUSR2")
|
||||
);
|
||||
|
||||
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
||||
signal_dict!(
|
||||
(1, "SIGHUP"),
|
||||
(2, "SIGINT"),
|
||||
(3, "SIGQUIT"),
|
||||
(4, "SIGILL"),
|
||||
(5, "SIGTRAP"),
|
||||
(6, "SIGABRT" | "SIGIOT"),
|
||||
(7, "SIGEMT"),
|
||||
(8, "SIGFPE"),
|
||||
(9, "SIGKILL"),
|
||||
(10, "SIGBUS"),
|
||||
(11, "SIGSEGV"),
|
||||
(12, "SIGSYS"),
|
||||
(13, "SIGPIPE"),
|
||||
(14, "SIGALRM"),
|
||||
(15, "SIGTERM"),
|
||||
(16, "SIGUSR1"),
|
||||
(17, "SIGUSR2"),
|
||||
(18, "SIGCHLD"),
|
||||
(19, "SIGPWR"),
|
||||
(20, "SIGWINCH"),
|
||||
(21, "SIGURG"),
|
||||
(22, "SIGPOLL"),
|
||||
(23, "SIGSTOP"),
|
||||
(24, "SIGTSTP"),
|
||||
(25, "SIGCONT"),
|
||||
(26, "SIGTTIN"),
|
||||
(27, "SIGTTOU"),
|
||||
(28, "SIGVTALRM"),
|
||||
(29, "SIGPROF"),
|
||||
(30, "SIGXCPU"),
|
||||
(31, "SIGXFSZ"),
|
||||
(32, "SIGWAITING"),
|
||||
(33, "SIGLWP"),
|
||||
(34, "SIGFREEZE"),
|
||||
(35, "SIGTHAW"),
|
||||
(36, "SIGCANCEL"),
|
||||
(37, "SIGLOST"),
|
||||
(38, "SIGXRES"),
|
||||
(39, "SIGJVM1"),
|
||||
(40, "SIGJVM2")
|
||||
);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
signal_dict!((2, "SIGINT"), (21, "SIGBREAK"));
|
8
tests/specs/task/signals/__test__.jsonc
Normal file
8
tests/specs/task/signals/__test__.jsonc
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
// signals don't really exist on windows
|
||||
"if": "unix",
|
||||
// this runs a deno task
|
||||
"args": "run -A --check sender.ts",
|
||||
// just ensure this doesn't hang and completes successfully
|
||||
"output": "[WILDCARD]"
|
||||
}
|
5
tests/specs/task/signals/deno.jsonc
Normal file
5
tests/specs/task/signals/deno.jsonc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"tasks": {
|
||||
"listener": "deno run listener.ts"
|
||||
}
|
||||
}
|
16
tests/specs/task/signals/listener.ts
Normal file
16
tests/specs/task/signals/listener.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { signals } from "./signals.ts";
|
||||
|
||||
for (const signal of signals) {
|
||||
Deno.addSignalListener(signal, () => {
|
||||
console.log("Received", signal);
|
||||
if (signal === "SIGTERM") {
|
||||
Deno.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
// keep alive
|
||||
}, 1000);
|
||||
|
||||
console.log("Ready");
|
55
tests/specs/task/signals/sender.ts
Normal file
55
tests/specs/task/signals/sender.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { signals } from "./signals.ts";
|
||||
|
||||
class StdoutReader {
|
||||
readonly #reader: ReadableStreamDefaultReader<string>;
|
||||
#text = "";
|
||||
|
||||
constructor(stream: ReadableStream<Uint8Array>) {
|
||||
const textStream = stream.pipeThrough(new TextDecoderStream());
|
||||
this.#reader = textStream.getReader();
|
||||
}
|
||||
|
||||
[Symbol.dispose]() {
|
||||
this.#reader.releaseLock();
|
||||
}
|
||||
|
||||
async waitForText(waitingText: string) {
|
||||
if (this.#text.includes(waitingText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
const { value, done } = await this.#reader.read();
|
||||
if (value) {
|
||||
this.#text += value;
|
||||
if (this.#text.includes(waitingText)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
throw new Error("Did not find text: " + waitingText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const command = new Deno.Command(Deno.execPath(), {
|
||||
args: ["task", "listener"],
|
||||
stdout: "piped",
|
||||
});
|
||||
|
||||
const child = command.spawn();
|
||||
const reader = new StdoutReader(child.stdout!);
|
||||
await reader.waitForText("Ready");
|
||||
|
||||
for (const signal of signals) {
|
||||
if (signal === "SIGTERM") {
|
||||
continue;
|
||||
}
|
||||
console.error("Sending", signal);
|
||||
child.kill(signal);
|
||||
await reader.waitForText("Received " + signal);
|
||||
}
|
||||
|
||||
console.error("Sending SIGTERM");
|
||||
child.kill("SIGTERM");
|
65
tests/specs/task/signals/signals.ts
Normal file
65
tests/specs/task/signals/signals.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
const signals = [
|
||||
"SIGABRT",
|
||||
"SIGALRM",
|
||||
"SIGBUS",
|
||||
"SIGCHLD",
|
||||
"SIGCONT",
|
||||
"SIGEMT",
|
||||
"SIGFPE",
|
||||
"SIGHUP",
|
||||
"SIGILL",
|
||||
"SIGINFO",
|
||||
"SIGINT",
|
||||
"SIGIO",
|
||||
"SIGPOLL",
|
||||
"SIGPIPE",
|
||||
"SIGPROF",
|
||||
"SIGPWR",
|
||||
"SIGQUIT",
|
||||
"SIGSEGV",
|
||||
"SIGSTKFLT",
|
||||
"SIGSYS",
|
||||
"SIGTERM",
|
||||
"SIGTRAP",
|
||||
"SIGTSTP",
|
||||
"SIGTTIN",
|
||||
"SIGTTOU",
|
||||
"SIGURG",
|
||||
"SIGUSR1",
|
||||
"SIGUSR2",
|
||||
"SIGVTALRM",
|
||||
"SIGWINCH",
|
||||
"SIGXCPU",
|
||||
"SIGXFSZ",
|
||||
] as const;
|
||||
|
||||
// SIGKILL and SIGSTOP are not stoppable, SIGBREAK is for windows, and SIGUNUSED is not defined
|
||||
type SignalsToTest = Exclude<
|
||||
Deno.Signal,
|
||||
"SIGKILL" | "SIGSTOP" | "SIGBREAK" | "SIGUNUSED"
|
||||
>;
|
||||
type EnsureAllSignalsIncluded = SignalsToTest extends typeof signals[number]
|
||||
? typeof signals[number] extends SignalsToTest ? true
|
||||
: never
|
||||
: never;
|
||||
const _checkSignals: EnsureAllSignalsIncluded = true;
|
||||
|
||||
const osSpecificSignals = signals.filter((s) => {
|
||||
switch (s) {
|
||||
case "SIGEMT":
|
||||
return Deno.build.os === "darwin";
|
||||
case "SIGINFO":
|
||||
case "SIGFPE":
|
||||
case "SIGILL":
|
||||
case "SIGSEGV":
|
||||
return Deno.build.os === "freebsd";
|
||||
case "SIGPOLL":
|
||||
case "SIGPWR":
|
||||
case "SIGSTKFLT":
|
||||
return Deno.build.os === "linux";
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
export { osSpecificSignals as signals };
|
Loading…
Reference in a new issue