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 two cargo features:
83 //!
84 //! - `owning_ref`: Allows your lock types to be used with the `owning_ref` crate.
85 //! - `nightly`: Enables nightly-only features. At the moment the only such
86 //!   feature is `const fn` constructors for lock types.
87 
88 #![no_std]
89 #![warn(missing_docs)]
90 #![warn(rust_2018_idioms)]
91 #![cfg_attr(feature = "nightly", feature(const_fn))]
92 
93 #[macro_use]
94 extern crate scopeguard;
95 
96 /// Marker type which indicates that the Guard type for a lock is `Send`.
97 pub struct GuardSend(());
98 
99 /// Marker type which indicates that the Guard type for a lock is not `Send`.
100 pub struct GuardNoSend(*mut ());
101 
102 unsafe impl Sync for GuardNoSend {}
103 
104 mod mutex;
105 pub use crate::mutex::*;
106 
107 mod remutex;
108 pub use crate::remutex::*;
109 
110 mod rwlock;
111 pub use crate::rwlock::*;
112