Skip to content

Commit 3a4f08b

Browse files
committed
zepyr: sys: sync: Mutex/Condvar
Update the sys Mutex/Condvar to use the new object initialization, and update the uses. This requires a few fixes: - The SimpleTls no longer needs the StaticTls helper, and we can just use a plain global static Mutex. - Bounded channels add items to a free queue during init. To avoid moving this queue after items have been inserted, we place it in a box. Given that the data of bounded queues is also boxed, this isn't really a concern. Signed-off-by: David Brown <[email protected]>
1 parent 64605eb commit 3a4f08b

File tree

5 files changed

+44
-139
lines changed

5 files changed

+44
-139
lines changed

zephyr/src/simpletls.rs

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,9 @@
55
66
extern crate alloc;
77

8-
use core::{ptr, sync::atomic::Ordering};
9-
10-
use alloc::boxed::Box;
118
use alloc::vec::Vec;
129
use zephyr_sys::{k_current_get, k_thread};
1310

14-
use crate::sync::{atomic::AtomicPtr, Mutex};
15-
1611
/// A container for simple thread local storage.
1712
///
1813
/// This will maintain a mapping between Zephyr threads and a value of type T. Entries will have to
@@ -55,70 +50,3 @@ impl<T: Copy + Send> SimpleTls<T> {
5550
.map(|pos| self.map[pos].1)
5651
}
5752
}
58-
59-
/// A helper to safely use these with static.
60-
///
61-
/// The StaticTls type has a constant constructor, and the same insert and get methods as the
62-
/// underlying SimpleTls, with support for initializing the Mutex as needed.
63-
// TODO: This should eventually make it into a more general lazy mechanism.
64-
pub struct StaticTls<T: Copy + Send> {
65-
/// The container for the data.
66-
///
67-
/// The AtomicPtr is either Null, or contains a raw pointer to the underlying Mutex holding the
68-
/// data.
69-
data: AtomicPtr<Mutex<SimpleTls<T>>>,
70-
}
71-
72-
impl<T: Copy + Send> StaticTls<T> {
73-
/// Create a new StaticTls that is empty.
74-
pub const fn new() -> Self {
75-
Self {
76-
data: AtomicPtr::new(ptr::null_mut()),
77-
}
78-
}
79-
80-
/// Get the underlying Mutex out of the data, initializing it with an empty type if necessary.
81-
fn get_inner(&self) -> &Mutex<SimpleTls<T>> {
82-
let data = self.data.fetch_update(
83-
// TODO: These orderings are likely stronger than necessary.
84-
Ordering::SeqCst,
85-
Ordering::SeqCst,
86-
|ptr| {
87-
if ptr.is_null() {
88-
// For null, we need to allocate a new one.
89-
let data = Box::new(Mutex::new(SimpleTls::new()));
90-
Some(Box::into_raw(data))
91-
} else {
92-
// If there was already a value, just use it.
93-
None
94-
}
95-
},
96-
);
97-
let data = match data {
98-
Ok(_) => {
99-
// If the update stored something, it unhelpfully returns the old value, which was
100-
// the null pointer. Since the pointer will only ever be updated once, it is safe
101-
// to use a relaxed load here.
102-
self.data.load(Ordering::Relaxed)
103-
}
104-
// If there was already a pointer, that is what we want.
105-
Err(ptr) => ptr,
106-
};
107-
108-
// SAFETY: The stored data was updated at most once, by the above code, and we now have a
109-
// pointer to a valid leaked box holding the data.
110-
unsafe { &*data }
111-
}
112-
113-
/// Insert a new association into the StaticTls.
114-
pub fn insert(&self, thread: *const k_thread, data: T) {
115-
let inner = self.get_inner();
116-
inner.lock().unwrap().insert(thread, data);
117-
}
118-
119-
/// Lookup the data associated with a given thread.
120-
pub fn get(&self) -> Option<T> {
121-
let inner = self.get_inner();
122-
inner.lock().unwrap().get()
123-
}
124-
}

