Skip to content

Commit a4f2337

Browse files
committed
zephyr-core: mutex: own the data rather than forcing a reference
The original design worked when both the mutex were static or the lifetime was known (which doesn't really work if you're sharing across threads). To share dynamically-allocated data, we need an Arc. So the mutex needs to either own an Arc, or own the data directly and be wrapped in an Arc. Forcing data to be a reference is incompatible with both. Retain the ability to clone the mutex directly if data is a reference (most likely static), so we don't have to put two static references in an Arc on the heap just to be able to share them. The new mutex struct will keep the lifetime constaints of the original.
1 parent 4409e10 commit a4f2337

File tree

2 files changed

+30
-18
lines changed

2 files changed

+30
-18
lines changed

rust/zephyr-core/src/mutex.rs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,57 +70,67 @@ impl<'a> RawMutex for &'a KMutex {
7070
/// Using this is safe, but creating it is not. Creator must ensure it is not
7171
/// possible to get a reference to the data elsewhere. Lifetime bounds ensure the
7272
/// mutex kobject lives at least as long as the data it protects.
73-
#[derive(Copy)]
74-
pub struct Mutex<'m: 'd, 'd, T> {
73+
pub struct Mutex<'m, T> {
7574
mutex: &'m KMutex,
76-
data: &'d MutexData<T>,
75+
data: MutexData<T>,
7776
}
7877

79-
impl<'m: 'd, 'd, T> Mutex<'m, 'd, T> {
80-
pub unsafe fn new(mutex: &'m KMutex, data: &'d MutexData<T>) -> Self {
81-
Mutex { mutex, data }
78+
impl<'m, T> Mutex<'m, T> {
79+
pub unsafe fn new(mutex: &'m KMutex, data: T) -> Self {
80+
Mutex {
81+
mutex,
82+
data: MutexData::new(data),
83+
}
8284
}
8385

8486
pub unsafe fn kobj(&self) -> *mut libc::c_void {
8587
self.mutex as *const _ as *mut _
8688
}
8789

88-
pub fn lock<C: MutexSyscalls>(&self) -> MutexGuard<'d, T, C> {
90+
pub fn lock<'a, C: MutexSyscalls>(&'a self) -> MutexGuard<'a, T, C> {
8991
unsafe {
9092
self.mutex.lock::<C>();
9193
}
92-
MutexGuard(self.clone(), PhantomData)
94+
MutexGuard {
95+
mutex: self,
96+
_syscalls: PhantomData,
97+
}
9398
}
9499
}
95100

96-
impl<'m: 'd, 'd, T> Clone for Mutex<'m, 'd, T> {
101+
/// Allow cloning a mutex where the data is a reference. This allows multiple references to static
102+
/// data with a static lock without wrapping those references in another Arc layer.
103+
impl<'m, 'd, T> Clone for Mutex<'m, &'d T> {
97104
fn clone(&self) -> Self {
98105
Mutex {
99106
mutex: self.mutex,
100-
data: self.data,
107+
data: unsafe { MutexData::new(&*self.data.0.get()) },
101108
}
102109
}
103110
}
104111

105-
pub struct MutexGuard<'a, T, C: MutexSyscalls>(Mutex<'a, 'a, T>, PhantomData<C>);
112+
pub struct MutexGuard<'a, T: 'a, C: MutexSyscalls> {
113+
mutex: &'a Mutex<'a, T>,
114+
_syscalls: PhantomData<C>,
115+
}
106116

107-
impl<'a, T, C: MutexSyscalls> Drop for MutexGuard<'a, T, C> {
117+
impl<'a, T: 'a, C: MutexSyscalls> Drop for MutexGuard<'a, T, C> {
108118
fn drop(&mut self) {
109-
unsafe { self.0.mutex.unlock::<C>() }
119+
unsafe { self.mutex.mutex.unlock::<C>() }
110120
}
111121
}
112122

113-
impl<'a, T, C: MutexSyscalls> Deref for MutexGuard<'a, T, C> {
123+
impl<'a, T: 'a, C: MutexSyscalls> Deref for MutexGuard<'a, T, C> {
114124
type Target = T;
115125

116126
fn deref(&self) -> &T {
117-
unsafe { &*self.0.data.0.get() }
127+
unsafe { &*self.mutex.data.0.get() }
118128
}
119129
}
120130

121-
impl<'a, T, C: MutexSyscalls> DerefMut for MutexGuard<'a, T, C> {
131+
impl<'a, T: 'a, C: MutexSyscalls> DerefMut for MutexGuard<'a, T, C> {
122132
fn deref_mut(&mut self) -> &mut T {
123-
unsafe { &mut *self.0.data.0.get() }
133+
unsafe { &mut *self.mutex.data.0.get() }
124134
}
125135
}
126136

samples/rust-app/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ zephyr_macros::k_mutex_define!(MUTEX);
2424
zephyr_macros::k_sem_define!(TLS_SEM, 0, 1);
2525

2626
fn mutex_test() {
27-
let data = MutexData::new(1u32);
27+
let data = 1u32;
2828

2929
// Bind the static mutex to our local data. This would make more sense if
3030
// the data were static, but that requires app mem regions for user mode.
3131
let mutex = unsafe { Mutex::new(&MUTEX, &data) };
3232

33+
// Should allow cloning directly if the data is a reference.
34+
let _other_mutex = mutex.clone();
3335
zephyr::any::k_str_out("Locking\n");
3436
let _val = mutex.lock::<zephyr::context::Any>();
3537
zephyr::any::k_str_out("Unlocking\n");

0 commit comments

Comments
 (0)