• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2025 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 use core::{
16     cell::UnsafeCell,
17     ops::{Deref, DerefMut},
18 };
19 
20 use crate::scheduler::{SchedulerState, WaitQueue};
21 use crate::sync::spinlock::SpinLockGuard;
22 
23 pub struct SchedLockGuard<'lock, T> {
24     guard: SpinLockGuard<'lock, SchedulerState>,
25     inner: &'lock mut T,
26 }
27 
28 impl<'lock, T> SchedLockGuard<'lock, T> {
29     #[allow(dead_code)]
sched(&self) -> &SpinLockGuard<'lock, SchedulerState>30     pub fn sched(&self) -> &SpinLockGuard<'lock, SchedulerState> {
31         &self.guard
32     }
33 
34     #[allow(dead_code)]
sched_mut(&mut self) -> &mut SpinLockGuard<'lock, SchedulerState>35     pub fn sched_mut(&mut self) -> &mut SpinLockGuard<'lock, SchedulerState> {
36         &mut self.guard
37     }
38 
39     #[allow(dead_code)]
into_sched(self) -> SpinLockGuard<'lock, SchedulerState>40     pub fn into_sched(self) -> SpinLockGuard<'lock, SchedulerState> {
41         self.guard
42     }
43 }
44 
45 impl<T> Deref for SchedLockGuard<'_, T> {
46     type Target = T;
47 
deref(&self) -> &T48     fn deref(&self) -> &T {
49         self.inner
50     }
51 }
52 
53 impl<T> DerefMut for SchedLockGuard<'_, T> {
deref_mut(&mut self) -> &mut T54     fn deref_mut(&mut self) -> &mut T {
55         self.inner
56     }
57 }
58 
59 /// An owning lock that shares the global scheduler lock.
60 ///
61 /// A [`SchedLockGuard`] can be turned into a `SpinLockGuard<'lock, SchedulerState>`
62 /// so that it can be passed to `reschedule()`
63 ///
64 /// # Safety
65 /// Taking two different `SchedLock`s at the same time will deadlock as they
66 /// share the same underlying lock.
67 pub struct SchedLock<T> {
68     inner: UnsafeCell<T>,
69 }
70 unsafe impl<T> Sync for SchedLock<T> {}
71 unsafe impl<T> Send for SchedLock<T> {}
72 
73 impl<T> SchedLock<T> {
new(initial_value: T) -> Self74     pub const fn new(initial_value: T) -> Self {
75         Self {
76             inner: UnsafeCell::new(initial_value),
77         }
78     }
79 
80     #[allow(unused)]
try_lock(&self) -> Option<SchedLockGuard<'_, T>>81     pub fn try_lock(&self) -> Option<SchedLockGuard<'_, T>> {
82         // Safety: The lock guarantees
83         super::SCHEDULER_STATE
84             .try_lock()
85             .map(|guard| SchedLockGuard {
86                 inner: unsafe { &mut *self.inner.get() },
87                 guard,
88             })
89     }
90 
lock(&self) -> SchedLockGuard<'_, T>91     pub fn lock(&self) -> SchedLockGuard<'_, T> {
92         let guard = super::SCHEDULER_STATE.lock();
93         SchedLockGuard {
94             inner: unsafe { &mut *self.inner.get() },
95             guard,
96         }
97     }
98 }
99 
100 pub struct WaitQueueLockState<T> {
101     queue: WaitQueue,
102     inner: T,
103 }
104 
105 pub struct WaitQueueLock<T> {
106     state: SchedLock<WaitQueueLockState<T>>,
107 }
108 
109 impl<T> WaitQueueLock<T> {
new(initial_value: T) -> Self110     pub const fn new(initial_value: T) -> Self {
111         Self {
112             state: SchedLock::new(WaitQueueLockState {
113                 queue: WaitQueue::new(),
114                 inner: initial_value,
115             }),
116         }
117     }
118 
lock(&self) -> WaitQueueLockGuard<'_, T>119     pub fn lock(&self) -> WaitQueueLockGuard<'_, T> {
120         WaitQueueLockGuard {
121             inner: self.state.lock(),
122         }
123     }
124 }
125 
126 pub struct WaitQueueLockGuard<'lock, T> {
127     inner: SchedLockGuard<'lock, WaitQueueLockState<T>>,
128 }
129 
130 impl<'lock, T> WaitQueueLockGuard<'lock, T> {
131     #[allow(dead_code)]
sched(&self) -> &SpinLockGuard<'lock, SchedulerState>132     pub fn sched(&self) -> &SpinLockGuard<'lock, SchedulerState> {
133         &self.inner.guard
134     }
135 
136     #[allow(dead_code)]
sched_mut(&mut self) -> &mut SpinLockGuard<'lock, SchedulerState>137     pub fn sched_mut(&mut self) -> &mut SpinLockGuard<'lock, SchedulerState> {
138         &mut self.inner.guard
139     }
140 
141     #[allow(dead_code)]
into_sched(self) -> SpinLockGuard<'lock, SchedulerState>142     pub fn into_sched(self) -> SpinLockGuard<'lock, SchedulerState> {
143         self.inner.guard
144     }
145 
146     #[allow(dead_code)]
into_wait_queue(self) -> SchedLockGuard<'lock, WaitQueue>147     pub fn into_wait_queue(self) -> SchedLockGuard<'lock, WaitQueue> {
148         SchedLockGuard::<'lock, WaitQueue> {
149             guard: self.inner.guard,
150             inner: &mut self.inner.inner.queue,
151         }
152     }
153 }
154 
155 impl<T> Deref for WaitQueueLockGuard<'_, T> {
156     type Target = T;
157 
deref(&self) -> &T158     fn deref(&self) -> &T {
159         &self.inner.inner.inner
160     }
161 }
162 
163 impl<T> DerefMut for WaitQueueLockGuard<'_, T> {
deref_mut(&mut self) -> &mut T164     fn deref_mut(&mut self) -> &mut T {
165         &mut self.inner.inner.inner
166     }
167 }
168