xref: /DragonOS/kernel/src/libs/spinlock.rs (revision 7a29d4fcbcd89a226289c7bf541c2c78623de3ad)
1 #![allow(dead_code)]
2 use core::cell::UnsafeCell;
3 use core::hint::spin_loop;
4 use core::mem::ManuallyDrop;
5 use core::ops::{Deref, DerefMut};
6 
7 use core::sync::atomic::{AtomicBool, Ordering};
8 
9 use crate::arch::CurrentIrqArch;
10 use crate::exception::{InterruptArch, IrqFlagsGuard};
11 use crate::process::ProcessManager;
12 use system_error::SystemError;
13 
14 /// 实现了守卫的SpinLock, 能够支持内部可变性
15 ///
16 #[derive(Debug)]
17 pub struct SpinLock<T> {
18     lock: AtomicBool,
19     /// 自旋锁保护的数据
20     data: UnsafeCell<T>,
21 }
22 
23 /// SpinLock的守卫
24 /// 该守卫没有构造器,并且其信息均为私有的。我们只能通过SpinLock的lock()方法获得一个守卫。
25 /// 因此我们可以认为,只要能够获得一个守卫,那么数据就在自旋锁的保护之下。
26 #[derive(Debug)]
27 pub struct SpinLockGuard<'a, T: 'a> {
28     lock: &'a SpinLock<T>,
29     data: *mut T,
30     irq_flag: Option<IrqFlagsGuard>,
31     flags: SpinLockGuardFlags,
32 }
33 
34 impl<'a, T: 'a> SpinLockGuard<'a, T> {
35     /// 泄露自旋锁的守卫,返回一个可变的引用
36     ///
37     ///  ## Safety
38     ///
39     /// 由于这样做可能导致守卫在另一个线程中被释放,从而导致pcb的preempt count不正确,
40     /// 因此必须小心的手动维护好preempt count。
41     ///
42     /// 并且,leak还可能导致锁的状态不正确。因此请仔细考虑是否真的需要使用这个函数。
43     #[inline]
44     pub unsafe fn leak(this: Self) -> &'a mut T {
45         // Use ManuallyDrop to avoid stacked-borrow invalidation
46         let this = ManuallyDrop::new(this);
47         // We know statically that only we are referencing data
48         unsafe { &mut *this.lock.data.get() }
49     }
50 
51     fn unlock_no_preempt(&self) {
52         unsafe {
53             self.lock.force_unlock();
54         }
55     }
56 }
57 
58 /// 向编译器保证,SpinLock在线程之间是安全的.
59 /// 其中要求类型T实现了Send这个Trait
60 unsafe impl<T> Sync for SpinLock<T> where T: Send {}
61 
62 impl<T> SpinLock<T> {
63     pub const fn new(value: T) -> Self {
64         return Self {
65             lock: AtomicBool::new(false),
66             data: UnsafeCell::new(value),
67         };
68     }
69 
70     #[inline(always)]
71     pub fn lock(&self) -> SpinLockGuard<T> {
72         loop {
73             let res = self.try_lock();
74             if res.is_ok() {
75                 return res.unwrap();
76             }
77             spin_loop();
78         }
79     }
80 
81     /// 加锁,但是不更改preempt count
82     #[inline(always)]
83     pub fn lock_no_preempt(&self) -> SpinLockGuard<T> {
84         loop {
85             if let Ok(guard) = self.try_lock_no_preempt() {
86                 return guard;
87             }
88             spin_loop();
89         }
90     }
91 
92     pub fn lock_irqsave(&self) -> SpinLockGuard<T> {
93         loop {
94             if let Ok(guard) = self.try_lock_irqsave() {
95                 return guard;
96             }
97             spin_loop();
98         }
99     }
100 
101     pub fn try_lock(&self) -> Result<SpinLockGuard<T>, SystemError> {
102         // 先增加自旋锁持有计数
103         ProcessManager::preempt_disable();
104 
105         if self.inner_try_lock() {
106             return Ok(SpinLockGuard {
107                 lock: self,
108                 data: unsafe { &mut *self.data.get() },
109                 irq_flag: None,
110                 flags: SpinLockGuardFlags::empty(),
111             });
112         }
113 
114         // 如果加锁失败恢复自旋锁持有计数
115         ProcessManager::preempt_enable();
116 
117         return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
118     }
119 
120     fn inner_try_lock(&self) -> bool {
121         let res = self
122             .lock
123             .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
124             .is_ok();
125         return res;
126     }
127 
128     pub fn try_lock_irqsave(&self) -> Result<SpinLockGuard<T>, SystemError> {
129         let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
130         ProcessManager::preempt_disable();
131         if self.inner_try_lock() {
132             return Ok(SpinLockGuard {
133                 lock: self,
134                 data: unsafe { &mut *self.data.get() },
135                 irq_flag: Some(irq_guard),
136                 flags: SpinLockGuardFlags::empty(),
137             });
138         }
139         ProcessManager::preempt_enable();
140         drop(irq_guard);
141         return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
142     }
143 
144     pub fn try_lock_no_preempt(&self) -> Result<SpinLockGuard<T>, SystemError> {
145         if self.inner_try_lock() {
146             return Ok(SpinLockGuard {
147                 lock: self,
148                 data: unsafe { &mut *self.data.get() },
149                 irq_flag: None,
150                 flags: SpinLockGuardFlags::NO_PREEMPT,
151             });
152         }
153         return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
154     }
155 
156     /// 强制解锁,并且不更改preempt count
157     ///
158     /// ## Safety
159     ///
160     /// 由于这样做可能导致preempt count不正确,因此必须小心的手动维护好preempt count。
161     /// 如非必要,请不要使用这个函数。
162     pub unsafe fn force_unlock(&self) {
163         self.lock.store(false, Ordering::SeqCst);
164     }
165 
166     fn unlock(&self) {
167         self.lock.store(false, Ordering::SeqCst);
168         ProcessManager::preempt_enable();
169     }
170 }
171 
172 /// 实现Deref trait,支持通过获取SpinLockGuard来获取临界区数据的不可变引用
173 impl<T> Deref for SpinLockGuard<'_, T> {
174     type Target = T;
175 
176     fn deref(&self) -> &Self::Target {
177         return unsafe { &*self.data };
178     }
179 }
180 
181 /// 实现DerefMut trait,支持通过获取SpinLockGuard来获取临界区数据的可变引用
182 impl<T> DerefMut for SpinLockGuard<'_, T> {
183     fn deref_mut(&mut self) -> &mut Self::Target {
184         return unsafe { &mut *self.data };
185     }
186 }
187 
188 /// @brief 为SpinLockGuard实现Drop方法,那么,一旦守卫的生命周期结束,就会自动释放自旋锁,避免了忘记放锁的情况
189 impl<T> Drop for SpinLockGuard<'_, T> {
190     fn drop(&mut self) {
191         if self.flags.contains(SpinLockGuardFlags::NO_PREEMPT) {
192             self.unlock_no_preempt();
193         } else {
194             self.lock.unlock();
195         }
196         // restore irq
197         self.irq_flag.take();
198     }
199 }
200 
201 bitflags! {
202     struct SpinLockGuardFlags: u8 {
203         /// 守卫是由“*no_preempt”方法获得的
204         const NO_PREEMPT = (1<<0);
205     }
206 }
207