1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 23:34:47 -05:00
denoland-deno/runtime/ops/signal.rs
Bartek Iwańczuk f3c0f0565b
feat(core): Add ability to "ref" and "unref" pending ops (#12889)
This commit adds an ability to "ref" or "unref" pending ops.

Up to this point Deno had a notion of "async ops" and "unref async ops";
the former keep event loop alive, while the latter do not block event loop
from finishing. It was not possible to change between op types after
dispatching, one had to decide which type to use before dispatch.

Instead of storing ops in two separate "FuturesUnordered" collections,
now ops are stored in a single collection, with supplemental "HashSet"
storing ids of promises that were "unrefed".

Two APIs were added to "Deno.core":

"Deno.core.refOp(promiseId)" which allows to mark promise id
to be "refed" and keep event loop alive (the default behavior)
"Deno.core.unrefOp(promiseId)" which allows to mark promise
id as "unrefed" which won't block event loop from exiting
2021-11-25 19:49:09 +01:00

249 lines
5.7 KiB
Rust

// Copyright 2018-2021 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_async;
use deno_core::op_sync;
use deno_core::Extension;
use deno_core::OpState;
use std::cell::RefCell;
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", op_sync(op_signal_bind)),
("op_signal_unbind", op_sync(op_signal_unbind)),
("op_signal_poll", op_async(op_signal_poll)),
])
.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(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(unix)]
fn op_signal_bind(
state: &mut OpState,
sig: String,
_: (),
) -> Result<ResourceId, AnyError> {
super::check_unstable(state, "Deno.signal");
let signo = signal_str_to_int(&sig)?;
let resource = SignalStreamResource {
signal: AsyncRefCell::new(signal(SignalKind::from_raw(signo)).unwrap()),
cancel: Default::default(),
};
let rid = state.resource_table.add(resource);
Ok(rid)
}
#[cfg(unix)]
async fn op_signal_poll(
state: Rc<RefCell<OpState>>,
rid: ResourceId,
_: (),
) -> Result<bool, AnyError> {
super::check_unstable2(&state, "Deno.signal");
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)]
pub fn op_signal_unbind(
state: &mut OpState,
rid: ResourceId,
_: (),
) -> Result<(), AnyError> {
super::check_unstable(state, "Deno.signal");
state.resource_table.close(rid)?;
Ok(())
}
#[cfg(not(unix))]
pub fn op_signal_bind(
_state: &mut OpState,
_: (),
_: (),
) -> Result<(), AnyError> {
Err(generic_error("not implemented"))
}
#[cfg(not(unix))]
fn op_signal_unbind(
_state: &mut OpState,
_: (),
_: (),
) -> Result<(), AnyError> {
Err(generic_error("not implemented"))
}
#[cfg(not(unix))]
async fn op_signal_poll(
_state: Rc<RefCell<OpState>>,
_: (),
_: (),
) -> Result<(), AnyError> {
Err(generic_error("not implemented"))
}