summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2019-07-09 10:44:45 +0000
committerRobin Krahl <robin.krahl@ireas.org>2019-07-09 12:47:26 +0200
commit5e8f0fbaf6df0cb919e4b02401cc21d5280bf09c (patch)
tree2495451253d9634e2ef1b5f4972bea93d634c2d7
parent88b32f5c2187e59fece93cd245aeadb4e5f9e04a (diff)
downloadnitrokey-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.md2
-rw-r--r--src/lib.rs32
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.
diff --git a/src/lib.rs b/src/lib.rs
index 4e45877..a4402c5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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`][]).