5
5
//! [`crossbeam-channel`](https://docs.rs/crossbeam-channel/latest/crossbeam_channel/), in as much
6
6
//! as it makes sense.
7
7
8
+ use core:: {
9
+ cell:: UnsafeCell ,
10
+ fmt,
11
+ marker:: PhantomData ,
12
+ ops:: { Deref , DerefMut } ,
13
+ } ;
14
+
15
+ use crate :: time:: Forever ;
16
+ use crate :: sys:: sync as sys;
17
+
8
18
pub mod atomic {
9
19
//! Re-export portable atomic.
10
20
//!
@@ -22,3 +32,116 @@ pub mod atomic {
22
32
23
33
#[ cfg( CONFIG_RUST_ALLOC ) ]
24
34
pub use portable_atomic_util:: Arc ;
35
+
36
+ /// Until poisoning is implemented, mutexes never return an error, and we just get back the guard.
37
+ pub type LockResult < Guard > = Result < Guard , ( ) > ;
38
+
39
+ /// A mutual exclusion primitive useful for protecting shared data.
40
+ ///
41
+ /// This mutex will block threads waiting for the lock to become available. This is modeled after
42
+ /// [`std::sync::Mutex`](https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html), and attempts
43
+ /// to implement that API as closely as makes sense on Zephyr. Currently, it has the following
44
+ /// differences:
45
+ /// - Poisoning: This does not yet implement poisoning, as there is no way to recover from panic at
46
+ /// this time on Zephyr.
47
+ /// - Allocation: `new` is not yet provided, and will be provided once kernel object pools are
48
+ /// implemented. Please use `new_from` which takes a reference to a statically allocated
49
+ /// `sys::Mutex`.
50
+ pub struct Mutex < T : ?Sized > {
51
+ inner : sys:: Mutex ,
52
+ // poison: ...
53
+ data : UnsafeCell < T > ,
54
+ }
55
+
56
+ // At least if correctly done, the Mutex provides for Send and Sync as long as the inner data
57
+ // supports Send.
58
+ unsafe impl < T : ?Sized + Send > Send for Mutex < T > { }
59
+ unsafe impl < T : ?Sized + Send > Sync for Mutex < T > { }
60
+
61
+ impl < T > fmt:: Debug for Mutex < T > {
62
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
63
+ write ! ( f, "Mutex {:?}" , self . inner)
64
+ }
65
+ }
66
+
67
+ /// An RAII implementation of a "scoped lock" of a mutex. When this structure is dropped (faslls
68
+ /// out of scope), the lock will be unlocked.
69
+ ///
70
+ /// The data protected by the mutex can be accessed through this guard via its [`Deref`] and
71
+ /// [`DerefMut`] implementations.
72
+ ///
73
+ /// This structure is created by the [`lock`] and [`try_lock`] methods on [`Mutex`].
74
+ ///
75
+ /// Taken directly from
76
+ /// [`std::sync::MutexGuard`](https://doc.rust-lang.org/stable/std/sync/struct.MutexGuard.html).
77
+ pub struct MutexGuard < ' a , T : ?Sized + ' a > {
78
+ lock : & ' a Mutex < T > ,
79
+ // until <https://github.com/rust-lang/rust/issues/68318> is implemented, we have to mark unsend
80
+ // explicitly. This can be done by holding Phantom data with an unsafe cell in it.
81
+ _nosend : PhantomData < UnsafeCell < ( ) > > ,
82
+ }
83
+
84
+ // Make sure the guard doesn't get sent.
85
+ // Negative trait bounds are unstable, see marker above.
86
+ // impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
87
+ unsafe impl < T : ?Sized + Sync > Sync for MutexGuard < ' _ , T > { }
88
+
89
+ impl < T > Mutex < T > {
90
+ /// Construct a new wrapped Mutex, using the given underlying sys mutex. This is different that
91
+ /// `std::sync::Mutex` in that in Zephyr, objects are frequently allocated statically, and the
92
+ /// sys Mutex will be taken by this structure. It is safe to share the underlying Mutex between
93
+ /// different items, but without careful use, it is easy to deadlock, so it is not recommended.
94
+ pub const fn new_from ( t : T , raw_mutex : sys:: Mutex ) -> Mutex < T > {
95
+ Mutex { inner : raw_mutex, data : UnsafeCell :: new ( t) }
96
+ }
97
+ }
98
+
99
+ impl < T : ?Sized > Mutex < T > {
100
+ /// Acquires a mutex, blocking the current thread until it is able to do so.
101
+ ///
102
+ /// This function will block the local thread until it is available to acquire the mutex. Upon
103
+ /// returning, the thread is the only thread with the lock held. An RAII guard is returned to
104
+ /// allow scoped unlock of the lock. When the guard goes out of scope, the mutex will be
105
+ /// unlocked.
106
+ ///
107
+ /// In `std`, an attempt to lock a mutex by a thread that already holds the mutex is
108
+ /// unspecified. Zephyr explicitly supports this behavior, by simply incrementing a lock
109
+ /// count.
110
+ pub fn lock ( & self ) -> LockResult < MutexGuard < ' _ , T > > {
111
+ // With `Forever`, should never return an error.
112
+ self . inner . lock ( Forever ) . unwrap ( ) ;
113
+ unsafe {
114
+ MutexGuard :: new ( self )
115
+ }
116
+ }
117
+ }
118
+
119
+ impl < ' mutex , T : ?Sized > MutexGuard < ' mutex , T > {
120
+ unsafe fn new ( lock : & ' mutex Mutex < T > ) -> LockResult < MutexGuard < ' mutex , T > > {
121
+ // poison todo
122
+ Ok ( MutexGuard { lock, _nosend : PhantomData } )
123
+ }
124
+ }
125
+
126
+ impl < T : ?Sized > Deref for MutexGuard < ' _ , T > {
127
+ type Target = T ;
128
+
129
+ fn deref ( & self ) -> & T {
130
+ unsafe {
131
+ & * self . lock . data . get ( )
132
+ }
133
+ }
134
+ }
135
+
136
+ impl < T : ?Sized > DerefMut for MutexGuard < ' _ , T > {
137
+ fn deref_mut ( & mut self ) -> & mut T {
138
+ unsafe { & mut * self . lock . data . get ( ) }
139
+ }
140
+ }
141
+
142
+ impl < T : ?Sized > Drop for MutexGuard < ' _ , T > {
143
+ #[ inline]
144
+ fn drop ( & mut self ) {
145
+ self . lock . inner . unlock ( ) . unwrap ( ) ;
146
+ }
147
+ }
0 commit comments