Make SpawnError wrappers contain a 'spawning' string

(By our convention, these errors should say what we were trying to
spawn when the error occurred.)
This commit is contained in:
Nick Mathewson 2022-02-04 15:39:12 -05:00
parent 9bd7419c20
commit 070e52653d
9 changed files with 160 additions and 90 deletions

View File

@ -337,39 +337,49 @@ impl<R: Runtime> TorClient<R> {
let conn_status = chanmgr.bootstrap_events();
let dir_status = dirmgr.bootstrap_events();
runtime.spawn(status::report_status(
status_sender,
conn_status,
dir_status,
))?;
runtime
.spawn(status::report_status(
status_sender,
conn_status,
dir_status,
))
.map_err(|e| Error::from_spawn("top-level status reporter", e))?;
circmgr.update_network_parameters(dirmgr.netdir().params());
// Launch a daemon task to inform the circmgr about new
// network parameters.
runtime.spawn(keep_circmgr_params_updated(
dirmgr.events(),
Arc::downgrade(&circmgr),
Arc::downgrade(&dirmgr),
))?;
runtime
.spawn(keep_circmgr_params_updated(
dirmgr.events(),
Arc::downgrade(&circmgr),
Arc::downgrade(&dirmgr),
))
.map_err(|e| Error::from_spawn("circmgr parameter updater", e))?;
runtime.spawn(update_persistent_state(
runtime.clone(),
Arc::downgrade(&circmgr),
statemgr.clone(),
))?;
runtime
.spawn(update_persistent_state(
runtime.clone(),
Arc::downgrade(&circmgr),
statemgr.clone(),
))
.map_err(|e| Error::from_spawn("persistent state updater", e))?;
runtime.spawn(continually_launch_timeout_testing_circuits(
runtime.clone(),
Arc::downgrade(&circmgr),
Arc::downgrade(&dirmgr),
))?;
runtime
.spawn(continually_launch_timeout_testing_circuits(
runtime.clone(),
Arc::downgrade(&circmgr),
Arc::downgrade(&dirmgr),
))
.map_err(|e| Error::from_spawn("timeout-probe circuit launcher", e))?;
runtime.spawn(continually_preemptively_build_circuits(
runtime.clone(),
Arc::downgrade(&circmgr),
Arc::downgrade(&dirmgr),
))?;
runtime
.spawn(continually_preemptively_build_circuits(
runtime.clone(),
Arc::downgrade(&circmgr),
Arc::downgrade(&dirmgr),
))
.map_err(|e| Error::from_spawn("preemptive circuit launcher", e))?;
let client_isolation = IsolationToken::new();

View File

@ -97,13 +97,29 @@ $vis enum Error {
Reconfigure(#[from] tor_config::ReconfigureError),
/// Unable to spawn task
#[error("unable to spawn task")]
Spawn(#[from] Arc<SpawnError>),
#[error("unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn.
spawning: &'static str,
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>
}
}
// End of the use of $vis to refer to visibility according to `error_detail`
} }
impl Error {
/// Construct a new `Error` from a `SpawnError`.
pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> Error {
Error::Spawn {
spawning,
cause: Arc::new(err),
}
}
}
impl Display for TorError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "tor: {}: {}", self.detail.kind(), &self.detail)
@ -116,12 +132,6 @@ impl tor_error::HasKind for TorError {
}
}
impl From<SpawnError> for Error {
fn from(e: SpawnError) -> Error {
Arc::new(e).into()
}
}
impl tor_error::HasKind for Error {
fn kind(&self) -> ErrorKind {
use Error as E;

View File

@ -139,9 +139,11 @@ impl<R: Runtime> ChanBuilder<R> {
}
// 3. Launch a task to run the channel reactor.
self.runtime.spawn(async {
let _ = reactor.run().await;
})?;
self.runtime
.spawn(async {
let _ = reactor.run().await;
})
.map_err(|e| Error::from_spawn("channel reactor", e))?;
Ok(chan)
}
}

View File

@ -43,20 +43,19 @@ pub enum Error {
},
/// Unable to spawn task
#[error("unable to spawn task")]
Spawn(#[from] Arc<SpawnError>),
#[error("unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn.
spawning: &'static str,
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>,
},
/// An internal error of some kind that should never occur.
#[error("Internal error: {0}")]
Internal(&'static str),
}
impl From<SpawnError> for Error {
fn from(e: SpawnError) -> Error {
Arc::new(e).into()
}
}
impl From<tor_rtcompat::TimeoutError> for Error {
fn from(_: tor_rtcompat::TimeoutError) -> Error {
Error::ChanTimeout
@ -79,3 +78,13 @@ impl tor_error::HasKind for Error {
}
}
}
impl Error {
/// Construct a new `Error` from a `SpawnError`.
pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> Error {
Error::Spawn {
spawning,
cause: Arc::new(err),
}
}
}

View File

@ -84,7 +84,8 @@ async fn create_common<RT: Runtime, CT: ChanTarget>(
rt.spawn(async {
let _ = reactor.run().await;
})?;
})
.map_err(|e| Error::from_spawn("circuit reactor task", e))?;
Ok(pending_circ)
}
@ -390,10 +391,12 @@ where
let inner_timeout_future = rt.timeout(abandon, fut);
let outer_timeout_future = rt.timeout(timeout, rcv);
runtime.spawn(async move {
let result = inner_timeout_future.await;
let _ignore_cancelled_error = snd.send(result);
})?;
runtime
.spawn(async move {
let result = inner_timeout_future.await;
let _ignore_cancelled_error = snd.send(result);
})
.map_err(|e| Error::from_spawn("circuit construction task", e))?;
let outcome = outer_timeout_future.await;
// 4 layers of error to collapse:

