mirror of
https://github.com/denoland/deno.git
synced 2024-12-11 01:58:05 -05:00
295 lines
6.8 KiB
Rust
295 lines
6.8 KiB
Rust
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
|
#[cfg(not(unix))]
|
|
use deno_core::error::generic_error;
|
|
#[cfg(not(target_os = "windows"))]
|
|
use deno_core::error::type_error;
|
|
use deno_core::error::AnyError;
|
|
use deno_core::op;
|
|
|
|
use deno_core::Extension;
|
|
#[cfg(unix)]
|
|
use deno_core::OpState;
|
|
#[cfg(unix)]
|
|
use std::cell::RefCell;
|
|
#[cfg(unix)]
|
|
use std::rc::Rc;
|
|
|
|
#[cfg(unix)]
|
|
use deno_core::AsyncRefCell;
|
|
#[cfg(unix)]
|
|
use deno_core::CancelFuture;
|
|
#[cfg(unix)]
|
|
use deno_core::CancelHandle;
|
|
#[cfg(unix)]
|
|
use deno_core::RcRef;
|
|
#[cfg(unix)]
|
|
use deno_core::Resource;
|
|
#[cfg(unix)]
|
|
use deno_core::ResourceId;
|
|
#[cfg(unix)]
|
|
use std::borrow::Cow;
|
|
#[cfg(unix)]
|
|
use tokio::signal::unix::{signal, Signal, SignalKind};
|
|
|
|
pub fn init() -> Extension {
|
|
Extension::builder()
|
|
.ops(vec![
|
|
op_signal_bind::decl(),
|
|
op_signal_unbind::decl(),
|
|
op_signal_poll::decl(),
|
|
])
|
|
.build()
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
/// The resource for signal stream.
|
|
/// The second element is the waker of polling future.
|
|
struct SignalStreamResource {
|
|
signal: AsyncRefCell<Signal>,
|
|
cancel: CancelHandle,
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
impl Resource for SignalStreamResource {
|
|
fn name(&self) -> Cow<str> {
|
|
"signal".into()
|
|
}
|
|
|
|
fn close(self: Rc<Self>) {
|
|
self.cancel.cancel();
|
|
}
|
|
}
|
|
|
|
#[cfg(target_os = "freebsd")]
|
|
pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, AnyError> {
|
|
match s {
|
|
"SIGHUP" => Ok(1),
|
|
"SIGINT" => Ok(2),
|
|
"SIGQUIT" => Ok(3),
|
|
"SIGILL" => Ok(4),
|
|
"SIGTRAP" => Ok(5),
|
|
"SIGABRT" => Ok(6),
|
|
"SIGEMT" => Ok(7),
|
|
"SIGFPE" => Ok(8),
|
|
"SIGKILL" => Ok(9),
|
|
"SIGBUS" => Ok(10),
|
|
"SIGSEGV" => Ok(11),
|
|
"SIGSYS" => Ok(12),
|
|
"SIGPIPE" => Ok(13),
|
|
"SIGALRM" => Ok(14),
|
|
"SIGTERM" => Ok(15),
|
|
"SIGURG" => Ok(16),
|
|
"SIGSTOP" => Ok(17),
|
|
"SIGTSTP" => Ok(18),
|
|
"SIGCONT" => Ok(19),
|
|
"SIGCHLD" => Ok(20),
|
|
"SIGTTIN" => Ok(21),
|
|
"SIGTTOU" => Ok(22),
|
|
"SIGIO" => Ok(23),
|
|
"SIGXCPU" => Ok(24),
|
|
"SIGXFSZ" => Ok(25),
|
|
"SIGVTALRM" => Ok(26),
|
|
"SIGPROF" => Ok(27),
|
|
"SIGWINCH" => Ok(28),
|
|
"SIGINFO" => Ok(29),
|
|
"SIGUSR1" => Ok(30),
|
|
"SIGUSR2" => Ok(31),
|
|
"SIGTHR" => Ok(32),
|
|
"SIGLIBRT" => Ok(33),
|
|
_ => Err(type_error(format!("Invalid signal : {}", s))),
|
|
}
|
|
}
|
|
|
|
#[cfg(any(target_os = "android", target_os = "linux"))]
|
|
pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, AnyError> {
|
|
match s {
|
|
"SIGHUP" => Ok(1),
|
|
"SIGINT" => Ok(2),
|
|
"SIGQUIT" => Ok(3),
|
|
"SIGILL" => Ok(4),
|
|
"SIGTRAP" => Ok(5),
|
|
"SIGABRT" => Ok(6),
|
|
"SIGBUS" => Ok(7),
|
|
"SIGFPE" => Ok(8),
|
|
"SIGKILL" => Ok(9),
|
|
"SIGUSR1" => Ok(10),
|
|
"SIGSEGV" => Ok(11),
|
|
"SIGUSR2" => Ok(12),
|
|
"SIGPIPE" => Ok(13),
|
|
"SIGALRM" => Ok(14),
|
|
"SIGTERM" => Ok(15),
|
|
"SIGSTKFLT" => Ok(16),
|
|
"SIGCHLD" => Ok(17),
|
|
"SIGCONT" => Ok(18),
|
|
"SIGSTOP" => Ok(19),
|
|
"SIGTSTP" => Ok(20),
|
|
"SIGTTIN" => Ok(21),
|
|
"SIGTTOU" => Ok(22),
|
|
"SIGURG" => Ok(23),
|
|
"SIGXCPU" => Ok(24),
|
|
"SIGXFSZ" => Ok(25),
|
|
"SIGVTALRM" => Ok(26),
|
|
"SIGPROF" => Ok(27),
|
|
"SIGWINCH" => Ok(28),
|
|
"SIGIO" => Ok(29),
|
|
"SIGPWR" => Ok(30),
|
|
"SIGSYS" => Ok(31),
|
|
_ => Err(type_error(format!("Invalid signal : {}", s))),
|
|
}
|
|
}
|
|
|
|
#[cfg(target_os = "macos")]
|
|
pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, AnyError> {
|
|
match s {
|
|
"SIGHUP" => Ok(1),
|
|
"SIGINT" => Ok(2),
|
|
"SIGQUIT" => Ok(3),
|
|
"SIGILL" => Ok(4),
|
|
"SIGTRAP" => Ok(5),
|
|
"SIGABRT" => Ok(6),
|
|
"SIGEMT" => Ok(7),
|
|
"SIGFPE" => Ok(8),
|
|
"SIGKILL" => Ok(9),
|
|
"SIGBUS" => Ok(10),
|
|
"SIGSEGV" => Ok(11),
|
|
"SIGSYS" => Ok(12),
|
|
"SIGPIPE" => Ok(13),
|
|
"SIGALRM" => Ok(14),
|
|
"SIGTERM" => Ok(15),
|
|
"SIGURG" => Ok(16),
|
|
"SIGSTOP" => Ok(17),
|
|
"SIGTSTP" => Ok(18),
|
|
"SIGCONT" => Ok(19),
|
|
"SIGCHLD" => Ok(20),
|
|
"SIGTTIN" => Ok(21),
|
|
"SIGTTOU" => Ok(22),
|
|
"SIGIO" => Ok(23),
|
|
"SIGXCPU" => Ok(24),
|
|
"SIGXFSZ" => Ok(25),
|
|
"SIGVTALRM" => Ok(26),
|
|
"SIGPROF" => Ok(27),
|
|
"SIGWINCH" => Ok(28),
|
|
"SIGINFO" => Ok(29),
|
|
"SIGUSR1" => Ok(30),
|
|
"SIGUSR2" => Ok(31),
|
|
_ => Err(type_error(format!("Invalid signal: {}", s))),
|
|
}
|
|
}
|
|
|
|
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
|
|
pub fn signal_str_to_int(s: &str) -> Result<libc::c_int, AnyError> {
|
|
match s {
|
|
"SIGHUP" => Ok(1),
|
|
"SIGINT" => Ok(2),
|
|
"SIGQUIT" => Ok(3),
|
|
"SIGILL" => Ok(4),
|
|
"SIGTRAP" => Ok(5),
|
|
"SIGIOT" => Ok(6),
|
|
"SIGABRT" => Ok(6),
|
|
"SIGEMT" => Ok(7),
|
|
"SIGFPE" => Ok(8),
|
|
"SIGKILL" => Ok(9),
|
|
"SIGBUS" => Ok(10),
|
|
"SIGSEGV" => Ok(11),
|
|
"SIGSYS" => Ok(12),
|
|
"SIGPIPE" => Ok(13),
|
|
"SIGALRM" => Ok(14),
|
|
"SIGTERM" => Ok(15),
|
|
"SIGUSR1" => Ok(16),
|
|
"SIGUSR2" => Ok(17),
|
|
"SIGCLD" => Ok(18),
|
|
"SIGCHLD" => Ok(18),
|
|
"SIGPWR" => Ok(19),
|
|
"SIGWINCH" => Ok(20),
|
|
"SIGURG" => Ok(21),
|
|
"SIGPOLL" => Ok(22),
|
|
"SIGIO" => Ok(22),
|
|
"SIGSTOP" => Ok(23),
|
|
"SIGTSTP" => Ok(24),
|
|
"SIGCONT" => Ok(25),
|
|
"SIGTTIN" => Ok(26),
|
|
"SIGTTOU" => Ok(27),
|
|
"SIGVTALRM" => Ok(28),
|
|
"SIGPROF" => Ok(29),
|
|
"SIGXCPU" => Ok(30),
|
|
"SIGXFSZ" => Ok(31),
|
|
"SIGWAITING" => Ok(32),
|
|
"SIGLWP" => Ok(33),
|
|
"SIGFREEZE" => Ok(34),
|
|
"SIGTHAW" => Ok(35),
|
|
"SIGCANCEL" => Ok(36),
|
|
"SIGLOST" => Ok(37),
|
|
"SIGXRES" => Ok(38),
|
|
"SIGJVM1" => Ok(39),
|
|
"SIGJVM2" => Ok(40),
|
|
_ => Err(type_error(format!("Invalid signal : {}", s))),
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[op]
|
|
fn op_signal_bind(
|
|
state: &mut OpState,
|
|
sig: String,
|
|
) -> Result<ResourceId, AnyError> {
|
|
let signo = signal_str_to_int(&sig)?;
|
|
if signal_hook_registry::FORBIDDEN.contains(&signo) {
|
|
return Err(type_error(format!(
|
|
"Binding to signal '{}' is not allowed",
|
|
sig
|
|
)));
|
|
}
|
|
let resource = SignalStreamResource {
|
|
signal: AsyncRefCell::new(signal(SignalKind::from_raw(signo))?),
|
|
cancel: Default::default(),
|
|
};
|
|
let rid = state.resource_table.add(resource);
|
|
Ok(rid)
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[op]
|
|
async fn op_signal_poll(
|
|
state: Rc<RefCell<OpState>>,
|
|
rid: ResourceId,
|
|
) -> Result<bool, AnyError> {
|
|
let resource = state
|
|
.borrow_mut()
|
|
.resource_table
|
|
.get::<SignalStreamResource>(rid)?;
|
|
let cancel = RcRef::map(&resource, |r| &r.cancel);
|
|
let mut signal = RcRef::map(&resource, |r| &r.signal).borrow_mut().await;
|
|
|
|
match signal.recv().or_cancel(cancel).await {
|
|
Ok(result) => Ok(result.is_none()),
|
|
Err(_) => Ok(true),
|
|
}
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
#[op]
|
|
pub fn op_signal_unbind(
|
|
state: &mut OpState,
|
|
rid: ResourceId,
|
|
) -> Result<(), AnyError> {
|
|
state.resource_table.close(rid)?;
|
|
Ok(())
|
|
}
|
|
|
|
#[cfg(not(unix))]
|
|
#[op]
|
|
pub fn op_signal_bind() -> Result<(), AnyError> {
|
|
Err(generic_error("not implemented"))
|
|
}
|
|
|
|
#[cfg(not(unix))]
|
|
#[op]
|
|
fn op_signal_unbind() -> Result<(), AnyError> {
|
|
Err(generic_error("not implemented"))
|
|
}
|
|
|
|
#[cfg(not(unix))]
|
|
#[op]
|
|
async fn op_signal_poll() -> Result<(), AnyError> {
|
|
Err(generic_error("not implemented"))
|
|
}
|