zephyr/src/sync/channel.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,8 +569,11 @@ struct Bounded<T> {
569569
/// The UnsafeCell is needed to indicate that this data is handled outside of what Rust is aware
570570
/// of. MaybeUninit allows us to create this without allocation.
571571
_slots: Pin<Box<[Slot<T>]>>,
572-
/// The free queue, holds messages that aren't be used.
573-
free: Queue,
572+
/// The free queue, holds messages that aren't be used. The free queue has to be in a box,
573+
/// because it cannot move after the constructor runs. The chan is fine to wait until first
574+
/// use, when the object has settled. As we are also boxing the messages, this isn't really
575+
/// that costly.
576+
free: Box<Queue>,
574577
/// The channel queue. These are messages that have been sent and are waiting to be received.
575578
chan: Queue,
576579
}
@@ -582,7 +585,7 @@ impl<T> Bounded<T> {
582585
.collect();
583586
let slots = Box::into_pin(slots);
584587

585-
let free = Queue::new();
588+
let free = Box::new(Queue::new());
586589
let chan = Queue::new();
587590

588591
// Add each of the boxes to the free list.

zephyr/src/sync/mutex.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ impl<T> Mutex<T> {
9898
}
9999

100100
/// Construct a new Mutex, dynamically allocating the underlying sys Mutex.
101-
#[cfg(CONFIG_RUST_ALLOC)]
102-
pub fn new(t: T) -> Mutex<T> {
103-
Mutex::new_from(t, sys::Mutex::new().unwrap())
101+
pub const fn new(t: T) -> Mutex<T> {
102+
Mutex::new_from(t, sys::Mutex::new())
104103
}
105104
}
106105

@@ -164,7 +163,9 @@ impl<T: ?Sized> DerefMut for MutexGuard<'_, T> {
164163
impl<T: ?Sized> Drop for MutexGuard<'_, T> {
165164
#[inline]
166165
fn drop(&mut self) {
167-
self.lock.inner.unlock().unwrap();
166+
if let Err(e) = self.lock.inner.unlock() {
167+
panic!("Problem unlocking MutexGuard in drop: {:?}", e);
168+
}
168169
}
169170
}
170171

@@ -195,7 +196,7 @@ impl Condvar {
195196
/// Construct a new Condvar, dynamically allocating the underlying Zephyr `k_condvar`.
196197
#[cfg(CONFIG_RUST_ALLOC)]
197198
pub fn new() -> Condvar {
198-
Condvar::new_from(sys::Condvar::new().unwrap())
199+
Condvar::new_from(sys::Condvar::new())
199200
}
200201

201202
/// Blocks the current thread until this conditional variable receives a notification.

zephyr/src/sys/sync/mutex.rs

Lines changed: 28 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//!
99
//! [`object`]: crate::object
1010
11-
use crate::object::{Fixed, StaticKernelObject, Wrapped};
11+
use crate::object::{ObjectInit, StaticKernelObject, ZephyrObject};
1212
use crate::sys::K_FOREVER;
1313
use crate::{
1414
error::{to_result_void, Result},
@@ -19,8 +19,6 @@ use crate::{
1919
time::Timeout,
2020
};
2121
use core::fmt;
22-
#[cfg(CONFIG_RUST_ALLOC)]
23-
use core::mem;
2422

2523
/// A Zephyr `k_mutux` usable from safe Rust code.
2624
///
@@ -46,20 +44,15 @@ use core::mem;
4644
/// [`sync::Mutex`]: http://example.com/TODO
4745
pub struct Mutex {
4846
/// The raw Zephyr mutex.
49-
item: Fixed<k_mutex>,
47+
item: ZephyrObject<k_mutex>,
5048
}
5149

5250
impl Mutex {
5351
/// Create a new Mutex in an unlocked state.
5452
///
5553
/// Create a new dynamically allocated Mutex. The Mutex can only be used from system threads.
56-
#[cfg(CONFIG_RUST_ALLOC)]
57-
pub fn new() -> Result<Mutex> {
58-
let item: Fixed<k_mutex> = Fixed::new(unsafe { mem::zeroed() });
59-
unsafe {
60-
to_result_void(k_mutex_init(item.get()))?;
61-
}
62-
Ok(Mutex { item })
54+
pub const fn new() -> Mutex {
55+
Mutex { item: <ZephyrObject<k_mutex>>::new_raw() }
6356
}
6457

6558
/// Lock a Zephyr Mutex.
@@ -84,6 +77,15 @@ impl Mutex {
8477
}
8578
}
8679

80+
impl ObjectInit<k_mutex> for ZephyrObject<k_mutex> {
81+
fn init(item: *mut k_mutex) {
82+
// SAFETY: ZephyrObject handles initialization and move prevention.
83+
unsafe {
84+
k_mutex_init(item);
85+
}
86+
}
87+
}
88+
8789
/// A static Zephyr `k_mutex`
8890
///
8991
/// This is intended to be used from within the `kobj_define!` macro. It declares a static
@@ -101,35 +103,18 @@ unsafe impl Send for Mutex {}
101103
unsafe impl Sync for StaticMutex {}
102104
unsafe impl Send for StaticMutex {}
103105

104-
impl Wrapped for StaticKernelObject<k_mutex> {
105-
type T = Mutex;
106-
107-
/// Mutex initializers take no argument.
108-
type I = ();
109-
110-
fn get_wrapped(&self, _arg: Self::I) -> Mutex {
111-
let ptr = self.value.get();
112-
unsafe {
113-
k_mutex_init(ptr);
114-
}
115-
Mutex {
116-
item: Fixed::Static(ptr),
117-
}
118-
}
119-
}
120-
121106
impl fmt::Debug for Mutex {
122107
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123-
write!(f, "sys::Mutex {:?}", self.item.get())
108+
// SAFETY: Address is just gotten to print for diagnostics.
109+
write!(f, "sys::Mutex {:?}", unsafe { self.item.get() })
124110
}
125111
}
126112

127113
/// A Condition Variable
128114
///
129115
/// Lightweight wrappers for Zephyr's `k_condvar`.
130116
pub struct Condvar {
131-
/// The underlying `k_condvar`.
132-
item: Fixed<k_condvar>,
117+
item: ZephyrObject<k_condvar>,
133118
}
134119

135120
#[doc(hidden)]
@@ -144,13 +129,8 @@ impl Condvar {
144129
/// Create a new Condvar.
145130
///
146131
/// Create a new dynamically allocated Condvar. The Condvar can only be used from system threads.
147-
#[cfg(CONFIG_RUST_ALLOC)]
148-
pub fn new() -> Result<Condvar> {
149-
let item: Fixed<k_condvar> = Fixed::new(unsafe { mem::zeroed() });
150-
unsafe {
151-
to_result_void(k_condvar_init(item.get()))?;
152-
}
153-
Ok(Condvar { item })
132+
pub const fn new() -> Condvar {
133+
Condvar { item: <ZephyrObject<k_condvar>>::new_raw() }
154134
}
155135

156136
/// Wait for someone else using this mutex/condvar pair to notify.
@@ -184,25 +164,18 @@ impl Condvar {
184164
}
185165
}
186166

187-
impl fmt::Debug for Condvar {
188-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189-
write!(f, "sys::Condvar {:?}", self.item.get())
167+
impl ObjectInit<k_condvar> for ZephyrObject<k_condvar> {
168+
fn init(item: *mut k_condvar) {
169+
// SAFETY: ZephyrObject handles initialization and move prevention.
170+
unsafe {
171+
k_condvar_init(item);
172+
}
190173
}
191174
}
192175

193-
impl Wrapped for StaticCondvar {
194-
type T = Condvar;
195-
196-
/// Condvar initializers take no argument.
197-
type I = ();
198-
199-
fn get_wrapped(&self, _arg: Self::I) -> Condvar {
200-
let ptr = self.value.get();
201-
unsafe {
202-
k_condvar_init(ptr);
203-
}
204-
Condvar {
205-
item: Fixed::Static(ptr),
206-
}
176+
impl fmt::Debug for Condvar {
177+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178+
// SAFETY: Just getting the address to print.
179+
write!(f, "sys::Condvar {:?}", unsafe { self.item.get() })
207180
}
208181
}

zephyr/src/work.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ use zephyr_sys::{
194194
};
195195

196196
use crate::{
197-
error::to_result_void, kio::ContextExt, object::Fixed, simpletls::StaticTls, sync::Arc,
197+
error::to_result_void, kio::ContextExt, object::Fixed, simpletls::SimpleTls, sync::{Arc, Mutex},
198198
sys::thread::ThreadStack, time::Timeout,
199199
};
200200

@@ -275,7 +275,7 @@ impl WorkQueueBuilder {
275275
// SAFETY: This associates the workqueue with the thread ID that runs it. The thread is
276276
// a pointer into this work item, which will not move, because of the Fixed.
277277
let this = &mut *item.get();
278-
WORK_QUEUES.insert(&this.thread, WorkQueueRef(item.get()));
278+
WORK_QUEUES.lock().unwrap().insert(&this.thread, WorkQueueRef(item.get()));
279279

280280
// SAFETY: Start work queue thread. The main issue here is that the work queue cannot
281281
// be deallocated once the thread has started. We enforce this by making Drop panic.
@@ -340,7 +340,7 @@ impl Drop for WorkQueue {
340340
///
341341
/// This is a little bit messy as we don't have a lazy mechanism, so we have to handle this a bit
342342
/// manually right now.
343-
static WORK_QUEUES: StaticTls<WorkQueueRef> = StaticTls::new();
343+
static WORK_QUEUES: Mutex<SimpleTls<WorkQueueRef>> = Mutex::new(SimpleTls::new());
344344

345345
/// For the queue mapping, we need a simple wrapper around the underlying pointer, one that doesn't
346346
/// implement stop.
@@ -353,7 +353,7 @@ unsafe impl Sync for WorkQueueRef {}
353353

354354
/// Retrieve the current work queue, if we are running within one.
355355
pub fn get_current_workq() -> Option<*mut k_work_q> {
356-
WORK_QUEUES.get().map(|wq| wq.0)
356+
WORK_QUEUES.lock().unwrap().get().map(|wq| wq.0)
357357
}
358358

359359
/// A Rust wrapper for `k_poll_signal`.

0 commit comments

Comments
 (0)