flexible_locks/lib.rs
1// Copyright 2018 Mike Hommey
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! # Flexible Locks
10//!
11//! This crate aims at providing generic, flexible implementations of locking
12//! primitives. For now, it only provides `Mutex` types (i.e. no `RwLock`, etc.),
13//! without [poisoning], and without `try_lock`. Support for those can be
14//! added in the future if there is interest (patches welcome). Poisoning is not
15//! necessary with panic=abort.
16//!
17//! [poisoning]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#poisoning
18//!
19//! The provided types allow flexibility in layout and locking implementation.
20//! See the [`Mutex`], [`MutexWrap`] and [`RawOsMutex`] documentation for more
21//! details.
22//!
23//! # Features
24//!
25//! The `parking_lot` feature can be enabled, providing a [`RawMutex`]
26//! implementation for `parking_log::Mutex<()>`.
27#![no_std]
28#![deny(missing_docs)]
29
30#[cfg(any(feature = "std", test))]
31extern crate std;
32#[cfg(any(feature = "std", test))]
33use std::prelude::v1::*;
34
35#[cfg(windows)]
36extern crate winapi;
37
38#[cfg(unix)]
39extern crate libc;
40
41#[macro_use]
42extern crate flexible_locks_derive;
43
44#[cfg(feature = "allocator_api")]
45extern crate allocator_api;
46
47#[cfg(feature = "parking_lot")]
48extern crate parking_lot;
49
50// Public for the *_new macros.
51#[doc(hidden)]
52pub use core::cell::UnsafeCell;
53use core::marker::PhantomData;
54use core::ops::{Deref, DerefMut};
55use core::ptr;
56
57// For #[derive(MutexProtected)]
58mod flexible_locks {
59 pub use super::MutexProtected;
60}
61
62mod os;
63
64pub use os::*;
65
66/// A trait for raw mutual exclusion primitives.
67pub trait RawMutex: Send + Sync {
68 /// Initialize the raw mutex.
69 ///
70 /// Because initializing an instance may involve moving its location
71 /// when doing e.g. `Box::new(Foo::new())`, because some types
72 /// of raw mutex primitives need to be initialized at their final,
73 /// permanent location (e.g. [`CRITICAL_SECTION`]), or because some
74 /// may not be statically initialized to an entirely satisfying state
75 /// (e.g. [`pthread_mutex_t`], see [issue #33770]), this method is called
76 /// from [`Mutex::new`] to finish the raw mutex initialization.
77 ///
78 /// [`CRITICAL_SECTION`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682530(v=vs.85).aspx
79 /// [`pthread_mutex_t`]: http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_mutex_init.html
80 /// [issue #33770]: https://github.com/rust-lang/rust/issues/33770
81 unsafe fn init(&mut self) {}
82
83 /// Destroy the raw mutex.
84 ///
85 /// In some cases, raw mutex primitives need to be cleaned up after
86 /// use, so this method is called when a [`Mutex`] is dropped.
87 unsafe fn destroy(&self) {}
88
89 /// Acquire the raw mutex.
90 unsafe fn lock(&self);
91
92 /// Release the raw mutex.
93 unsafe fn unlock(&self);
94}
95
96/// Wrapping a `RawMutex` in a `Box` is just as good a valid `RawMutex`.
97///
98/// Ideally, any type that derefs to a `RawMutex` would be good too, but
99/// without specialization, this would prevent implementing `RawMutex` on
100/// your own mutex types.
101//
102// Ideally, this would be:
103// `impl<T: RawMutex, U: DerefMut<Target = T> + Send + Sync> RawMutex for U`
104#[cfg(any(feature = "std", test))]
105impl<T: RawMutex> RawMutex for Box<T> {
106 unsafe fn init(&mut self) {
107 self.as_mut().init()
108 }
109
110 unsafe fn lock(&self) {
111 self.as_ref().lock()
112 }
113
114 unsafe fn unlock(&self) {
115 self.as_ref().unlock()
116 }
117
118 unsafe fn destroy(&self) {
119 self.as_ref().destroy()
120 }
121}
122
123/// A trait describing types that can be wrapped in a [`Mutex`].
124///
125/// It is not recommended to implement this trait manually. Instead, use the
126/// `flexible-locks_derive` crate that provides a custom
127/// `#[derive(MutexProtected)]`.
128///
129/// When using that custom derive, the `#[mutex]` attribute is used to
130/// indicate the data field containing the raw mutex type.
131///
132/// # Examples
133///
134/// ```
135/// extern crate flexible_locks;
136/// #[macro_use]
137/// extern crate flexible_locks_derive;
138/// use flexible_locks::{Mutex, RawMutex};
139///
140/// // Pick your choice of raw mutex;
141/// #[cfg(windows)]
142/// use flexible_locks::CRITICAL_SECTION as RawOsMutex;
143/// #[cfg(unix)]
144/// use flexible_locks::pthread_mutex_t as RawOsMutex;
145///
146/// #[derive(MutexProtected)]
147/// struct Data {
148/// a: usize,
149/// #[mutex]
150/// mutex: RawOsMutex,
151/// b: usize,
152/// }
153/// # fn main() {}
154/// ```
155pub trait MutexProtected {
156 /// Raw mutex pritimive used to protect the data type.
157 type MutexType: RawMutex;
158
159 /// Data type that [`Mutex::lock`] will give access to.
160 ///
161 /// `[derive(MutexProtected)]` makes this `Self` when the type is large,
162 /// but when there are only two fields in the struct (whichever their
163 /// order is), it will set the `DataType` to the type of the non-mutex
164 /// field.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// extern crate flexible_locks;
170 /// #[macro_use]
171 /// extern crate flexible_locks_derive;
172 /// use flexible_locks::{Mutex, RawMutex};
173 ///
174 /// // Pick your choice of raw mutex;
175 /// #[cfg(windows)]
176 /// use flexible_locks::SRWLOCK as RawOsMutex;
177 /// #[cfg(unix)]
178 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
179 ///
180 /// #[derive(MutexProtected, Default)]
181 /// struct Data {
182 /// a: usize,
183 /// b: usize,
184 /// #[mutex]
185 /// mutex: RawOsMutex,
186 /// }
187 ///
188 /// #[derive(MutexProtected, Default)]
189 /// struct Data2 {
190 /// a: usize,
191 /// #[mutex]
192 /// mutex: RawOsMutex,
193 /// }
194 ///
195 /// #[derive(MutexProtected, Default)]
196 /// struct Data3 {
197 /// #[mutex]
198 /// mutex: RawOsMutex,
199 /// a: usize,
200 /// }
201 ///
202 /// fn main() {
203 /// let mut mutex = Mutex::new(Data::default());
204 /// mutex.lock().a = 10;
205 /// let mut mutex = Mutex::new(Data2::default());
206 /// *mutex.lock() = 10;
207 /// let mut mutex = Mutex::new(Data3::default());
208 /// *mutex.lock() = 10;
209 /// }
210 /// ```
211 ///
212 /// `MutexWrap<RawOsMutex, usize>` should be preferred to `Mutex<Data2>`
213 /// and `Mutex<Data3>`.
214 type DataType: ?Sized;
215
216 /// Return an immutable reference to the raw mutex.
217 fn get_mutex(&self) -> &Self::MutexType;
218
219 /// Return a mutable reference to the raw mutex.
220 fn get_mutex_mut(&mut self) -> &mut Self::MutexType;
221
222 /// Return an immutable reference to the data.
223 fn get_data(&self) -> &Self::DataType;
224
225 /// Return a mutable reference to the data.
226 fn get_data_mut(&mut self) -> &mut Self::DataType;
227
228 /// Consumes the wrapping type, returning the underlying data.
229 fn into_data(self) -> Self::DataType
230 where
231 Self::DataType: Sized;
232}
233
234// FIXME: specialization should allow to just use (M, T) directly,
235// and to turn MutexWrap into a type alias.
236#[doc(hidden)]
237#[derive(MutexProtected)]
238pub struct MutexWrapper<M: RawMutex, T: ?Sized>(#[mutex] pub M, pub T);
239
240impl<M: RawMutex + Default, T> From<T> for MutexWrapper<M, T> {
241 fn from(t: T) -> Self {
242 MutexWrapper(Default::default(), t)
243 }
244}
245
246/// A mutual exclusion primitive useful for protecting shared data
247///
248/// This mutex will block threads waiting for the lock to become available. The
249/// mutex can be statically initialized via the [`mutex_new`] macro, or created
250/// via a [`new`] constructor. Each mutex has a type parameter which represents
251/// the data that it is protecting. The data can only be accessed through the
252/// RAII guards returned from [`lock`], which guarantees that the data is only
253/// ever accessed when the mutex is locked.
254///
255/// [`new`]: #method.new
256/// [`lock`]: #method.lock
257///
258/// # Differences from [`std::sync::Mutex`]
259///
260/// - No poisoning.
261/// - No `try_lock`.
262/// - The underlying raw mutex primitive can be of any kind, within a `Box` or
263/// not, as long as the [`RawMutex`] trait is implemented. Choose carefully.
264/// - The raw mutex primitive can be embedded anywhere in the data type. See
265/// the [`MutexWrap`] type for a variant that looks more like
266/// [`std::sync::Mutex`] but still allows to use a specific raw mutex
267/// primitive.
268/// - With care, this can allow to share data through FFI and contend on the
269/// same locks. See the `ffi-example` directory.
270///
271/// [`std::sync::Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
272/// [`RawMutex`]: trait.RawMutex.html
273///
274/// # Examples
275///
276/// ```
277/// extern crate flexible_locks;
278/// #[macro_use]
279/// extern crate flexible_locks_derive;
280/// use flexible_locks::{Mutex, RawMutex};
281///
282/// // Pick your choice of raw mutex;
283/// #[cfg(windows)]
284/// use flexible_locks::SRWLOCK as RawOsMutex;
285/// #[cfg(unix)]
286/// use flexible_locks::pthread_mutex_t as RawOsMutex;
287///
288/// use std::sync::Arc;
289/// use std::thread;
290/// use std::sync::mpsc::channel;
291///
292/// #[derive(MutexProtected, Default)]
293/// struct Data {
294/// a: usize,
295/// b: usize,
296/// #[mutex]
297/// mutex: RawOsMutex,
298/// }
299///
300/// const N: usize = 10;
301///
302/// fn main() {
303/// // Spawn a few threads to increment a shared variable (non-atomically),
304/// // and let the main thread know once all increments are done.
305/// //
306/// // Here we're using an Arc to share memory among threads, and the data
307/// // inside the Arc is protected with a mutex.
308/// let data = Arc::new(Mutex::new(Data::default()));
309///
310/// let (tx, rx) = channel();
311/// for _ in 0..N {
312/// let (data, tx) = (data.clone(), tx.clone());
313/// thread::spawn(move || {
314/// // The shared state can only be accessed once the lock is held.
315/// // Our non-atomic increment is safe because we're the only thread
316/// // which can access the shared state when the lock is held.
317/// let mut data = data.lock();
318/// data.a += 1;
319/// if data.a == N {
320/// tx.send(()).unwrap();
321/// }
322/// // the lock is unlocked here when `data` goes out of scope.
323/// });
324/// }
325///
326/// rx.recv().unwrap();
327/// }
328/// ```
329///
330/// Please note that `#[derive(MutexProtected)]` treats structs containing only
331/// two fields including the raw mutex differently, such that the data handed
332/// by [`Mutex::lock`] is the non-mutex field, rather than the whole data.
333/// In that case, it is preferable to use [`MutexWrap`] instead.
334/// See [`MutexProtected::DataType`].
335pub struct Mutex<T: MutexProtected + ?Sized> {
336 #[doc(hidden)]
337 pub __wrapper: UnsafeCell<T>,
338}
339
340unsafe impl<T: MutexProtected + ?Sized + Send> Send for Mutex<T> {}
341unsafe impl<T: MutexProtected + ?Sized + Send> Sync for Mutex<T> {}
342
343/// Statically initializes a [`Mutex`] or a [`MutexWrap`].
344///
345/// This skips the [`RawMutex::init`] method, so please be careful when using
346/// this, and ensure the statically initialized raw mutex is properly usable.
347///
348/// For non-static initialization, it is recommended to use [`Mutex::new`] or
349/// [`MutexWrap::new`].
350///
351/// # Examples
352///
353/// ```
354/// #[macro_use]
355/// extern crate flexible_locks;
356/// #[macro_use]
357/// extern crate flexible_locks_derive;
358/// use flexible_locks::{Mutex, MutexWrap, RawMutex};
359///
360/// // Pick your choice of raw mutex;
361/// #[cfg(windows)]
362/// use flexible_locks::SRWLOCK as RawOsMutex;
363/// #[cfg(unix)]
364/// use flexible_locks::pthread_mutex_t as RawOsMutex;
365///
366/// #[derive(MutexProtected)]
367/// struct Data {
368/// a: usize,
369/// b: usize,
370/// #[mutex]
371/// mutex: RawOsMutex,
372/// }
373///
374/// static DATA: Mutex<Data> = mutex_new!(Data {
375/// a: 2,
376/// b: 1,
377/// #[cfg(windows)]
378/// mutex: srwlock_new!(),
379/// #[cfg(unix)]
380/// mutex: pthread_mutex_new!(),
381/// });
382///
383/// struct Data2 {
384/// a: usize,
385/// b: usize,
386/// }
387///
388/// #[cfg(windows)]
389/// macro_rules! raw_os_mutex {
390/// () => { srwlock_new!() };
391/// }
392/// #[cfg(unix)]
393/// macro_rules! raw_os_mutex {
394/// () => { pthread_mutex_new!() };
395/// }
396///
397/// static DATA2: MutexWrap<RawOsMutex, Data2> = mutex_new!(
398/// raw_os_mutex!(),
399/// Data2 { a: 2, b: 1 }
400/// );
401/// # fn main() {}
402/// ```
403#[macro_export]
404macro_rules! mutex_new {
405 ($m:expr, $d:expr) => {
406 $crate::MutexWrap {
407 __inner: mutex_new!($crate::MutexWrapper($m, $d)),
408 }
409 };
410 ($e:expr) => {
411 $crate::Mutex {
412 __wrapper: $crate::UnsafeCell::new($e),
413 }
414 };
415}
416
417impl<T: MutexProtected> Mutex<T>
418where
419 T::DataType: Sized,
420{
421 /// Creates a new mutex in an unlocked state ready for use.
422 ///
423 /// # Examples
424 ///
425 /// ```
426 /// #[macro_use]
427 /// extern crate flexible_locks;
428 /// #[macro_use]
429 /// extern crate flexible_locks_derive;
430 /// use flexible_locks::{Mutex, RawMutex};
431 ///
432 /// // Pick your choice of raw mutex;
433 /// #[cfg(windows)]
434 /// use flexible_locks::SRWLOCK as RawOsMutex;
435 /// #[cfg(unix)]
436 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
437 ///
438 /// #[derive(MutexProtected)]
439 /// struct Data {
440 /// a: usize,
441 /// b: usize,
442 /// #[mutex]
443 /// mutex: RawOsMutex,
444 /// }
445 ///
446 /// fn main() {
447 /// let mutex = Mutex::new(Data {
448 /// a: 2,
449 /// b: 1,
450 /// mutex: Default::default(),
451 /// });
452 /// }
453 /// ```
454 pub fn new(t: T) -> Self {
455 let m = mutex_new!(t);
456 unsafe {
457 let wrapper: &mut T = &mut *m.__wrapper.get();
458 wrapper.get_mutex_mut().init();
459 }
460 m
461 }
462
463 /// Consumes this mutex, returning the underlying data.
464 ///
465 /// When the data type contains the raw mutex, which happens with
466 /// `#[derive(MutexProtected)]`, the returned data obviously still
467 /// contains it. It is however in a destroyed state and may not be
468 /// reused.
469 ///
470 /// # Examples
471 ///
472 /// ```
473 /// #[macro_use]
474 /// extern crate flexible_locks;
475 /// #[macro_use]
476 /// extern crate flexible_locks_derive;
477 /// use flexible_locks::{Mutex, RawMutex};
478 ///
479 /// // Pick your choice of raw mutex;
480 /// #[cfg(windows)]
481 /// use flexible_locks::SRWLOCK as RawOsMutex;
482 /// #[cfg(unix)]
483 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
484 ///
485 /// #[derive(MutexProtected)]
486 /// struct Data {
487 /// a: usize,
488 /// b: usize,
489 /// #[mutex]
490 /// mutex: RawOsMutex,
491 /// }
492 ///
493 /// fn main() {
494 /// let mutex = Mutex::new(Data {
495 /// a: 2,
496 /// b: 1,
497 /// mutex: Default::default(),
498 /// });
499 /// let data = mutex.into_inner();
500 /// assert_eq!(data.a, 2);
501 /// assert_eq!(data.b, 1);
502 /// }
503 /// ```
504 pub fn into_inner(self) -> T::DataType {
505 unsafe {
506 let wrapper = ptr::read(&self.__wrapper);
507 core::mem::forget(self);
508 wrapper.into_inner().into_data()
509 }
510 }
511}
512
513impl<T: MutexProtected> From<T> for Mutex<T>
514where
515 T::DataType: Sized,
516{
517 fn from(t: T) -> Self {
518 Mutex::<T>::new(t)
519 }
520}
521
522impl<T: MutexProtected<DataType = T> + Sized + Default> Default for Mutex<T> {
523 fn default() -> Self {
524 Mutex::<T>::new(Default::default())
525 }
526}
527
528impl<T: MutexProtected + ?Sized> Mutex<T> {
529 /// Acquires a mutex, blocking the current thread until it is able to do so.
530 ///
531 /// This function will block the local thread until it is available to acquire
532 /// the mutex. Upon returning, the thread is the only thread with the lock
533 /// held. An RAII guard is returned to allow scoped unlock of the lock. When
534 /// the guard goes out of scope, the mutex will be unlocked.
535 ///
536 /// The exact behavior on locking a mutex in the thread which already holds
537 /// the lock depends on the underlying raw mutex implementation.
538 ///
539 /// # Examples
540 ///
541 /// ```
542 /// extern crate flexible_locks;
543 /// #[macro_use]
544 /// extern crate flexible_locks_derive;
545 /// use flexible_locks::{Mutex, RawMutex};
546 ///
547 /// // Pick your choice of raw mutex;
548 /// #[cfg(windows)]
549 /// use flexible_locks::SRWLOCK as RawOsMutex;
550 /// #[cfg(unix)]
551 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
552 ///
553 /// use std::sync::Arc;
554 /// use std::thread;
555 ///
556 /// #[derive(MutexProtected, Default)]
557 /// struct Data {
558 /// a: usize,
559 /// b: usize,
560 /// #[mutex]
561 /// mutex: RawOsMutex,
562 /// }
563 ///
564 /// fn main() {
565 /// let mutex = Arc::new(Mutex::new(Data::default()));
566 /// let c_mutex = mutex.clone();
567 ///
568 /// thread::spawn(move || {
569 /// c_mutex.lock().a = 10;
570 /// }).join().expect("thread::spawn failed");
571 /// assert_eq!(mutex.lock().a, 10);
572 /// }
573 /// ```
574 pub fn lock(&self) -> MutexGuard<T> {
575 unsafe {
576 let wrapper = &mut *self.__wrapper.get();
577 wrapper.get_mutex().lock();
578 MutexGuard::new(wrapper)
579 }
580 }
581
582 /// Returns a mutable reference to the underlying data.
583 ///
584 /// Since this call borrows the `Mutex` mutably, no actual locking needs to
585 /// take place---the mutable borrow statically guarantees no locks exist.
586 ///
587 /// # Examples
588 ///
589 /// ```
590 /// extern crate flexible_locks;
591 /// #[macro_use]
592 /// extern crate flexible_locks_derive;
593 /// use flexible_locks::{Mutex, RawMutex};
594 ///
595 /// // Pick your choice of raw mutex;
596 /// #[cfg(windows)]
597 /// use flexible_locks::SRWLOCK as RawOsMutex;
598 /// #[cfg(unix)]
599 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
600 ///
601 /// #[derive(MutexProtected, Default)]
602 /// struct Data {
603 /// a: usize,
604 /// b: usize,
605 /// #[mutex]
606 /// mutex: RawOsMutex,
607 /// }
608 ///
609 /// fn main() {
610 /// let mut mutex = Mutex::new(Data::default());
611 /// mutex.get_mut().a = 10;
612 /// assert_eq!(mutex.lock().a, 10);
613 /// }
614 /// ```
615 pub fn get_mut(&mut self) -> &mut T::DataType {
616 let wrapper = unsafe { &mut *self.__wrapper.get() };
617 T::get_data_mut(wrapper)
618 }
619}
620
621impl<T: MutexProtected + ?Sized> Drop for Mutex<T> {
622 fn drop(&mut self) {
623 unsafe {
624 let wrapper: &T = &*self.__wrapper.get();
625 wrapper.get_mutex().destroy();
626 }
627 }
628}
629
630/// A mutual exclusion primitive useful for protecting shared data
631///
632/// This mutex will block threads waiting for the lock to become available. The
633/// mutex can be statically initialized via the [`mutex_new`] macro, or created
634/// via a [`new`] constructor. Each mutex has a raw mutex and a type parameter
635/// which represents the data that it is protecting. The data can only be
636/// accessed through the RAII guards returned from [`lock`], which guarantees
637/// that the data is only ever accessed when the mutex is locked.
638///
639/// [`new`]: #method.new
640/// [`lock`]: #method.lock
641///
642/// # Differences from [`std::sync::Mutex`]
643///
644/// - No poisoning.
645/// - No `try_lock`.
646/// - The underlying raw mutex primitive can be of any kind, within a `Box` or
647/// not, as long as the [`RawMutex`] trait is implemented. Choose carefully.
648/// - With care, this can allow to share data through FFI and contend on the
649/// same locks. See the `ffi-example` directory.
650///
651/// # Examples
652///
653/// ```
654/// extern crate flexible_locks;
655/// #[macro_use]
656/// extern crate flexible_locks_derive;
657/// use flexible_locks::MutexWrap;
658///
659/// // Pick your choice of raw mutex;
660/// #[cfg(windows)]
661/// use flexible_locks::SRWLOCK as RawOsMutex;
662/// #[cfg(unix)]
663/// use flexible_locks::pthread_mutex_t as RawOsMutex;
664///
665/// use std::sync::Arc;
666/// use std::thread;
667/// use std::sync::mpsc::channel;
668///
669/// const N: usize = 10;
670///
671/// fn main() {
672/// // Spawn a few threads to increment a shared variable (non-atomically),
673/// // and let the main thread know once all increments are done.
674/// //
675/// // Here we're using an Arc to share memory among threads, and the data
676/// // inside the Arc is protected with a mutex.
677/// let data = Arc::new(MutexWrap::<RawOsMutex, _>::new(0));
678///
679/// let (tx, rx) = channel();
680/// for _ in 0..N {
681/// let (data, tx) = (data.clone(), tx.clone());
682/// thread::spawn(move || {
683/// // The shared state can only be accessed once the lock is held.
684/// // Our non-atomic increment is safe because we're the only thread
685/// // which can access the shared state when the lock is held.
686/// let mut data = data.lock();
687/// *data += 1;
688/// if *data == N {
689/// tx.send(()).unwrap();
690/// }
691/// // the lock is unlocked here when `data` goes out of scope.
692/// });
693/// }
694///
695/// rx.recv().unwrap();
696/// }
697/// ```
698pub struct MutexWrap<M: RawMutex, T: ?Sized> {
699 #[doc(hidden)]
700 pub __inner: Mutex<MutexWrapper<M, T>>,
701}
702
703impl<M: RawMutex + Default, T> MutexWrap<M, T> {
704 /// Creates a new mutex in an unlocked state ready for use.
705 ///
706 /// # Examples
707 ///
708 /// ```
709 /// #[macro_use]
710 /// extern crate flexible_locks;
711 /// #[macro_use]
712 /// extern crate flexible_locks_derive;
713 /// use flexible_locks::MutexWrap;
714 ///
715 /// // Pick your choice of raw mutex;
716 /// #[cfg(windows)]
717 /// use flexible_locks::SRWLOCK as RawOsMutex;
718 /// #[cfg(unix)]
719 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
720 ///
721 /// fn main() {
722 /// let mutex = MutexWrap::<RawOsMutex, _>::new(0);
723 /// }
724 /// ```
725 pub fn new(t: T) -> Self {
726 MutexWrap {
727 __inner: Mutex::new(MutexWrapper(Default::default(), t)),
728 }
729 }
730
731 /// Consumes this mutex, returning the underlying data.
732 ///
733 /// # Examples
734 ///
735 /// ```
736 /// #[macro_use]
737 /// extern crate flexible_locks;
738 /// #[macro_use]
739 /// extern crate flexible_locks_derive;
740 /// use flexible_locks::MutexWrap;
741 ///
742 /// // Pick your choice of raw mutex;
743 /// #[cfg(windows)]
744 /// use flexible_locks::SRWLOCK as RawOsMutex;
745 /// #[cfg(unix)]
746 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
747 ///
748 /// fn main() {
749 /// let mutex = MutexWrap::<RawOsMutex, _>::new(0);
750 /// assert_eq!(mutex.into_inner(), 0);
751 /// }
752 /// ```
753 pub fn into_inner(self) -> T {
754 self.__inner.into_inner()
755 }
756}
757
758impl<M: RawMutex + Default, T> From<T> for MutexWrap<M, T> {
759 fn from(t: T) -> Self {
760 MutexWrap::new(t)
761 }
762}
763
764impl<M: RawMutex + Default, T: Default> Default for MutexWrap<M, T> {
765 fn default() -> Self {
766 MutexWrap::new(Default::default())
767 }
768}
769
770impl<M: RawMutex, T: ?Sized> MutexWrap<M, T> {
771 /// Acquires a mutex, blocking the current thread until it is able to do so.
772 ///
773 /// This function will block the local thread until it is available to acquire
774 /// the mutex. Upon returning, the thread is the only thread with the lock
775 /// held. An RAII guard is returned to allow scoped unlock of the lock. When
776 /// the guard goes out of scope, the mutex will be unlocked.
777 ///
778 /// The exact behavior on locking a mutex in the thread which already holds
779 /// the lock depends on the underlying raw mutex implementation.
780 ///
781 /// # Examples
782 ///
783 /// ```
784 /// extern crate flexible_locks;
785 /// #[macro_use]
786 /// extern crate flexible_locks_derive;
787 /// use flexible_locks::MutexWrap;
788 ///
789 /// // Pick your choice of raw mutex;
790 /// #[cfg(windows)]
791 /// use flexible_locks::SRWLOCK as RawOsMutex;
792 /// #[cfg(unix)]
793 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
794 ///
795 /// use std::sync::Arc;
796 /// use std::thread;
797 ///
798 /// fn main() {
799 /// let mutex = Arc::new(MutexWrap::<RawOsMutex, _>::new(0));
800 /// let c_mutex = mutex.clone();
801 ///
802 /// thread::spawn(move || {
803 /// *c_mutex.lock() = 10;
804 /// }).join().expect("thread::spawn failed");
805 /// assert_eq!(*mutex.lock(), 10);
806 /// }
807 /// ```
808 pub fn lock(&self) -> MutexGuard<MutexWrapper<M, T>> {
809 self.__inner.lock()
810 }
811
812 /// Returns a mutable reference to the underlying data.
813 ///
814 /// Since this call borrows the `Mutex` mutably, no actual locking needs to
815 /// take place---the mutable borrow statically guarantees no locks exist.
816 ///
817 /// # Examples
818 ///
819 /// ```
820 /// extern crate flexible_locks;
821 /// #[macro_use]
822 /// extern crate flexible_locks_derive;
823 /// use flexible_locks::MutexWrap;
824 ///
825 /// // Pick your choice of raw mutex;
826 /// #[cfg(windows)]
827 /// use flexible_locks::SRWLOCK as RawOsMutex;
828 /// #[cfg(unix)]
829 /// use flexible_locks::pthread_mutex_t as RawOsMutex;
830 ///
831 /// fn main() {
832 /// let mut mutex = MutexWrap::<RawOsMutex, _>::new(0);
833 /// *mutex.get_mut() = 10;
834 /// assert_eq!(*mutex.lock(), 10);
835 /// }
836 /// ```
837 pub fn get_mut(&mut self) -> &mut T {
838 self.__inner.get_mut()
839 }
840}
841
842/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
843/// dropped (falls out of scope), the lock will be unlocked.
844///
845/// The data protected by the mutex can be accessed through this guard via its
846/// [`Deref`] and [`DerefMut`] implementations.
847///
848/// This structure is created by [`Mutex::lock`] and [`MutexWrap::lock`].
849#[must_use]
850pub struct MutexGuard<'a, T: MutexProtected + ?Sized + 'a> {
851 __wrapper: &'a mut T,
852 marker: PhantomData<*mut ()>, // prevents an automatic impl Send.
853}
854
855unsafe impl<'a, T: MutexProtected + ?Sized + Sync> Sync for MutexGuard<'a, T> {}
856
857impl<'a, T: MutexProtected + ?Sized + 'a> MutexGuard<'a, T> {
858 fn new(wrapper: &'a mut T) -> Self {
859 MutexGuard {
860 __wrapper: wrapper,
861 marker: PhantomData,
862 }
863 }
864}
865
866impl<'a, T: MutexProtected + ?Sized + 'a> Drop for MutexGuard<'a, T> {
867 fn drop(&mut self) {
868 unsafe {
869 self.__wrapper.get_mutex().unlock();
870 }
871 }
872}
873
874impl<'a, T: MutexProtected + ?Sized + 'a> Deref for MutexGuard<'a, T> {
875 type Target = T::DataType;
876
877 fn deref(&self) -> &T::DataType {
878 T::get_data(&self.__wrapper)
879 }
880}
881
882impl<'a, T: MutexProtected + ?Sized + 'a> DerefMut for MutexGuard<'a, T> {
883 fn deref_mut(&mut self) -> &mut T::DataType {
884 T::get_data_mut(&mut self.__wrapper)
885 }
886}
887
888/// Type alias for `parking_lot::Mutex<()>`.
889#[cfg(feature = "parking_lot")]
890pub type ParkingLotMutex = parking_lot::Mutex<()>;
891
892#[cfg(feature = "parking_lot")]
893impl RawMutex for ParkingLotMutex {
894 unsafe fn lock(&self) {
895 self.raw_lock()
896 }
897
898 unsafe fn unlock(&self) {
899 self.raw_unlock()
900 }
901}
902
903#[cfg(test)]
904mod tests {
905 use super::*;
906 #[cfg(windows)]
907 type RawOsMutex = SRWLOCK;
908 #[cfg(unix)]
909 type RawOsMutex = pthread_mutex_t;
910
911 mod base {
912 use super::*;
913
914 static mut INITIALIZED: usize = 0;
915 static mut LOCKED: usize = 0;
916 static mut UNLOCKED: usize = 0;
917 static mut DESTROYED: usize = 0;
918
919 #[derive(PartialEq, Debug, Default)]
920 struct FakeMutex;
921
922 unsafe impl Send for FakeMutex {}
923 unsafe impl Sync for FakeMutex {}
924
925 impl RawMutex for FakeMutex {
926 unsafe fn init(&mut self) {
927 INITIALIZED += 1;
928 }
929
930 unsafe fn lock(&self) {
931 LOCKED += 1;
932 }
933
934 unsafe fn unlock(&self) {
935 UNLOCKED += 1;
936 }
937
938 unsafe fn destroy(&self) {
939 DESTROYED += 1;
940 }
941 }
942
943 #[derive(MutexProtected, PartialEq, Debug, Default)]
944 struct WithEmbeddedMutex<M: RawMutex>(usize, #[mutex] M, usize);
945
946 #[test]
947 fn smoke() {
948 macro_rules! smoke_test {
949 ($m:expr, $drop:expr) => {
950 unsafe {
951 INITIALIZED = 0;
952 LOCKED = 0;
953 UNLOCKED = 0;
954 DESTROYED = 0;
955 }
956 let m = $m;
957 unsafe {
958 assert_eq!(INITIALIZED, 1);
959 assert_eq!(LOCKED, 0);
960 assert_eq!(UNLOCKED, 0);
961 assert_eq!(DESTROYED, 0);
962 }
963 for i in 0..2 {
964 let data = m.lock();
965 unsafe {
966 assert_eq!(INITIALIZED, 1);
967 assert_eq!(LOCKED, i + 1);
968 assert_eq!(UNLOCKED, i);
969 assert_eq!(DESTROYED, 0);
970 }
971 drop(data);
972 unsafe {
973 assert_eq!(INITIALIZED, 1);
974 assert_eq!(LOCKED, i + 1);
975 assert_eq!(UNLOCKED, i + 1);
976 assert_eq!(DESTROYED, 0);
977 }
978 }
979 $drop(m);
980 unsafe {
981 assert_eq!(INITIALIZED, 1);
982 assert_eq!(LOCKED, 2);
983 assert_eq!(UNLOCKED, 2);
984 assert_eq!(DESTROYED, 1);
985 }
986 };
987 }
988
989 smoke_test!(MutexWrap::<FakeMutex, usize>::new(42), drop);
990 smoke_test!(
991 MutexWrap::<FakeMutex, usize>::new(42),
992 |m: MutexWrap<_, _>| assert_eq!(m.into_inner(), 42)
993 );
994 smoke_test!(MutexWrap::<Box<FakeMutex>, usize>::new(42), drop);
995 smoke_test!(
996 MutexWrap::<Box<FakeMutex>, usize>::new(42),
997 |m: MutexWrap<_, _>| assert_eq!(m.into_inner(), 42)
998 );
999 smoke_test!(Mutex::new(WithEmbeddedMutex(42, FakeMutex, 42)), drop);
1000 smoke_test!(
1001 Mutex::new(WithEmbeddedMutex(42, FakeMutex, 42)),
1002 |m: Mutex<_>| assert_eq!(m.into_inner(), WithEmbeddedMutex(42, FakeMutex, 42))
1003 );
1004 smoke_test!(
1005 Mutex::new(WithEmbeddedMutex(42, Box::new(FakeMutex), 42)),
1006 drop
1007 );
1008 smoke_test!(
1009 Mutex::new(WithEmbeddedMutex(42, Box::new(FakeMutex), 42)),
1010 |m: Mutex<_>| assert_eq!(
1011 m.into_inner(),
1012 WithEmbeddedMutex(42, Box::new(FakeMutex), 42)
1013 )
1014 );
1015 }
1016 }
1017
1018 mod wrap {
1019 use super::*;
1020 type Mutex<T> = super::MutexWrap<RawOsMutex, T>;
1021 include!("tests.rs");
1022 }
1023
1024 mod boxed {
1025 use super::*;
1026 type Mutex<T> = super::MutexWrap<Box<RawOsMutex>, T>;
1027 include!("tests.rs");
1028 }
1029
1030 #[cfg(feature = "parking_lot")]
1031 mod parking_lot {
1032 use super::*;
1033 type Mutex<T> = super::MutexWrap<ParkingLotMutex, T>;
1034 include!("tests.rs");
1035 }
1036
1037 #[cfg(windows)]
1038 mod critical_section {
1039 use super::*;
1040 type Mutex<T> = super::MutexWrap<CRITICAL_SECTION, T>;
1041 include!("tests.rs");
1042 }
1043
1044 #[cfg(any(target_os = "macos", target_os = "ios"))]
1045 mod osspinlock {
1046 use super::*;
1047 type Mutex<T> = super::MutexWrap<OSSpinLock, T>;
1048 include!("tests.rs");
1049 }
1050}