1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#[cfg(not(feature = "parking-lot"))]
mod internals {
//! Manual implementation using atomics.
use std::sync::atomic::{AtomicIsize, Ordering};
/// A simplified RwLock implementation which only supports voluntary locking.
#[repr(C)]
pub struct RwLock {
state: AtomicIsize,
}
impl RwLock {
/// Construct a new lock that's in an unlocked state.
pub(crate) const fn new() -> Self {
Self {
state: AtomicIsize::new(0),
}
}
/// Construct a new lock that is already locked.
pub(crate) fn locked() -> Self {
Self {
state: AtomicIsize::new(-std::isize::MAX),
}
}
/// Try to lock exclusively.
pub(crate) fn try_lock_exclusive_immediate(&self) -> bool {
let last = self.state.fetch_sub(std::isize::MAX, Ordering::AcqRel);
if last != 0 {
// try again later
self.state.fetch_add(std::isize::MAX, Ordering::AcqRel);
return false;
}
if last == std::isize::MIN {
// Sentinel value in case we observe a value that has wrapped
// around. This is such a abnormal state that there's not much
// we _can_ do. Abort the process.
std::process::abort();
}
true
}
/// Unlock shared access.
///
/// # Safety
///
/// This method may only be called if an exclusive lock is held in the
/// current context.
pub(crate) unsafe fn unlock_exclusive_immediate(&self) {
let old = self.state.fetch_add(std::isize::MAX, Ordering::AcqRel);
debug_assert!(old >= -std::isize::MAX && old < 0);
}
/// Try to lock shared.
pub(crate) fn try_lock_shared_immediate(&self) -> bool {
let existing = self.state.fetch_add(1, Ordering::AcqRel);
if existing < 0 {
self.state.fetch_sub(1, Ordering::AcqRel);
return false;
}
if existing == std::isize::MAX {
// Sentinel value in case we observe a value that has wrapped
// around. This is such a abnormal state that there's not much
// we _can_ do. Abort the process.
std::process::abort();
}
true
}
/// Unlock shared access.
///
/// # Safety
///
/// This method may only be called if a shared lock is held in the
/// current context.
pub(crate) unsafe fn unlock_shared_immediate(&self) {
self.state.fetch_sub(1, Ordering::AcqRel);
}
}
}
#[cfg(feature = "parking-lot")]
mod internals {
//! Implementation using raw locks from parking_lot.
use lock_api::RawRwLock as _;
/// A simplified RwLock implementation which only supports voluntary locking.
pub struct RwLock {
state: parking_lot::RawRwLock,
}
impl RwLock {
/// Construct a new lock that's in an unlocked state.
pub(crate) const fn new() -> Self {
Self {
state: parking_lot::RawRwLock::INIT,
}
}
/// Construct a new lock that is already locked.
pub(crate) fn locked() -> Self {
let state = parking_lot::RawRwLock::INIT;
state.lock_exclusive();
Self { state }
}
/// Try to lock exclusively.
pub(crate) fn try_lock_exclusive_immediate(&self) -> bool {
self.state.try_lock_exclusive()
}
/// Unlock shared access.
///
/// # Safety
///
/// This method may only be called if an exclusive lock is held in the
/// current context.
pub(crate) unsafe fn unlock_exclusive_immediate(&self) {
self.state.unlock_exclusive()
}
/// Try to lock shared.
pub(crate) fn try_lock_shared_immediate(&self) -> bool {
self.state.try_lock_shared()
}
/// Unlock shared access.
///
/// # Safety
///
/// This method may only be called if a shared lock is held in the
/// current context.
pub(crate) unsafe fn unlock_shared_immediate(&self) {
self.state.unlock_shared()
}
}
}
pub use self::internals::RwLock;
impl RwLock {
pub fn try_lock_exclusive_guard(&self) -> Option<LockExclusiveGuard<'_>> {
if self.try_lock_exclusive_immediate() {
Some(LockExclusiveGuard { lock: self })
} else {
None
}
}
/// Try to acquire a shared lock with a guard.
pub fn try_lock_shared(&self) -> Option<LockSharedGuard<'_>> {
if self.try_lock_shared_immediate() {
Some(LockSharedGuard { lock: self })
} else {
None
}
}
}
/// A lock guard for an exclusive lock.
pub struct LockExclusiveGuard<'a> {
lock: &'a RwLock,
}
impl Drop for LockExclusiveGuard<'_> {
fn drop(&mut self) {
// SAFETY: lock is held by the guard correctly.
unsafe { self.lock.unlock_exclusive_immediate() }
}
}
/// A lock guard for a shared lock.
pub struct LockSharedGuard<'a> {
lock: &'a RwLock,
}
impl Drop for LockSharedGuard<'_> {
fn drop(&mut self) {
// SAFETY: lock is held by the guard correctly.
unsafe { self.lock.unlock_shared_immediate() }
}
}