// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use super::dispatch_json::Value; use crate::state::State; use deno_core::BufVec; use deno_core::CoreIsolate; use deno_core::ErrBox; use deno_core::ResourceTable; use deno_core::ZeroCopyBuf; use std::cell::RefCell; use std::rc::Rc; #[cfg(unix)] use super::dispatch_json::Deserialize; #[cfg(unix)] use futures::future::poll_fn; #[cfg(unix)] use std::task::Waker; #[cfg(unix)] use tokio::signal::unix::{signal, Signal, SignalKind}; pub fn init(i: &mut CoreIsolate, s: &Rc) { let t = &CoreIsolate::state(i).borrow().resource_table.clone(); i.register_op("op_signal_bind", s.stateful_json_op_sync(t, op_signal_bind)); i.register_op( "op_signal_unbind", s.stateful_json_op_sync(t, op_signal_unbind), ); i.register_op( "op_signal_poll", s.stateful_json_op_async(t, 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); #[cfg(unix)] #[derive(Deserialize)] struct BindSignalArgs { signo: i32, } #[cfg(unix)] #[derive(Deserialize)] struct SignalArgs { rid: i32, } #[cfg(unix)] fn op_signal_bind( state: &State, resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result { state.check_unstable("Deno.signal"); let args: BindSignalArgs = serde_json::from_value(args)?; let rid = resource_table.add( "signal", Box::new(SignalStreamResource( signal(SignalKind::from_raw(args.signo)).expect(""), None, )), ); Ok(json!({ "rid": rid, })) } #[cfg(unix)] async fn op_signal_poll( state: Rc, resource_table: Rc>, args: Value, _zero_copy: BufVec, ) -> Result { state.check_unstable("Deno.signal"); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let future = poll_fn(move |cx| { let mut resource_table = resource_table.borrow_mut(); if let Some(mut signal) = resource_table.get_mut::(rid) { signal.1 = Some(cx.waker().clone()); return signal.0.poll_recv(cx); } std::task::Poll::Ready(None) }); let result = future.await; Ok(json!({ "done": result.is_none() })) } #[cfg(unix)] pub fn op_signal_unbind( state: &State, resource_table: &mut ResourceTable, args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result { state.check_unstable("Deno.signal"); let args: SignalArgs = serde_json::from_value(args)?; let rid = args.rid as u32; let resource = resource_table.get::(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(); } } resource_table .close(rid) .ok_or_else(ErrBox::bad_resource_id)?; Ok(json!({})) } #[cfg(not(unix))] pub fn op_signal_bind( _state: &State, _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result { unimplemented!(); } #[cfg(not(unix))] fn op_signal_unbind( _state: &State, _resource_table: &mut ResourceTable, _args: Value, _zero_copy: &mut [ZeroCopyBuf], ) -> Result { unimplemented!(); } #[cfg(not(unix))] async fn op_signal_poll( _state: Rc, _resource_table: Rc>, _args: Value, _zero_copy: BufVec, ) -> Result { unimplemented!(); }