diff options
author | Robin Krahl <robin.krahl@ireas.org> | 2019-07-09 10:44:45 +0000 |
---|---|---|
committer | Robin Krahl <robin.krahl@ireas.org> | 2019-07-09 12:47:26 +0200 |
commit | 5e8f0fbaf6df0cb919e4b02401cc21d5280bf09c (patch) | |
tree | 2495451253d9634e2ef1b5f4972bea93d634c2d7 | |
parent | 88b32f5c2187e59fece93cd245aeadb4e5f9e04a (diff) | |
download | nitrokey-rs-5e8f0fbaf6df0cb919e4b02401cc21d5280bf09c.tar.gz nitrokey-rs-5e8f0fbaf6df0cb919e4b02401cc21d5280bf09c.tar.bz2 |
Add force_take function to ignore poisoned cache
The take and take_blocking functions return a PoisonError if the cache
is poisoned, i. e. if a thread panicked while holding the manager. This
is a sensible default behaviour, but for example during testing, one
might want to ignore the poisoned cache. This patch adds the force_take
function that unwraps the PoisonError and returns the cached Manager
even if the cache was poisoned.
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/lib.rs | 32 |
2 files changed, 33 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 06769bd..b779929 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,8 @@ SPDX-License-Identifier: MIT - Add the `Manager` struct that manages connections to Nitrokey devices. - Remove `connect`, `connect_model`, `Pro::connect` and `Storage::connect`. - Add the `into_manager` function to the `Device` trait. + - Add the `force_take` function that ignores a `PoisonError` when accessing + the manager instance. # v0.3.4 (2019-01-20) - Fix authentication methods that assumed that `char` is signed. @@ -377,7 +377,8 @@ pub fn take_blocking() -> Result<sync::MutexGuard<'static, Manager>, Error> { /// /// There may only be one [`Manager`][] instance at the same time. If there already is an /// instance, a [`ConcurrentAccessError`][] is returned. If you want a blocking version, use -/// [`take_blocking`][]. +/// [`take_blocking`][]. If you want to access the manager instance even if the cache is poisoned, +/// use [`force_take`][]. /// /// # Errors /// @@ -385,6 +386,7 @@ pub fn take_blocking() -> Result<sync::MutexGuard<'static, Manager>, Error> { /// - [`PoisonError`][] if the lock is poisoned /// /// [`take_blocking`]: fn.take_blocking.html +/// [`force_take`]: fn.force_take.html /// [`ConcurrentAccessError`]: struct.Error.html#variant.ConcurrentAccessError /// [`PoisonError`]: struct.Error.html#variant.PoisonError /// [`Manager`]: struct.Manager.html @@ -392,6 +394,34 @@ pub fn take() -> Result<sync::MutexGuard<'static, Manager>, Error> { MANAGER.try_lock().map_err(Into::into) } +/// Try to take an instance of the connection manager, ignoring a poisoned cache. +/// +/// There may only be one [`Manager`][] instance at the same time. If there already is an +/// instance, a [`ConcurrentAccessError`][] is returned. If you want a blocking version, use +/// [`take_blocking`][]. +/// +/// If a thread has previously panicked while accessing the manager instance, the cache is +/// poisoned. The default implementation, [`take`][], returns a [`PoisonError`][] on subsequent +/// calls. This implementation ignores the poisoned cache and returns the manager instance. +/// +/// # Errors +/// +/// - [`ConcurrentAccessError`][] if the token for the `Manager` instance cannot be locked +/// +/// [`take`]: fn.take.html +/// [`take_blocking`]: fn.take_blocking.html +/// [`ConcurrentAccessError`]: struct.Error.html#variant.ConcurrentAccessError +/// [`Manager`]: struct.Manager.html +pub fn force_take() -> Result<sync::MutexGuard<'static, Manager>, Error> { + match take() { + Ok(guard) => Ok(guard), + Err(err) => match err { + Error::PoisonError(err) => Ok(err.into_inner()), + err => Err(err), + }, + } +} + /// Enables or disables debug output. Calling this method with `true` is equivalent to setting the /// log level to `Debug`; calling it with `false` is equivalent to the log level `Error` (see /// [`set_log_level`][]). |