Skip to content

Commit 46f7f3b

Browse files
committed
zephyr: Move the sync::Mutex into it's own file
Avoid cluttering the top-level sync module with specifics. Signed-off-by: David Brown <[email protected]>
1 parent 343c044 commit 46f7f3b

File tree

2 files changed

+257
-245
lines changed

2 files changed

+257
-245
lines changed

zephyr/src/sync.rs

+8-245
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,6 @@
55
//! [`crossbeam-channel`](https://docs.rs/crossbeam-channel/latest/crossbeam_channel/), in as much
66
//! as it makes sense.
77
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-
188
// Channels are currently only available with allocation. Bounded channels later might be
199
// available.
2010
#[cfg(CONFIG_RUST_ALLOC)]
@@ -38,239 +28,12 @@ pub mod atomic {
3828
#[cfg(CONFIG_RUST_ALLOC)]
3929
pub use portable_atomic_util::Arc;
4030

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;
11332

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

Comments
 (0)