1// Copyright 2018 Amanieu d'Antras
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! This library provides type-safe and fully-featured `Mutex` and `RwLock`
9//! types which wrap a simple raw mutex or rwlock type. This has several
10//! benefits: not only does it eliminate a large portion of the work in
11//! implementing custom lock types, it also allows users to write code which is
12//! generic with regards to different lock implementations.
13//!
14//! Basic usage of this crate is very straightforward:
15//!
16//! 1. Create a raw lock type. This should only contain the lock state, not any
17//! data protected by the lock.
18//! 2. Implement the `RawMutex` trait for your custom lock type.
19//! 3. Export your mutex as a type alias for `lock_api::Mutex`, and
20//! your mutex guard as a type alias for `lock_api::MutexGuard`.
21//! See the [example](#example) below for details.
22//!
23//! This process is similar for RwLocks, except that two guards need to be
24//! exported instead of one. (Or 3 guards if your type supports upgradable read
25//! locks, see [extension traits](#extension-traits) below for details)
26//!
27//! # Example
28//!
29//! ```
30//! use lock_api::{RawMutex, Mutex, GuardSend};
31//! use std::sync::atomic::{AtomicBool, Ordering};
32//!
33//! // 1. Define our raw lock type
34//! pub struct RawSpinlock(AtomicBool);
35//!
36//! // 2. Implement RawMutex for this type
37//! unsafe impl RawMutex for RawSpinlock {
38//! const INIT: RawSpinlock = RawSpinlock(AtomicBool::new(false));
39//!
40//! // A spinlock guard can be sent to another thread and unlocked there
41//! type GuardMarker = GuardSend;
42//!
43//! fn lock(&self) {
44//! // Note: This isn't the best way of implementing a spinlock, but it
45//! // suffices for the sake of this example.
46//! while !self.try_lock() {}
47//! }
48//!
49//! fn try_lock(&self) -> bool {
50//! self.0
51//! .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
52//! .is_ok()
53//! }
54//!
55//! unsafe fn unlock(&self) {
56//! self.0.store(false, Ordering::Release);
57//! }
58//! }
59//!
60//! // 3. Export the wrappers. This are the types that your users will actually use.
61//! pub type Spinlock<T> = lock_api::Mutex<RawSpinlock, T>;
62//! pub type SpinlockGuard<'a, T> = lock_api::MutexGuard<'a, RawSpinlock, T>;
63//! ```
64//!
65//! # Extension traits
66//!
67//! In addition to basic locking & unlocking functionality, you have the option
68//! of exposing additional functionality in your lock types by implementing
69//! additional traits for it. Examples of extension features include:
70//!
71//! - Fair unlocking (`RawMutexFair`, `RawRwLockFair`)
72//! - Lock timeouts (`RawMutexTimed`, `RawRwLockTimed`)
73//! - Downgradable write locks (`RawRwLockDowngradable`)
74//! - Recursive read locks (`RawRwLockRecursive`)
75//! - Upgradable read locks (`RawRwLockUpgrade`)
76//!
77//! The `Mutex` and `RwLock` wrappers will automatically expose this additional
78//! functionality if the raw lock type implements these extension traits.
79//!
80//! # Cargo features
81//!
82//! This crate supports three cargo features:
83//!
84//! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate.
85//! - `arc_lock`: Enables locking from an `Arc`. This enables types such as `ArcMutexGuard`. Note that this
86//! requires the `alloc` crate to be present.
87
88#![no_std]
89#![cfg_attr(docsrs, feature(doc_auto_cfg))]
90#![warn(missing_docs)]
91#![warn(rust_2018_idioms)]
92
93#[macro_use]
94extern crate scopeguard;
95
96#[cfg(feature = "arc_lock")]
97extern crate alloc;
98
99/// Marker type which indicates that the Guard type for a lock is `Send`.
100pub struct GuardSend(());
101
102/// Marker type which indicates that the Guard type for a lock is not `Send`.
103pub struct GuardNoSend(*mut ());
104
105unsafe impl Sync for GuardNoSend {}
106
107mod mutex;
108pub use crate::mutex::*;
109
110#[cfg(feature = "atomic_usize")]
111mod remutex;
112#[cfg(feature = "atomic_usize")]
113pub use crate::remutex::*;
114
115mod rwlock;
116pub use crate::rwlock::*;
117