1#![warn(missing_docs, unreachable_patterns, unused)]
8
9extern crate alloc;
10
11#[cfg(loom)]
12pub(crate) use loom::sync;
13#[cfg(not(loom))]
14pub(crate) use std::sync;
15
16use net_types::ip::{GenericOverIp, Ip};
17
18pub use sync::atomic;
20
21pub mod rc;
22
23#[derive(Debug, Default)]
25pub struct Mutex<T>(
26 #[cfg(all(target_os = "fuchsia", not(loom)))] fuchsia_sync::Mutex<T>,
27 #[cfg(not(all(target_os = "fuchsia", not(loom))))] sync::Mutex<T>,
28);
29
30#[cfg(all(target_os = "fuchsia", not(loom)))]
32pub type LockGuard<'a, T> = fuchsia_sync::MutexGuard<'a, T>;
33
34#[cfg(not(all(target_os = "fuchsia", not(loom))))]
36pub type LockGuard<'a, T> = sync::MutexGuard<'a, T>;
37
38impl<T> Mutex<T> {
39 #[inline]
41 pub fn new(t: T) -> Mutex<T> {
42 #[cfg(all(target_os = "fuchsia", not(loom)))]
43 let m = fuchsia_sync::Mutex::new(t);
44 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
45 let m = sync::Mutex::new(t);
46 Mutex(m)
47 }
48
49 #[inline]
56 pub fn lock(&self) -> LockGuard<'_, T> {
57 let Self(m) = self;
58 #[cfg(all(target_os = "fuchsia", not(loom)))]
59 return m.lock();
60 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
61 return m.lock().expect("unexpectedly poisoned");
62 }
63
64 #[inline]
66 pub fn into_inner(self) -> T {
67 let Self(mutex) = self;
68 #[cfg(all(target_os = "fuchsia", not(loom)))]
69 return mutex.into_inner();
70 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
71 return mutex.into_inner().expect("unexpectedly poisoned");
72 }
73
74 #[inline]
79 #[cfg(not(loom))]
82 pub fn get_mut(&mut self) -> &mut T {
83 let Self(mutex) = self;
84 #[cfg(target_os = "fuchsia")]
85 return mutex.get_mut();
86 #[cfg(not(target_os = "fuchsia"))]
87 return mutex.get_mut().expect("unexpectedly poisoned");
88 }
89}
90
91impl<T: 'static> lock_order::lock::ExclusiveLock<T> for Mutex<T> {
92 type Guard<'l> = LockGuard<'l, T>;
93
94 fn lock(&self) -> Self::Guard<'_> {
95 self.lock()
96 }
97}
98
99impl<T, I: Ip> GenericOverIp<I> for Mutex<T>
100where
101 T: GenericOverIp<I>,
102{
103 type Type = Mutex<T::Type>;
104}
105
106#[derive(Debug, Default)]
108pub struct RwLock<T>(
109 #[cfg(all(target_os = "fuchsia", not(loom)))] fuchsia_sync::RwLock<T>,
110 #[cfg(not(all(target_os = "fuchsia", not(loom))))] sync::RwLock<T>,
111);
112
113#[cfg(all(target_os = "fuchsia", not(loom)))]
115pub type RwLockReadGuard<'a, T> = fuchsia_sync::RwLockReadGuard<'a, T>;
116
117#[cfg(not(all(target_os = "fuchsia", not(loom))))]
119pub type RwLockReadGuard<'a, T> = sync::RwLockReadGuard<'a, T>;
120
121#[cfg(all(target_os = "fuchsia", not(loom)))]
123pub type RwLockWriteGuard<'a, T> = fuchsia_sync::RwLockWriteGuard<'a, T>;
124
125#[cfg(not(all(target_os = "fuchsia", not(loom))))]
127pub type RwLockWriteGuard<'a, T> = sync::RwLockWriteGuard<'a, T>;
128
129impl<T> RwLock<T> {
130 #[inline]
132 pub fn new(t: T) -> RwLock<T> {
133 #[cfg(all(target_os = "fuchsia", not(loom)))]
134 let rw = fuchsia_sync::RwLock::new(t);
135 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
136 let rw = sync::RwLock::new(t);
137 RwLock(rw)
138 }
139
140 #[inline]
148 pub fn read(&self) -> RwLockReadGuard<'_, T> {
149 let Self(rw) = self;
150 #[cfg(all(target_os = "fuchsia", not(loom)))]
151 return rw.read();
152 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
153 return rw.read().expect("unexpectedly poisoned");
154 }
155
156 #[inline]
164 pub fn write(&self) -> RwLockWriteGuard<'_, T> {
165 let Self(rw) = self;
166 #[cfg(all(target_os = "fuchsia", not(loom)))]
167 return rw.write();
168 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
169 return rw.write().expect("unexpectedly poisoned");
170 }
171
172 #[inline]
174 pub fn into_inner(self) -> T {
175 let Self(rwlock) = self;
176 #[cfg(all(target_os = "fuchsia", not(loom)))]
177 return rwlock.into_inner();
178 #[cfg(not(all(target_os = "fuchsia", not(loom))))]
179 return rwlock.into_inner().expect("unexpectedly poisoned");
180 }
181
182 #[inline]
187 #[cfg(not(loom))]
190 pub fn get_mut(&mut self) -> &mut T {
191 let Self(rwlock) = self;
192 #[cfg(target_os = "fuchsia")]
193 return rwlock.get_mut();
194 #[cfg(not(target_os = "fuchsia"))]
195 return rwlock.get_mut().expect("unexpectedly poisoned");
196 }
197}
198
199impl<T: 'static> lock_order::lock::ReadWriteLock<T> for RwLock<T> {
200 type ReadGuard<'l> = RwLockReadGuard<'l, T>;
201
202 type WriteGuard<'l> = RwLockWriteGuard<'l, T>;
203
204 fn read_lock(&self) -> Self::ReadGuard<'_> {
205 self.read()
206 }
207
208 fn write_lock(&self) -> Self::WriteGuard<'_> {
209 self.write()
210 }
211}
212
213impl<T, I: Ip> GenericOverIp<I> for RwLock<T>
214where
215 T: GenericOverIp<I>,
216{
217 type Type = RwLock<T::Type>;
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223
224 use std::thread;
225
226 #[test]
227 fn mutex_lock_and_write() {
228 let m = Mutex::<u32>::new(0);
229 {
230 let mut guard = m.lock();
231 assert_eq!(*guard, 0);
232 *guard = 5;
233 }
234
235 {
236 let guard = m.lock();
237 assert_eq!(*guard, 5);
238 }
239 }
240
241 #[test]
242 fn mutex_lock_from_different_threads() {
243 const NUM_THREADS: u32 = 4;
244
245 let m = Mutex::<u32>::new(u32::MAX);
246 let m = &m;
247
248 thread::scope(|s| {
249 for i in 0..NUM_THREADS {
250 let _: thread::ScopedJoinHandle<'_, _> = s.spawn(move || {
251 let prev = {
252 let mut guard = m.lock();
253 let prev = *guard;
254 *guard = i;
255 prev
256 };
257
258 assert!(prev == u32::MAX || prev < NUM_THREADS);
259 });
260 }
261 });
262
263 let guard = m.lock();
264 assert!(*guard < NUM_THREADS);
265 }
266
267 #[test]
268 fn rwlock_read_lock() {
269 let rw = RwLock::<u32>::new(0);
270
271 {
272 let guard = rw.read();
273 assert_eq!(*guard, 0);
274 }
275
276 {
277 let guard = rw.read();
278 assert_eq!(*guard, 0);
279 }
280 }
281
282 #[test]
283 fn rwlock_write_lock() {
284 let rw = RwLock::<u32>::new(0);
285 {
286 let mut guard = rw.write();
287 assert_eq!(*guard, 0);
288 *guard = 5;
289 }
290
291 {
292 let guard = rw.write();
293 assert_eq!(*guard, 5);
294 }
295 }
296
297 #[test]
298 fn rwlock_read_and_write_from_different_threads() {
299 const NUM_THREADS: u32 = 4;
300
301 let rw = RwLock::<u32>::new(u32::MAX);
302 let rw = &rw;
303
304 thread::scope(|s| {
305 for i in 0..NUM_THREADS {
306 let _: thread::ScopedJoinHandle<'_, _> = s.spawn(move || {
307 let prev = if i % 2 == 0 {
308 let mut guard = rw.write();
310 let prev = *guard;
311 *guard = i;
312 prev
313 } else {
314 let guard = rw.read();
315 *guard
316 };
317
318 assert!(prev == u32::MAX || (prev < NUM_THREADS && prev % 2 == 0));
319 });
320 }
321 });
322
323 let val = *rw.read();
324 assert!(val < NUM_THREADS && val % 2 == 0);
325 }
326}