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 , NoWait } ;
16
- use crate :: sys:: sync as sys;
17
-
18
8
// Channels are currently only available with allocation. Bounded channels later might be
19
9
// available.
20
10
#[ cfg( CONFIG_RUST_ALLOC ) ]
@@ -38,239 +28,12 @@ pub mod atomic {
38
28
#[ cfg( CONFIG_RUST_ALLOC ) ]
39
29
pub use portable_atomic_util:: Arc ;
40
30
41
- // Channels are currently only available with allocation. Bounded channels later might be
42
- // available.
43
-
44
- /// Until poisoning is implemented, mutexes never return an error, and we just get back the guard.
45
- pub type LockResult < Guard > = Result < Guard , ( ) > ;
46
-
47
- /// The return type from [`Mutex::try_lock`].
48
- ///
49
- /// The error indicates the reason for the failure. Until poisoning is
50
- /// implemented, there is only a single type of failure.
51
- pub type TryLockResult < Guard > = Result < Guard , TryLockError > ;
52
-
53
- /// An enumeration of possible errors associated with a [`TryLockResult`].
54
- ///
55
- /// Note that until Poisoning is implemented, there is only one value of this.
56
- pub enum TryLockError {
57
- /// The lock could not be acquired at this time because the operation would otherwise block.
58
- WouldBlock ,
59
- }
60
-
61
- /// A mutual exclusion primitive useful for protecting shared data.
62
- ///
63
- /// This mutex will block threads waiting for the lock to become available. This is modeled after
64
- /// [`std::sync::Mutex`](https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html), and attempts
65
- /// to implement that API as closely as makes sense on Zephyr. Currently, it has the following
66
- /// differences:
67
- /// - Poisoning: This does not yet implement poisoning, as there is no way to recover from panic at
68
- /// this time on Zephyr.
69
- /// - Allocation: `new` is not yet provided, and will be provided once kernel object pools are
70
- /// implemented. Please use `new_from` which takes a reference to a statically allocated
71
- /// `sys::Mutex`.
72
- pub struct Mutex < T : ?Sized > {
73
- inner : sys:: Mutex ,
74
- // poison: ...
75
- data : UnsafeCell < T > ,
76
- }
77
-
78
- // At least if correctly done, the Mutex provides for Send and Sync as long as the inner data
79
- // supports Send.
80
- unsafe impl < T : ?Sized + Send > Send for Mutex < T > { }
81
- unsafe impl < T : ?Sized + Send > Sync for Mutex < T > { }
82
-
83
- impl < T > fmt:: Debug for Mutex < T > {
84
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
85
- write ! ( f, "Mutex {:?}" , self . inner)
86
- }
87
- }
88
-
89
- /// An RAII implementation of a "scoped lock" of a mutex. When this structure is dropped (faslls
90
- /// out of scope), the lock will be unlocked.
91
- ///
92
- /// The data protected by the mutex can be accessed through this guard via its [`Deref`] and
93
- /// [`DerefMut`] implementations.
94
- ///
95
- /// This structure is created by the [`lock`] and [`try_lock`] methods on [`Mutex`].
96
- ///
97
- /// [`lock`]: Mutex::lock
98
- /// [`try_lock`]: Mutex::try_lock
99
- ///
100
- /// Taken directly from
101
- /// [`std::sync::MutexGuard`](https://doc.rust-lang.org/stable/std/sync/struct.MutexGuard.html).
102
- pub struct MutexGuard < ' a , T : ?Sized + ' a > {
103
- lock : & ' a Mutex < T > ,
104
- // until <https://github.com/rust-lang/rust/issues/68318> is implemented, we have to mark unsend
105
- // explicitly. This can be done by holding Phantom data with an unsafe cell in it.
106
- _nosend : PhantomData < UnsafeCell < ( ) > > ,
107
- }
108
-
109
- // Make sure the guard doesn't get sent.
110
- // Negative trait bounds are unstable, see marker above.
111
- // impl<T: ?Sized> !Send for MutexGuard<'_, T> {}
112
- unsafe impl < T : ?Sized + Sync > Sync for MutexGuard < ' _ , T > { }
31
+ mod mutex;
113
32
114
- impl < T > Mutex < T > {
115
- /// Construct a new wrapped Mutex, using the given underlying sys mutex. This is different that
116
- /// `std::sync::Mutex` in that in Zephyr, objects are frequently allocated statically, and the
117
- /// sys Mutex will be taken by this structure. It is safe to share the underlying Mutex between
118
- /// different items, but without careful use, it is easy to deadlock, so it is not recommended.
119
- pub const fn new_from ( t : T , raw_mutex : sys:: Mutex ) -> Mutex < T > {
120
- Mutex { inner : raw_mutex, data : UnsafeCell :: new ( t) }
121
- }
122
-
123
- /// Construct a new Mutex, dynamically allocating the underlying sys Mutex.
124
- #[ cfg( CONFIG_RUST_ALLOC ) ]
125
- pub fn new ( t : T ) -> Mutex < T > {
126
- Mutex :: new_from ( t, sys:: Mutex :: new ( ) . unwrap ( ) )
127
- }
128
- }
129
-
130
- impl < T : ?Sized > Mutex < T > {
131
- /// Acquires a mutex, blocking the current thread until it is able to do so.
132
- ///
133
- /// This function will block the local thread until it is available to acquire the mutex. Upon
134
- /// returning, the thread is the only thread with the lock held. An RAII guard is returned to
135
- /// allow scoped unlock of the lock. When the guard goes out of scope, the mutex will be
136
- /// unlocked.
137
- ///
138
- /// In `std`, an attempt to lock a mutex by a thread that already holds the mutex is
139
- /// unspecified. Zephyr explicitly supports this behavior, by simply incrementing a lock
140
- /// count.
141
- pub fn lock ( & self ) -> LockResult < MutexGuard < ' _ , T > > {
142
- // With `Forever`, should never return an error.
143
- self . inner . lock ( Forever ) . unwrap ( ) ;
144
- unsafe {
145
- Ok ( MutexGuard :: new ( self ) )
146
- }
147
- }
148
-
149
- /// Attempts to acquire this lock.
150
- ///
151
- /// If the lock could not be acquired at this time, then [`Err`] is returned. Otherwise, an RAII
152
- /// guard is returned. The lock will be unlocked when the guard is dropped.
153
- ///
154
- /// This function does not block.
155
- pub fn try_lock ( & self ) -> TryLockResult < MutexGuard < ' _ , T > > {
156
- match self . inner . lock ( NoWait ) {
157
- Ok ( ( ) ) => {
158
- unsafe {
159
- Ok ( MutexGuard :: new ( self ) )
160
- }
161
- }
162
- // TODO: It might be better to distinguish these errors, and only return the WouldBlock
163
- // if that is the corresponding error. But, the lock shouldn't fail in Zephyr.
164
- Err ( _) => {
165
- Err ( TryLockError :: WouldBlock )
166
- }
167
- }
168
- }
169
- }
170
-
171
- impl < ' mutex , T : ?Sized > MutexGuard < ' mutex , T > {
172
- unsafe fn new ( lock : & ' mutex Mutex < T > ) -> MutexGuard < ' mutex , T > {
173
- // poison todo
174
- MutexGuard { lock, _nosend : PhantomData }
175
- }
176
- }
177
-
178
- impl < T : ?Sized > Deref for MutexGuard < ' _ , T > {
179
- type Target = T ;
180
-
181
- fn deref ( & self ) -> & T {
182
- unsafe {
183
- & * self . lock . data . get ( )
184
- }
185
- }
186
- }
187
-
188
- impl < T : ?Sized > DerefMut for MutexGuard < ' _ , T > {
189
- fn deref_mut ( & mut self ) -> & mut T {
190
- unsafe { & mut * self . lock . data . get ( ) }
191
- }
192
- }
193
-
194
- impl < T : ?Sized > Drop for MutexGuard < ' _ , T > {
195
- #[ inline]
196
- fn drop ( & mut self ) {
197
- self . lock . inner . unlock ( ) . unwrap ( ) ;
198
- }
199
- }
200
-
201
- /// Inspired by
202
- /// [`std::sync::Condvar`](https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html),
203
- /// implemented directly using `z_condvar` in Zephyr.
204
- ///
205
- /// Condition variables represent the ability to block a thread such that it consumes no CPU time
206
- /// while waiting for an even to occur. Condition variables are typically associated with a
207
- /// boolean predicate (a condition) and a mutex. The predicate is always verified inside of the
208
- /// mutex before determining that a thread must block.
209
- ///
210
- /// Functions in this module will block the current **thread** of execution. Note that any attempt
211
- /// to use multiple mutexces on the same condition variable may result in a runtime panic.
212
- pub struct Condvar {
213
- inner : sys:: Condvar ,
214
- }
215
-
216
- impl Condvar {
217
- /// Construct a new wrapped Condvar, using the given underlying `k_condvar`.
218
- ///
219
- /// This is different from `std::sync::Condvar` in that in Zephyr, objects are frequently
220
- /// allocated statically, and the sys Condvar will be taken by this structure.
221
- pub const fn new_from ( raw_condvar : sys:: Condvar ) -> Condvar {
222
- Condvar { inner : raw_condvar }
223
- }
224
-
225
- /// Construct a new Condvar, dynamically allocating the underlying Zephyr `k_condvar`.
226
- #[ cfg( CONFIG_RUST_ALLOC ) ]
227
- pub fn new ( ) -> Condvar {
228
- Condvar :: new_from ( sys:: Condvar :: new ( ) . unwrap ( ) )
229
- }
230
-
231
- /// Blocks the current thread until this conditional variable receives a notification.
232
- ///
233
- /// This function will automatically unlock the mutex specified (represented by `guard`) and
234
- /// block the current thread. This means that any calls to `notify_one` or `notify_all` which
235
- /// happen logically after the mutex is unlocked are candidates to wake this thread up. When
236
- /// this function call returns, the lock specified will have been re-equired.
237
- ///
238
- /// Note that this function is susceptable to spurious wakeups. Condition variables normally
239
- /// have a boolean predicate associated with them, and the predicate must always be checked
240
- /// each time this function returns to protect against spurious wakeups.
241
- pub fn wait < ' a , T > ( & self , guard : MutexGuard < ' a , T > ) -> LockResult < MutexGuard < ' a , T > > {
242
- self . inner . wait ( & guard. lock . inner ) ;
243
- Ok ( guard)
244
- }
245
-
246
- // TODO: wait_while
247
- // TODO: wait_timeout_ms
248
- // TODO: wait_timeout
249
- // TODO: wait_timeout_while
250
-
251
- /// Wakes up one blocked thread on this condvar.
252
- ///
253
- /// If there is a blocked thread on this condition variable, then it will be woken up from its
254
- /// call to `wait` or `wait_timeout`. Calls to `notify_one` are not buffered in any way.
255
- ///
256
- /// To wakeup all threads, see `notify_all`.
257
- pub fn notify_one ( & self ) {
258
- self . inner . notify_one ( ) ;
259
- }
260
-
261
- /// Wakes up all blocked threads on this condvar.
262
- ///
263
- /// This methods will ensure that any current waiters on the condition variable are awoken.
264
- /// Calls to `notify_all()` are not buffered in any way.
265
- ///
266
- /// To wake up only one thread, see `notify_one`.
267
- pub fn notify_all ( & self ) {
268
- self . inner . notify_all ( ) ;
269
- }
270
- }
271
-
272
- impl fmt:: Debug for Condvar {
273
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
274
- write ! ( f, "Condvar {:?}" , self . inner)
275
- }
276
- }
33
+ pub use mutex:: {
34
+ Mutex ,
35
+ MutexGuard ,
36
+ Condvar ,
37
+ LockResult ,
38
+ TryLockResult ,
39
+ } ;
0 commit comments