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 ] |
94 | extern crate scopeguard; |
95 | |
96 | #[cfg (feature = "arc_lock" )] |
97 | extern crate alloc; |
98 | |
99 | /// Marker type which indicates that the Guard type for a lock is `Send`. |
100 | pub struct GuardSend(()); |
101 | |
102 | /// Marker type which indicates that the Guard type for a lock is not `Send`. |
103 | pub struct GuardNoSend(*mut ()); |
104 | |
105 | unsafe impl Sync for GuardNoSend {} |
106 | |
107 | mod mutex; |
108 | pub use crate::mutex::*; |
109 | |
110 | #[cfg (feature = "atomic_usize" )] |
111 | mod remutex; |
112 | #[cfg (feature = "atomic_usize" )] |
113 | pub use crate::remutex::*; |
114 | |
115 | mod rwlock; |
116 | pub use crate::rwlock::*; |
117 | |