signals: Move signal handling to its own crate
We're going to share this code with `radicle-term`.
This commit is contained in:
parent
425e7b5092
commit
2801403182
|
|
@ -2551,6 +2551,7 @@ dependencies = [
|
||||||
"radicle-crypto",
|
"radicle-crypto",
|
||||||
"radicle-fetch",
|
"radicle-fetch",
|
||||||
"radicle-git-ext",
|
"radicle-git-ext",
|
||||||
|
"radicle-signals",
|
||||||
"scrypt",
|
"scrypt",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
|
@ -2572,6 +2573,14 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radicle-signals"
|
||||||
|
version = "0.9.0"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "radicle-ssh"
|
name = "radicle-ssh"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ members = [
|
||||||
"radicle-remote-helper",
|
"radicle-remote-helper",
|
||||||
"radicle-ssh",
|
"radicle-ssh",
|
||||||
"radicle-tools",
|
"radicle-tools",
|
||||||
|
"radicle-signals",
|
||||||
]
|
]
|
||||||
default-members = [
|
default-members = [
|
||||||
"radicle",
|
"radicle",
|
||||||
|
|
@ -25,6 +26,7 @@ default-members = [
|
||||||
"radicle-ssh",
|
"radicle-ssh",
|
||||||
"radicle-remote-helper",
|
"radicle-remote-helper",
|
||||||
"radicle-term",
|
"radicle-term",
|
||||||
|
"radicle-signals",
|
||||||
]
|
]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ features = ["logger"]
|
||||||
path = "../radicle-fetch"
|
path = "../radicle-fetch"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
|
||||||
|
[dependencies.radicle-signals]
|
||||||
|
path = "../radicle-signals"
|
||||||
|
version = "0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
radicle = { path = "../radicle", version = "0", features = ["test"] }
|
radicle = { path = "../radicle", version = "0", features = ["test"] }
|
||||||
radicle-crypto = { path = "../radicle-crypto", version = "0", features = ["test", "cyphernet"] }
|
radicle-crypto = { path = "../radicle-crypto", version = "0", features = ["test", "cyphernet"] }
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ pub mod control;
|
||||||
pub mod deserializer;
|
pub mod deserializer;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
pub mod service;
|
pub mod service;
|
||||||
pub mod signals;
|
|
||||||
#[cfg(any(test, feature = "test"))]
|
#[cfg(any(test, feature = "test"))]
|
||||||
pub mod test;
|
pub mod test;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ use radicle::prelude::Signer;
|
||||||
use radicle::profile;
|
use radicle::profile;
|
||||||
use radicle::version::Version;
|
use radicle::version::Version;
|
||||||
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
|
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
|
||||||
use radicle_node::signals;
|
|
||||||
use radicle_node::Runtime;
|
use radicle_node::Runtime;
|
||||||
|
use radicle_signals as signals;
|
||||||
|
|
||||||
pub const VERSION: Version = Version {
|
pub const VERSION: Version = Version {
|
||||||
name: env!("CARGO_PKG_NAME"),
|
name: env!("CARGO_PKG_NAME"),
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ use crossbeam_channel as chan;
|
||||||
use cyphernet::Ecdh;
|
use cyphernet::Ecdh;
|
||||||
use netservices::resource::NetAccept;
|
use netservices::resource::NetAccept;
|
||||||
use radicle_fetch::FetchLimit;
|
use radicle_fetch::FetchLimit;
|
||||||
|
use radicle_signals::Signal;
|
||||||
use reactor::poller::popol;
|
use reactor::poller::popol;
|
||||||
use reactor::Reactor;
|
use reactor::Reactor;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -128,7 +129,7 @@ pub struct Runtime {
|
||||||
pub reactor: Reactor<wire::Control, popol::Poller>,
|
pub reactor: Reactor<wire::Control, popol::Poller>,
|
||||||
pub pool: worker::Pool,
|
pub pool: worker::Pool,
|
||||||
pub local_addrs: Vec<net::SocketAddr>,
|
pub local_addrs: Vec<net::SocketAddr>,
|
||||||
pub signals: chan::Receiver<()>,
|
pub signals: chan::Receiver<Signal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runtime {
|
impl Runtime {
|
||||||
|
|
@ -139,7 +140,7 @@ impl Runtime {
|
||||||
home: Home,
|
home: Home,
|
||||||
config: service::Config,
|
config: service::Config,
|
||||||
listen: Vec<net::SocketAddr>,
|
listen: Vec<net::SocketAddr>,
|
||||||
signals: chan::Receiver<()>,
|
signals: chan::Receiver<Signal>,
|
||||||
signer: G,
|
signer: G,
|
||||||
) -> Result<Runtime, Error>
|
) -> Result<Runtime, Error>
|
||||||
where
|
where
|
||||||
|
|
@ -306,7 +307,7 @@ impl Runtime {
|
||||||
|| control::listen(self.control, handle)
|
|| control::listen(self.control, handle)
|
||||||
});
|
});
|
||||||
let _signals = thread::spawn(&self.id, "signals", move || {
|
let _signals = thread::spawn(&self.id, "signals", move || {
|
||||||
if let Ok(()) = self.signals.recv() {
|
if let Ok(Signal::Terminate | Signal::Interrupt) = self.signals.recv() {
|
||||||
log::info!(target: "node", "Termination signal received; shutting down..");
|
log::info!(target: "node", "Termination signal received; shutting down..");
|
||||||
self.handle.shutdown().ok();
|
self.handle.shutdown().ok();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "radicle-signals"
|
||||||
|
homepage = "https://radicle.xyz"
|
||||||
|
repository = "https://app.radicle.xyz/seeds/seed.radicle.xyz/rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5"
|
||||||
|
edition = "2021"
|
||||||
|
version = "0.9.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
crossbeam-channel = { version = "0.5.6" }
|
||||||
|
libc = { version = "0.2" }
|
||||||
|
|
@ -3,11 +3,38 @@ use std::sync::Mutex;
|
||||||
|
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
|
|
||||||
/// Signal notifications are sent via this channel.
|
/// Operating system signal.
|
||||||
static NOTIFY: Mutex<Option<chan::Sender<()>>> = Mutex::new(None);
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Signal {
|
||||||
|
/// `SIGINT`.
|
||||||
|
Interrupt,
|
||||||
|
/// `SIGTERM`.
|
||||||
|
Terminate,
|
||||||
|
/// `SIGHUP`.
|
||||||
|
Hangup,
|
||||||
|
/// `SIGWINCH`.
|
||||||
|
WindowChanged,
|
||||||
|
}
|
||||||
|
|
||||||
/// Install global signal handlers for `SIGTERM` and `SIGINT`.
|
impl TryFrom<i32> for Signal {
|
||||||
pub fn install(notify: chan::Sender<()>) -> io::Result<()> {
|
type Error = i32;
|
||||||
|
|
||||||
|
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
libc::SIGTERM => Ok(Self::Terminate),
|
||||||
|
libc::SIGINT => Ok(Self::Interrupt),
|
||||||
|
libc::SIGWINCH => Ok(Self::WindowChanged),
|
||||||
|
libc::SIGHUP => Ok(Self::Hangup),
|
||||||
|
_ => Err(value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signal notifications are sent via this channel.
|
||||||
|
static NOTIFY: Mutex<Option<chan::Sender<Signal>>> = Mutex::new(None);
|
||||||
|
|
||||||
|
/// Install global signal handlers.
|
||||||
|
pub fn install(notify: chan::Sender<Signal>) -> io::Result<()> {
|
||||||
if let Ok(mut channel) = NOTIFY.try_lock() {
|
if let Ok(mut channel) = NOTIFY.try_lock() {
|
||||||
if channel.is_some() {
|
if channel.is_some() {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
|
|
@ -27,7 +54,7 @@ pub fn install(notify: chan::Sender<()>) -> io::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Install global signal handlers for `SIGTERM` and `SIGINT`.
|
/// Install global signal handlers.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
|
@ -39,17 +66,23 @@ unsafe fn _install() -> io::Result<()> {
|
||||||
if libc::signal(libc::SIGINT, handler as libc::sighandler_t) == libc::SIG_ERR {
|
if libc::signal(libc::SIGINT, handler as libc::sighandler_t) == libc::SIG_ERR {
|
||||||
return Err(io::Error::last_os_error());
|
return Err(io::Error::last_os_error());
|
||||||
}
|
}
|
||||||
|
if libc::signal(libc::SIGHUP, handler as libc::sighandler_t) == libc::SIG_ERR {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
if libc::signal(libc::SIGWINCH, handler as libc::sighandler_t) == libc::SIG_ERR {
|
||||||
|
return Err(io::Error::last_os_error());
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called by `libc` when a signal is received.
|
/// Called by `libc` when a signal is received.
|
||||||
extern "C" fn handler(sig: libc::c_int, _info: *mut libc::siginfo_t, _data: *mut libc::c_void) {
|
extern "C" fn handler(sig: libc::c_int, _info: *mut libc::siginfo_t, _data: *mut libc::c_void) {
|
||||||
if sig != libc::SIGTERM && sig != libc::SIGINT {
|
let Ok(sig) = sig.try_into() else {
|
||||||
return;
|
return;
|
||||||
}
|
};
|
||||||
if let Ok(guard) = NOTIFY.try_lock() {
|
if let Ok(guard) = NOTIFY.try_lock() {
|
||||||
if let Some(c) = &*guard {
|
if let Some(c) = &*guard {
|
||||||
c.try_send(()).ok();
|
c.try_send(sig).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue