fix: join the RNS loop thread before exit and keep the response slot per-request
This commit is contained in:
parent
39c4c4d6a5
commit
234b75651f
17 changed files with 84 additions and 11 deletions
|
|
@ -42,6 +42,8 @@ mod inner {
|
|||
) -> c_int;
|
||||
|
||||
pub fn smolmail_rns_close();
|
||||
|
||||
pub fn smolmail_rns_stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,6 +152,14 @@ pub fn close() {
|
|||
unsafe { inner::smolmail_rns_close() };
|
||||
}
|
||||
|
||||
/// Stops the Reticulum stack: joins the loop thread, tears the link down,
|
||||
/// stops the UDP interface and releases the instance. Must run before the
|
||||
/// embedding process tears down statics; a no-op when never started, and
|
||||
/// the stack can be started again afterwards.
|
||||
pub fn stop() {
|
||||
unsafe { inner::smolmail_rns_stop() };
|
||||
}
|
||||
|
||||
/// The destination hash length, for callers checking address shapes.
|
||||
pub const DEST_LEN: usize = 16;
|
||||
const _: () = assert!(DEST_LEN == 16 && KEY_LEN == 32);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
//! the C shim, dispatched through the same operations as TCP.
|
||||
//!
|
||||
//! The carrier starts lazily, on the first `smol+rns://` dial, so local-only
|
||||
//! commands stay usable offline and start instantly. A client creates no
|
||||
//! commands stay usable offline and start instantly, and stops via `stop()`,
|
||||
//! which every embedding process must call before it tears down: the
|
||||
//! Reticulum loop thread otherwise races the destruction of the statics it
|
||||
//! is calling into. A client creates no
|
||||
//! Reticulum identity (upstream spec sec 13.8): the shim never calls
|
||||
//! `Link::identify`, and the flags below configure only the storage path and
|
||||
//! the UDP interface.
|
||||
|
|
@ -11,6 +14,7 @@ pub mod ffi;
|
|||
pub mod transport;
|
||||
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
use crate::error::Error;
|
||||
|
|
@ -44,7 +48,7 @@ impl Default for RnsConfig {
|
|||
}
|
||||
|
||||
static CONFIG: OnceLock<RnsConfig> = OnceLock::new();
|
||||
static STARTED: OnceLock<()> = OnceLock::new();
|
||||
static STARTED: AtomicBool = AtomicBool::new(false);
|
||||
static START_MUTEX: Mutex<()> = Mutex::new(());
|
||||
|
||||
/// Records the carrier configuration; the first dial wins, as in a CLI the
|
||||
|
|
@ -53,19 +57,33 @@ pub fn configure(config: RnsConfig) {
|
|||
let _ = CONFIG.set(config);
|
||||
}
|
||||
|
||||
/// Starts the Reticulum stack at most once, on the first RNS dial.
|
||||
/// Starts the Reticulum stack at most once between calls to `stop`, on the
|
||||
/// first RNS dial.
|
||||
pub fn ensure_started() -> Result<(), Error> {
|
||||
if STARTED.get().is_some() {
|
||||
if STARTED.load(Ordering::Acquire) {
|
||||
return Ok(());
|
||||
}
|
||||
let _guard = START_MUTEX.lock().unwrap();
|
||||
if STARTED.get().is_some() {
|
||||
if STARTED.load(Ordering::Acquire) {
|
||||
return Ok(());
|
||||
}
|
||||
let config = CONFIG.get().cloned().unwrap_or_default();
|
||||
std::fs::create_dir_all(Path::new(&config.storage_dir))
|
||||
.map_err(|e| Error::Other(format!("cannot create {}: {e}", config.storage_dir)))?;
|
||||
ffi::start(&config)?;
|
||||
let _ = STARTED.set(());
|
||||
STARTED.store(true, Ordering::Release);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stops the Reticulum stack and joins its loop thread. The shim's loop
|
||||
/// thread otherwise outlives the caller and races the teardown of its statics
|
||||
/// at process exit — a nondeterministic hang the RNS carrier hit on a
|
||||
/// first-run provisioning pass. Embedders call this when they are done with
|
||||
/// the carrier; the CLI calls it before exiting. A no-op when never started,
|
||||
/// and the stack starts again on the next dial.
|
||||
pub fn stop() {
|
||||
if !STARTED.swap(false, Ordering::AcqRel) {
|
||||
return;
|
||||
}
|
||||
ffi::stop();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue