iceoryx2_bb_posix/
mutex.rs

1// Copyright (c) 2023 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! Provides an inter-process capable POSIX [`Mutex`] which can be created by the [`MutexBuilder`].
14//!
15//! # Example
16//!
17//! ```ignore
18//! use iceoryx2_bb_posix::mutex::*;
19//! use core::time::Duration;
20//! use iceoryx2_bb_posix::clock::ClockType;
21//!
22//! let handle = MutexHandle::<i32>::new();
23//! let mutex = MutexBuilder::new()
24//!               // is used in [`Mutex::timed_lock()`]
25//!               .clock_type(ClockType::Monotonic)
26//!               .is_interprocess_capable(false)
27//!               .mutex_type(MutexType::WithDeadlockDetection)
28//!               .thread_termination_behavior(MutexThreadTerminationBehavior::ReleaseWhenLocked)
29//!               .create(1234, &handle)
30//!               .expect("failed to create mutex");
31//!
32//! {
33//!     let guard = mutex.lock().expect("failed to lock mutex");
34//!     println!("current mutex value is: {}", *guard);
35//! }
36//!
37//! match mutex.try_lock().expect("failed to lock") {
38//!     Some(mut guard) => *guard = 123, // set mutex value to 123
39//!     None => println!("unable to acquire lock"),
40//! };
41//!
42//! match mutex.timed_lock(Duration::from_secs(1)).expect("failed to lock") {
43//!     Some(guard) => println!("New mutex value is: {}", *guard),
44//!     None => println!("Timeout occurred while trying to get lock.")
45//! };
46//! ```
47pub use crate::ipc_capable::{Handle, IpcCapable};
48
49use crate::ipc_capable::internal::{Capability, HandleStorage, IpcConstructible};
50use core::cell::UnsafeCell;
51use core::fmt::Debug;
52use core::ops::{Deref, DerefMut};
53use core::time::Duration;
54use iceoryx2_bb_elementary::scope_guard::*;
55use iceoryx2_bb_log::{fail, fatal_panic, warn};
56use iceoryx2_pal_posix::*;
57
58use crate::adaptive_wait::*;
59use crate::clock::{AsTimespec, ClockType, NanosleepError, Time, TimeError};
60use crate::handle_errno;
61use iceoryx2_pal_posix::posix::errno::Errno;
62use iceoryx2_pal_posix::posix::Struct;
63
64#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
65pub enum MutexCreationError {
66    InsufficientMemory,
67    InsufficientResources,
68    InsufficientPermissions,
69    NoInterProcessSupport,
70    UnableToSetType,
71    UnableToSetProtocol,
72    UnableToSetThreadTerminationBehavior,
73    UnknownError(i32),
74}
75
76#[derive(Debug, PartialEq, Eq)]
77pub enum MutexLockError<'mutex, 'handle, T: Sized + Debug> {
78    ExceededMaximumNumberOfRecursiveLocks,
79    DeadlockDetected,
80    LockAcquiredButOwnerDied(MutexGuard<'mutex, 'handle, T>),
81    UnrecoverableState,
82    UnknownError(i32),
83}
84
85impl<T: Sized + Debug> PartialEq for MutexGuard<'_, '_, T> {
86    fn eq(&self, other: &Self) -> bool {
87        core::ptr::eq(self.mutex, other.mutex)
88    }
89}
90
91impl<T: Sized + Debug> Eq for MutexGuard<'_, '_, T> {}
92
93#[derive(Debug, PartialEq, Eq)]
94pub enum MutexTimedLockError<'mutex, 'handle, T: Sized + Debug> {
95    TimeoutExceedsMaximumSupportedDuration,
96    MutexLockError(MutexLockError<'mutex, 'handle, T>),
97    NanosleepError(NanosleepError),
98    AdaptiveWaitError(AdaptiveWaitError),
99    FailureInInternalClockWhileWait(TimeError),
100}
101
102impl<T: Debug> From<TimeError> for MutexTimedLockError<'_, '_, T> {
103    fn from(v: TimeError) -> Self {
104        MutexTimedLockError::FailureInInternalClockWhileWait(v)
105    }
106}
107
108impl<T: Debug> From<NanosleepError> for MutexTimedLockError<'_, '_, T> {
109    fn from(v: NanosleepError) -> Self {
110        MutexTimedLockError::NanosleepError(v)
111    }
112}
113
114impl<T: Debug> From<AdaptiveWaitError> for MutexTimedLockError<'_, '_, T> {
115    fn from(v: AdaptiveWaitError) -> Self {
116        MutexTimedLockError::AdaptiveWaitError(v)
117    }
118}
119
120#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
121pub enum MutexUnlockError {
122    OwnedByDifferentEntity,
123    UnknownError(i32),
124}
125
126/// The MutexError enum is a generalization when one doesn't require the fine-grained error
127/// handling enums. One can forward MutexError as more generic return value when a method
128/// returns a Mutex***Error.
129/// On a higher level it is again convertable to [`crate::Error`].
130#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
131pub enum MutexError {
132    CreationFailed,
133    LockFailed,
134    UnlockFailed,
135}
136
137impl<'mutex, 'handle, T: Debug> From<MutexLockError<'mutex, 'handle, T>> for MutexError {
138    fn from(_: MutexLockError<'mutex, 'handle, T>) -> Self {
139        MutexError::LockFailed
140    }
141}
142
143impl<'mutex, 'handle, T: Debug> From<MutexTimedLockError<'mutex, 'handle, T>> for MutexError {
144    fn from(_: MutexTimedLockError<'mutex, 'handle, T>) -> Self {
145        MutexError::LockFailed
146    }
147}
148
149impl From<MutexUnlockError> for MutexError {
150    fn from(_: MutexUnlockError) -> Self {
151        MutexError::UnlockFailed
152    }
153}
154
155impl From<MutexCreationError> for MutexError {
156    fn from(_: MutexCreationError) -> Self {
157        MutexError::CreationFailed
158    }
159}
160
161/// A guard which allows the modification of a value guarded by a [`Mutex`]. It is returned in
162/// [`Mutex::lock()`], [`Mutex::try_lock()`] and [`Mutex::timed_lock()`].
163///
164/// # Example
165///
166/// ```
167/// use iceoryx2_bb_posix::mutex::*;
168///
169/// let handle = MutexHandle::<i32>::new();
170/// let mutex = MutexBuilder::new().create(123, &handle)
171///                                .expect("failed to create mutex");
172///
173/// {
174///     let mut guard = mutex.lock().expect("failed to lock");
175///     println!("Old value is {}", *guard);
176///     *guard = 456;
177/// }
178/// ```
179#[derive(Debug)]
180pub struct MutexGuard<'mutex, 'handle, T: Debug> {
181    mutex: &'mutex Mutex<'handle, T>,
182}
183
184unsafe impl<T: Send + Debug> Send for MutexGuard<'_, '_, T> {}
185unsafe impl<T: Send + Sync + Debug> Sync for MutexGuard<'_, '_, T> {}
186
187impl<T: Debug> Deref for MutexGuard<'_, '_, T> {
188    type Target = T;
189
190    fn deref(&self) -> &Self::Target {
191        unsafe { (*self.mutex.handle.value.get()).as_ref().unwrap() }
192    }
193}
194
195impl<T: Debug> DerefMut for MutexGuard<'_, '_, T> {
196    fn deref_mut(&mut self) -> &mut Self::Target {
197        unsafe { (*self.mutex.handle.value.get()).as_mut().unwrap() }
198    }
199}
200
201impl<T: Debug> Drop for MutexGuard<'_, '_, T> {
202    fn drop(&mut self) {
203        if self.mutex.release().is_err() {
204            fatal_panic!(from self.mutex, "This should never happen! The MutexGuard is unable to release the mutex.");
205        }
206    }
207}
208
209/// The type of a mutex defines its behavior.
210#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
211#[repr(i32)]
212pub enum MutexType {
213    /// default behavior
214    Normal = posix::PTHREAD_MUTEX_NORMAL,
215    /// the mutex can be locked multiple times by the same thread
216    Recursive = posix::PTHREAD_MUTEX_RECURSIVE,
217    /// if the call [`Mutex::lock()`] would cause a deadlock it returns an error instead of causing
218    /// an actual deadlock.
219    WithDeadlockDetection = posix::PTHREAD_MUTEX_ERRORCHECK,
220}
221
222/// Defines the behavior when a mutex owning thread is terminated
223#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
224#[repr(i32)]
225pub enum MutexThreadTerminationBehavior {
226    /// The mutex stays locked, is unlockable and no longer usable. This can also lead to a mutex
227    /// leak in the drop.
228    StallWhenLocked = posix::PTHREAD_MUTEX_STALLED,
229
230    /// It implies the same behavior as [`MutexType::WithDeadlockDetection`]. Additionally, when a
231    /// mutex owning
232    /// thread/process dies the mutex is put into an inconsistent state which can be recovered with
233    /// [`Mutex::make_consistent()`]. The inconsistent state is detected by the next instance which
234    /// calls [`Mutex::try_lock()`] or [`Mutex::timed_lock()`].
235    ///
236    /// **Important:** If the owner dies after another thread has already locked the [`Mutex`] it
237    /// may become impossible to recover the [`Mutex`]. Therefore, this feature should be used
238    /// only in combination with either [`Mutex::try_lock`] or [`Mutex::timed_lock()`] and
239    /// never with [`Mutex::lock()`].
240    ///
241    /// This is also known as robust mutex.
242    ReleaseWhenLocked = posix::PTHREAD_MUTEX_ROBUST,
243}
244
245/// Creates a [`Mutex`].
246#[derive(Debug)]
247pub struct MutexBuilder {
248    pub(crate) is_interprocess_capable: bool,
249    pub(crate) mutex_type: MutexType,
250    pub(crate) thread_termination_behavior: MutexThreadTerminationBehavior,
251    pub(crate) clock_type: ClockType,
252}
253
254impl Default for MutexBuilder {
255    fn default() -> Self {
256        Self {
257            is_interprocess_capable: true,
258            mutex_type: MutexType::Normal,
259            thread_termination_behavior: MutexThreadTerminationBehavior::StallWhenLocked,
260            clock_type: ClockType::default(),
261        }
262    }
263}
264
265impl MutexBuilder {
266    pub fn new() -> Self {
267        Self::default()
268    }
269
270    /// Defines the [`ClockType`] which should be used in [`Mutex::timed_lock()`].
271    pub fn clock_type(mut self, clock_type: ClockType) -> Self {
272        self.clock_type = clock_type;
273        self
274    }
275
276    /// Can the same mutex be used from multiple processes.
277    pub fn is_interprocess_capable(mut self, value: bool) -> Self {
278        self.is_interprocess_capable = value;
279        self
280    }
281
282    /// [`MutexType`] defines the behavior of the mutex.
283    pub fn mutex_type(mut self, value: MutexType) -> Self {
284        self.mutex_type = value;
285        self
286    }
287
288    /// Defines the [`MutexThreadTerminationBehavior`].
289    pub fn thread_termination_behavior(mut self, value: MutexThreadTerminationBehavior) -> Self {
290        self.thread_termination_behavior = value;
291        self
292    }
293
294    fn initialize_mutex<T: Debug>(
295        &self,
296        mutex: *mut posix::pthread_mutex_t,
297    ) -> Result<Capability, MutexCreationError> {
298        let msg = "Unable to create mutex";
299
300        let mut mutex_attributes = ScopeGuardBuilder::new(posix::pthread_mutexattr_t::new())
301            .on_init(
302                |attr| match unsafe { posix::pthread_mutexattr_init(attr) } {
303                    0 => Ok(()),
304                    _ => {
305                        fail!(from self, with MutexCreationError::InsufficientMemory,
306                        "{} since the mutex attribute initialization failed.", msg);
307                    }
308                },
309            )
310            .on_drop(
311                |attr| match unsafe { posix::pthread_mutexattr_destroy(attr) } {
312                    0 => (),
313                    _ => {
314                        fatal_panic!(
315                            "Mutex<{}>, failed to destroy mutex attributes - possible leak?",
316                            core::any::type_name::<T>()
317                        );
318                    }
319                },
320            )
321            .create()?;
322
323        if self.is_interprocess_capable
324            && unsafe {
325                posix::pthread_mutexattr_setpshared(
326                    mutex_attributes.get_mut(),
327                    posix::PTHREAD_PROCESS_SHARED,
328                )
329            } != 0
330        {
331            fail!(from self, with MutexCreationError::NoInterProcessSupport,
332                "{} due to a failure while setting the inter process flag in mutex attributes.", msg);
333        }
334
335        if unsafe {
336            posix::pthread_mutexattr_settype(mutex_attributes.get_mut(), self.mutex_type as i32)
337        } != 0
338        {
339            fail!(from self, with MutexCreationError::UnableToSetType,
340                "{} due to a failure while setting the mutex type in mutex attributes.", msg);
341        }
342
343        if unsafe {
344            posix::pthread_mutexattr_setprotocol(
345                mutex_attributes.get_mut(),
346                posix::PTHREAD_PRIO_NONE,
347            )
348        } != 0
349        {
350            fail!(from self, with MutexCreationError::UnableToSetProtocol,
351                "{} due to a failure while setting the mutex protocol in mutex attributes.", msg);
352        }
353
354        if unsafe {
355            posix::pthread_mutexattr_setrobust(
356                mutex_attributes.get_mut(),
357                self.thread_termination_behavior as i32,
358            )
359        } != 0
360        {
361            fail!(from self, with MutexCreationError::UnableToSetThreadTerminationBehavior,
362                "{} due to a failure while setting the mutex thread termination behavior in mutex attributes.", msg);
363        }
364
365        match unsafe { posix::pthread_mutex_init(mutex, mutex_attributes.get()) }.into() {
366            Errno::ESUCCES => (),
367            Errno::ENOMEM => {
368                fail!(from self, with MutexCreationError::InsufficientMemory, "{} due to insufficient memory.", msg);
369            }
370            Errno::EAGAIN => {
371                fail!(from self, with MutexCreationError::InsufficientResources,
372                "{} due to insufficient resources.",
373                msg);
374            }
375            Errno::EPERM => {
376                fail!(from self, with MutexCreationError::InsufficientPermissions,
377                    "{} due to insufficient permissions.", msg
378                );
379            }
380            v => {
381                fail!(from self, with MutexCreationError::UnknownError(v as i32),
382                "{} since an unknown error occurred ({})", msg, v);
383            }
384        };
385
386        match self.is_interprocess_capable {
387            true => Ok(Capability::InterProcess),
388            false => Ok(Capability::ProcessLocal),
389        }
390    }
391
392    /// Creates a new mutex with a guarded value.
393    pub fn create<T: Debug>(
394        self,
395        t: T,
396        handle: &MutexHandle<T>,
397    ) -> Result<Mutex<T>, MutexCreationError> {
398        unsafe {
399            handle
400                .handle
401                .initialize(|mtx| self.initialize_mutex::<T>(mtx))?
402        };
403
404        unsafe { *handle.clock_type.get() = self.clock_type };
405        unsafe { *handle.value.get() = Some(t) };
406
407        Ok(Mutex::new(handle))
408    }
409}
410
411#[derive(Debug)]
412pub struct MutexHandle<T: Sized + Debug> {
413    pub(crate) handle: HandleStorage<posix::pthread_mutex_t>,
414    clock_type: UnsafeCell<ClockType>,
415    value: UnsafeCell<Option<T>>,
416}
417
418unsafe impl<T: Sized + Debug> Send for MutexHandle<T> {}
419unsafe impl<T: Sized + Debug> Sync for MutexHandle<T> {}
420
421impl<T: Sized + Debug> Drop for MutexHandle<T> {
422    fn drop(&mut self) {
423        if self.handle.is_initialized() {
424            unsafe {
425                self.handle.cleanup(|mtx| {
426                if posix::pthread_mutex_destroy(mtx) != 0 {
427                    warn!(from self,
428                        "Unable to destroy mutex. Was it already destroyed by another instance in another process?");
429                }
430            })
431            };
432        }
433    }
434}
435
436impl<T: Sized + Debug> Handle for MutexHandle<T> {
437    fn new() -> Self {
438        Self {
439            handle: HandleStorage::new(posix::pthread_mutex_t::new()),
440            clock_type: UnsafeCell::new(ClockType::default()),
441            value: UnsafeCell::new(None),
442        }
443    }
444
445    fn is_initialized(&self) -> bool {
446        self.handle.is_initialized()
447    }
448
449    fn is_inter_process_capable(&self) -> bool {
450        self.handle.is_inter_process_capable()
451    }
452}
453
454impl<T: Sized + Debug> MutexHandle<T> {
455    fn clock_type(&self) -> ClockType {
456        unsafe { *self.clock_type.get() }
457    }
458}
459
460/// Represents a POSIX mutex which can be created by the [`MutexBuilder`].
461///
462/// # Example
463///
464/// For a detailed builder example, see [`MutexBuilder`].
465///
466/// ```
467/// use iceoryx2_bb_posix::mutex::*;
468/// use core::time::Duration;
469///
470/// let handle = MutexHandle::<i32>::new();
471/// let mutex = MutexBuilder::new().create(5, &handle)
472///     .expect("Failed to create mutex");
473///
474/// {
475///     let guard = mutex.lock().expect("failed to lock mutex");
476///     println!("current mutex value is: {}", *guard);
477/// }
478///
479/// match mutex.try_lock().expect("failed to lock") {
480///     Some(mut guard) => *guard = 123, // set mutex value to 123
481///     None => println!("unable to acquire lock"),
482/// };
483///
484/// match mutex.timed_lock(Duration::from_secs(1)).expect("failed to lock") {
485///     Some(guard) => println!("New mutex value is: {}", *guard),
486///     None => println!("Timeout occurred while trying to get lock.")
487/// };
488/// ```
489#[derive(Debug)]
490pub struct Mutex<'a, T: Sized + Debug> {
491    pub(crate) handle: &'a MutexHandle<T>,
492}
493
494unsafe impl<T: Sized + Send + Debug> Send for Mutex<'_, T> {}
495unsafe impl<T: Sized + Send + Debug> Sync for Mutex<'_, T> {}
496
497impl<'a, T: Debug> IpcConstructible<'a, MutexHandle<T>> for Mutex<'a, T> {
498    fn new(handle: &'a MutexHandle<T>) -> Self {
499        Self { handle }
500    }
501}
502
503impl<'a, T: Debug> IpcCapable<'a, MutexHandle<T>> for Mutex<'a, T> {
504    fn is_interprocess_capable(&self) -> bool {
505        self.handle.is_inter_process_capable()
506    }
507}
508
509impl<T: Debug> Mutex<'_, T> {
510    /// Blocks until the ownership of the lock could be acquired. If it was successful it returns a
511    /// [`MutexGuard`] to allow access to the underlying value.
512    /// If the previously owning thread has died and
513    /// [`MutexThreadTerminationBehavior::ReleaseWhenLocked`] was set it returns the error
514    /// [`MutexLockError::LockAcquiredButOwnerDied`] which contains also the [`MutexGuard`]. The
515    /// new owner now has the responsibility to either repair the underlying value of the mutex and
516    /// call [`Mutex::make_consistent()`] when it is repaired or to undertake other measures when
517    /// it is unrepairable.
518    pub fn lock(&self) -> Result<MutexGuard<'_, '_, T>, MutexLockError<'_, '_, T>> {
519        let msg = "Failed to lock";
520        handle_errno!(MutexLockError, from self,
521            errno_source unsafe { posix::pthread_mutex_lock(self.handle.handle.get()) }.into(),
522            success Errno::ESUCCES => MutexGuard { mutex: self },
523            Errno::EAGAIN => (ExceededMaximumNumberOfRecursiveLocks, "{} since the maximum number of recursive locks exceeded.", msg),
524            Errno::EDEADLK => (DeadlockDetected, "{} since the operation would lead to a deadlock.", msg),
525            Errno::EOWNERDEAD => (LockAcquiredButOwnerDied(MutexGuard { mutex: self }), "{} since the thread/process holding the mutex died.", msg),
526            Errno::ENOTRECOVERABLE => (UnrecoverableState, "{} since the thread/process holding the mutex died and the next owner did not repair the state with Mutex::make_consistent.", msg),
527            v => (UnknownError(v as i32), "{} since an unknown error occurred while acquiring the lock ({})", msg, v)
528        );
529    }
530
531    /// Tries to acquire the ownership of the lock. If it was successful it returns a
532    /// [`MutexGuard`] packed inside an [`Option`], if the lock is already owned by someone else it
533    /// returns [`None`].
534    /// If the previously owning thread has died and
535    /// [`MutexThreadTerminationBehavior::ReleaseWhenLocked`] was set it returns the error
536    /// [`MutexLockError::LockAcquiredButOwnerDied`] which contains also the [`MutexGuard`]. The
537    /// new owner now has the responsibility to either repair the underlying value of the mutex and
538    /// call [`Mutex::make_consistent()`] when it is repaired or to undertake other measures when
539    /// it is unrepairable.
540    pub fn try_lock(&self) -> Result<Option<MutexGuard<'_, '_, T>>, MutexLockError<'_, '_, T>> {
541        let msg = "Try lock failed";
542        handle_errno!(MutexLockError, from self,
543            errno_source unsafe { posix::pthread_mutex_trylock(self.handle.handle.get()) }.into(),
544            success Errno::ESUCCES => Some(MutexGuard { mutex: self });
545            success Errno::EDEADLK => None;
546            success Errno::EBUSY => None,
547            Errno::EAGAIN => (ExceededMaximumNumberOfRecursiveLocks, "{} since the maximum number of recursive locks exceeded.", msg),
548            Errno::EOWNERDEAD => (LockAcquiredButOwnerDied(MutexGuard { mutex: self }), "{} since the thread/process holding the mutex dies.", msg),
549            Errno::ENOTRECOVERABLE => (UnrecoverableState, "{} since the thread/process holding the mutex died and the next owner did not repair the state with Mutex::make_consistent.", msg),
550            v => (UnknownError(v as i32), "{} since unknown error occurred while acquiring the lock ({})", msg, v)
551        );
552    }
553
554    /// Tries to acquire the ownership of the lock until the provided timeout has elapsed. If it was
555    /// successful it returns a [`MutexGuard`] packed inside an [`Option`], if the could not be
556    /// acquired lock when the timeout passed it returns [`None`].
557    /// If the previously owning thread has died and
558    /// [`MutexThreadTerminationBehavior::ReleaseWhenLocked`] was set it returns the error
559    /// [`MutexTimedLockError::MutexLockError`] which contains also the [`MutexGuard`]. The
560    /// new owner now has the responsibility to either repair the underlying value of the mutex and
561    /// call [`Mutex::make_consistent()`] when it is repaired or to undertake other measures when
562    /// it is unrepairable.
563    pub fn timed_lock(
564        &self,
565        duration: Duration,
566    ) -> Result<Option<MutexGuard<'_, '_, T>>, MutexTimedLockError<'_, '_, T>> {
567        let msg = "Timed lock failed";
568
569        match self.handle.clock_type() {
570            ClockType::Realtime => {
571                let now = fail!(from self, when Time::now_with_clock(ClockType::Realtime),
572                    "{} due to a failure while acquiring current system time.", msg);
573                let timeout = now.as_duration() + duration;
574                handle_errno!(MutexTimedLockError, from self,
575                    errno_source unsafe { posix::pthread_mutex_timedlock(self.handle.handle.get(), &timeout.as_timespec()) }.into(),
576                    success Errno::ESUCCES => Some(MutexGuard { mutex: self });
577                    success Errno::ETIMEDOUT => None;
578                    success Errno::EDEADLK => None,
579                    Errno::EAGAIN => (MutexLockError(MutexLockError::ExceededMaximumNumberOfRecursiveLocks), "{} since the maximum number of recursive locks exceeded.", msg),
580                    Errno::EINVAL => (TimeoutExceedsMaximumSupportedDuration, "{} since the timeout of {:?} exceeds the maximum supported duration.", msg, duration),
581                    Errno::ENOTRECOVERABLE => (MutexLockError(MutexLockError::UnrecoverableState), "{} since the thread/process holding the mutex died and the next owner did not repair the state with Mutex::make_consistent.", msg),
582                    v => (MutexLockError(MutexLockError::UnknownError(v as i32)), "{} since unknown error occurred while acquiring the lock ({})", msg, v)
583                )
584            }
585            ClockType::Monotonic => {
586                let time = fail!(from self, when Time::now_with_clock(ClockType::Monotonic),
587                    "{} due to a failure while acquiring current system time.", msg);
588                let mut adaptive_wait = fail!(from self, when AdaptiveWaitBuilder::new()
589                    .clock_type(self.handle.clock_type())
590                    .create(), "{} since the adaptive wait could not be created.", msg);
591
592                loop {
593                    match self.try_lock() {
594                        Ok(Some(v)) => return Ok(Some(v)),
595                        Ok(None) => match fail!(from self, when time.elapsed(),
596                    "{} due to a failure while acquiring elapsed system time.", msg)
597                            < duration
598                        {
599                            true => {
600                                fail!(from self, when  adaptive_wait.wait(), "{} since AdaptiveWait failed.", msg);
601                            }
602                            false => return Ok(None),
603                        },
604                        Err(v) => {
605                            fail!(from self, with MutexTimedLockError::MutexLockError(v),
606                        "{} since timed lock failed for duration {:?}.", msg, duration);
607                        }
608                    }
609                }
610            }
611        }
612    }
613
614    /// If the previously owning thread has died and
615    /// [`MutexThreadTerminationBehavior::ReleaseWhenLocked`] was set it returns the error
616    /// [`MutexLockError::LockAcquiredButOwnerDied`] which contains also the [`MutexGuard`]. The
617    /// new owner now has the responsibility to either repair the underlying value of the mutex and
618    /// call [`Mutex::make_consistent()`] when it is repaired or to undertake other measures when
619    /// it is unrepairable.
620    pub fn make_consistent(&self) {
621        if unsafe { posix::pthread_mutex_consistent(self.handle.handle.get()) } != 0 {
622            warn!(from self, "pthread_mutex_consistent has no effect since either the mutex was not a robust mutex or the mutex was not in an inconsistent state.");
623        }
624    }
625
626    pub(crate) fn release(&self) -> Result<(), MutexUnlockError> {
627        let msg = "Unable to release lock";
628        handle_errno!(MutexUnlockError, from self,
629            errno_source unsafe { posix::pthread_mutex_unlock(self.handle.handle.get()) }.into(),
630            success Errno::ESUCCES => (),
631            Errno::EPERM => (OwnedByDifferentEntity, "{} since the current thread/process does not own the lock", msg),
632            v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
633        );
634    }
635}