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