View File

@ -92,8 +92,14 @@ pub enum Error {
ExpiredConsensus,
/// Unable to spawn task
#[error("unable to spawn task")]
Spawn(#[from] Arc<SpawnError>),
#[error("unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn
spawning: &'static str,
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>,
},
}
impl From<futures::channel::oneshot::Canceled> for Error {
@ -102,12 +108,6 @@ impl From<futures::channel::oneshot::Canceled> for Error {
}
}
impl From<SpawnError> for Error {
fn from(e: SpawnError) -> Error {
Arc::new(e).into()
}
}
impl From<tor_rtcompat::TimeoutError> for Error {
fn from(_: tor_rtcompat::TimeoutError) -> Error {
Error::CircTimeout
@ -133,3 +133,13 @@ impl tor_error::HasKind for Error {
}
}
}
impl Error {
/// Construct a new `Error` from a `SpawnError`.
pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> Error {
Error::Spawn {
spawning,
cause: Arc::new(err),
}
}
}

View File

@ -77,8 +77,14 @@ pub enum Error {
IOError(#[source] Arc<std::io::Error>),
/// Unable to spawn task
#[error("unable to spawn task")]
Spawn(#[from] Arc<SpawnError>),
#[error("unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn
spawning: &'static str,
/// What happened when we tried to spawn it
#[source]
cause: Arc<SpawnError>,
},
}
impl From<std::str::Utf8Error> for Error {
@ -117,8 +123,12 @@ impl From<rusqlite::Error> for Error {
}
}
impl From<SpawnError> for Error {
fn from(e: SpawnError) -> Error {
Arc::new(e).into()
impl Error {
/// Construct a new `Error` from a `SpawnError`.
pub(crate) fn from_spawn(spawning: &'static str, err: SpawnError) -> Error {
Error::Spawn {
spawning,
cause: Arc::new(err),
}
}
}

View File

@ -216,24 +216,26 @@ impl<R: Runtime> DirMgr<R> {
// Whether we loaded or not, we now start downloading.
let dirmgr_weak = Arc::downgrade(&dirmgr);
runtime.spawn(async move {
// NOTE: This is a daemon task. It should eventually get
// treated as one.
runtime
.spawn(async move {
// NOTE: This is a daemon task. It should eventually get
// treated as one.
// Don't warn when these are Error::ManagerDropped: that
// means that the DirMgr has been shut down.
if let Err(e) = Self::reload_until_owner(&dirmgr_weak, &mut sender).await {
match e {
Error::ManagerDropped => {}
_ => warn!("Unrecovered error while waiting for bootstrap: {}", e),
// Don't warn when these are Error::ManagerDropped: that
// means that the DirMgr has been shut down.
if let Err(e) = Self::reload_until_owner(&dirmgr_weak, &mut sender).await {
match e {
Error::ManagerDropped => {}
_ => warn!("Unrecovered error while waiting for bootstrap: {}", e),
}
} else if let Err(e) = Self::download_forever(dirmgr_weak, sender).await {
match e {
Error::ManagerDropped => {}
_ => warn!("Unrecovered error while downloading: {}", e),
}
}
} else if let Err(e) = Self::download_forever(dirmgr_weak, sender).await {
match e {
Error::ManagerDropped => {}
_ => warn!("Unrecovered error while downloading: {}", e),
}
}
})?;
})
.map_err(|e| Error::from_spawn("directory updater task", e))?;
if let Some(receiver) = receiver {
match receiver.await {

View File

@ -284,12 +284,16 @@ impl<R: Runtime> GuardMgr<R> {
{
let weak_inner = Arc::downgrade(&inner);
let rt_clone = runtime.clone();
runtime.spawn(daemon::report_status_events(rt_clone, weak_inner, rcv))?;
runtime
.spawn(daemon::report_status_events(rt_clone, weak_inner, rcv))
.map_err(|e| GuardMgrError::from_spawn("guard status event reporter", e))?;
}
{
let rt_clone = runtime.clone();
let weak_inner = Arc::downgrade(&inner);
runtime.spawn(daemon::run_periodic(rt_clone, weak_inner))?;
runtime
.spawn(daemon::run_periodic(rt_clone, weak_inner))
.map_err(|e| GuardMgrError::from_spawn("periodic guard updater", e))?;
}
Ok(GuardMgr { runtime, inner })
}
@ -1026,14 +1030,14 @@ pub enum GuardMgrError {
State(#[from] tor_persist::Error),
/// An error that occurred while trying to spawn a daemon task.
#[error("Unable to spawn task")]
Spawn(#[from] Arc<SpawnError>),
}
impl From<SpawnError> for GuardMgrError {
fn from(e: SpawnError) -> GuardMgrError {
Arc::new(e).into()
}
#[error("Unable to spawn {spawning}")]
Spawn {
/// What we were trying to spawn.
spawning: &'static str,
/// What happened when we tried to spawn it.
#[source]
cause: Arc<SpawnError>,
},
}
impl HasKind for GuardMgrError {
@ -1042,7 +1046,17 @@ impl HasKind for GuardMgrError {
use GuardMgrError as G;
match self {
G::State(e) => e.kind(),
G::Spawn(e) => e.kind(),
G::Spawn{ cause, .. } => cause.kind(),
}
}
}
impl GuardMgrError {
/// Construct a new `GuardMgrError` from a `SpawnError`.
fn from_spawn(spawning: &'static str, err: SpawnError) -> GuardMgrError {
GuardMgrError::Spawn {
spawning,
cause: Arc::new(err),
}
}
}