1 #![allow(dead_code)]
2 use super::spinlock::RawSpinlock;
3 use crate::{
4     arch::asm::cmpxchg::try_cmpxchg_q,
5     include::bindings::bindings::{ENOTSUP, ETIMEDOUT},
6 };
7 use core::{fmt::Debug, intrinsics::size_of};
8 
9 #[cfg(target_arch = "x86_64")]
10 /// 由于需要cmpxchg,所以整个lockref按照8字节对齐
11 #[repr(align(8))]
12 #[derive(Debug)]
13 pub struct LockRef {
14     pub lock: RawSpinlock,
15     pub count: i32,
16 }
17 
18 /// 除了x86_64以外的架构,不使用cmpxchg进行优化
19 #[cfg(not(target_arch = "x86_64"))]
20 pub struct LockRef {
21     lock: RawSpinlock,
22     count: i32,
23 }
24 
25 enum CmpxchgMode {
26     Increase,
27     IncreaseNotZero,
28     IncreaseNotDead,
29     Decrease,
30     DecreaseReturn,
31     DecreaseNotZero,
32     DecreaseOrLockNotZero,
33 }
34 
35 impl LockRef {
36     pub const INIT: LockRef = LockRef {
37         lock: RawSpinlock::INIT,
38         count: 0,
39     };
40 
new() -> LockRef41     pub fn new() -> LockRef {
42         assert_eq!(size_of::<LockRef>(), 8);
43         return LockRef::INIT;
44     }
45 
46     /// @brief 为X86架构实现cmpxchg循环,以支持无锁操作。
47     ///
48     /// @return 操作成功:返回Ok(new.count)
49     /// @return 操作失败,原因:超时 => 返回Err(-ETIMEDOUT)
50     /// @return 操作失败,原因:不满足规则 => 返回Err(1)
51     #[cfg(target_arch = "x86_64")]
52     #[inline]
cmpxchg_loop(&mut self, mode: CmpxchgMode) -> Result<i32, i32>53     fn cmpxchg_loop(&mut self, mode: CmpxchgMode) -> Result<i32, i32> {
54         use core::ptr::read_volatile;
55 
56         use crate::arch::cpu::cpu_relax;
57 
58         let mut old: LockRef = LockRef::INIT;
59         old.count = unsafe { read_volatile(&self.count) };
60         for _ in 0..100 {
61             if !old.lock.is_locked() {
62                 let mut new = LockRef::INIT;
63                 unsafe {
64                     *(&mut new as *mut LockRef as *mut usize as *mut u64) =
65                         read_volatile(&mut old as *mut LockRef as *mut usize as *mut u64);
66                     new.lock.set_value(false);
67                 }
68 
69                 // 根据不同情况,执行不同代码
70                 match mode {
71                     CmpxchgMode::Increase => {
72                         new.count += 1;
73                     }
74                     CmpxchgMode::IncreaseNotZero => {
75                         // 操作失败
76                         if old.count <= 0 {
77                             return Err(1);
78                         }
79                         new.count += 1;
80                     }
81 
82                     CmpxchgMode::IncreaseNotDead => {
83                         if old.count < 0 {
84                             return Err(1);
85                         }
86                         new.count += 1;
87                     }
88 
89                     CmpxchgMode::Decrease | CmpxchgMode::DecreaseReturn => {
90                         if old.count <= 0 {
91                             return Err(1);
92                         }
93                         new.count -= 1;
94                     }
95                     CmpxchgMode::DecreaseNotZero | CmpxchgMode::DecreaseOrLockNotZero => {
96                         if old.count <= 1 {
97                             return Err(1);
98                         }
99                         new.count -= 1;
100                     }
101                 }
102 
103                 if unsafe {
104                     try_cmpxchg_q(
105                         self as *mut LockRef as *mut usize as *mut u64,
106                         &mut old as *mut LockRef as *mut usize as *mut u64,
107                         &mut new as *mut LockRef as *mut usize as *mut u64,
108                     )
109                 } {
110                     // 无锁操作成功,返回新的值
111                     return Ok(new.count);
112                 }
113                 cpu_relax();
114             }
115         }
116 
117         return Err(-(ETIMEDOUT as i32));
118     }
119 
120     /// @brief 对于不支持无锁lockref的架构,直接返回Err(-ENOTSUP),表示不支持
121     #[cfg(not(target_arch = "x86_64"))]
122     #[inline]
cmpxchg_loop(&mut self, mode: CmpxchgMode) -> Result<i32, i32>123     fn cmpxchg_loop(&mut self, mode: CmpxchgMode) -> Result<i32, i32> {
124         use crate::include::bindings::bindings::ENOTSUP;
125 
126         return Err(-(ENOTSUP as i32));
127     }
128 
129     /// @brief 原子的将引用计数加1
inc(&mut self)130     pub fn inc(&mut self) {
131         let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::Increase);
132         if cmpxchg_result.is_ok() {
133             return;
134         }
135 
136         self.lock.lock();
137         self.count += 1;
138         self.lock.unlock();
139     }
140 
141     /**
142      * @brief 原子地将引用计数加1.如果原来的count≤0,则操作失败。
143      *
144      * @return Result<i32, i32>     操作成功=>Ok(self.count)
145      *                              操作失败=>Err(-1)
146      */
inc_not_zero(&mut self) -> Result<i32, i32>147     pub fn inc_not_zero(&mut self) -> Result<i32, i32> {
148         {
149             let cmpxchg_res = self.cmpxchg_loop(CmpxchgMode::IncreaseNotZero);
150             if cmpxchg_res.is_ok() {
151                 return cmpxchg_res;
152             } else if cmpxchg_res.unwrap_err() == 1 {
153                 // 不满足not zero 的条件
154                 return Err(-1);
155             }
156         }
157 
158         let mut retval = Err(-1);
159         self.lock.lock();
160 
161         if self.count > 0 {
162             self.count += 1;
163             retval = Ok(self.count);
164         }
165 
166         self.lock.unlock();
167         return retval;
168     }
169 
170     /**
171      * @brief 引用计数自增1。(除非该lockref已经被标记为死亡)
172      *
173      * @return Ok(self.count) 操作成功
174      * @return Err(-1) 操作失败,lockref已死亡
175      */
inc_not_dead(&mut self) -> Result<i32, i32>176     pub fn inc_not_dead(&mut self) -> Result<i32, i32> {
177         {
178             let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::IncreaseNotDead);
179             if cmpxchg_result.is_ok() {
180                 return cmpxchg_result;
181             } else if cmpxchg_result.unwrap_err() == 1 {
182                 return Err(-1);
183             }
184         }
185         // 快捷路径操作失败,尝试加锁
186         let mut retval = Err(-1);
187 
188         self.lock.lock();
189         if self.count >= 0 {
190             self.count += 1;
191             retval = Ok(self.count);
192         }
193         self.lock.unlock();
194         return retval;
195     }
196 
197     /**
198      * @brief 原子地将引用计数-1。如果已处于count≤0的状态,则返回Err(-1)
199      *
200      * 本函数与lockref_dec_return()的区别在于,当在cmpxchg()中检测到count<=0或已加锁,本函数会再次尝试通过加锁来执行操作
201      * 而后者会直接返回错误
202      *
203      * @return int 操作成功 => 返回新的引用变量值
204      *             操作失败lockref处于count≤0的状态 => 返回-1
205      */
dec(&mut self) -> Result<i32, i32>206     pub fn dec(&mut self) -> Result<i32, i32> {
207         {
208             let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::Decrease);
209             if cmpxchg_result.is_ok() {
210                 return cmpxchg_result;
211             }
212         }
213         let retval: Result<i32, i32>;
214         self.lock.lock();
215 
216         if self.count > 0 {
217             self.count -= 1;
218             retval = Ok(self.count);
219         } else {
220             retval = Err(-1);
221         }
222 
223         self.lock.unlock();
224 
225         return retval;
226     }
227 
228     /**
229      * @brief 原子地将引用计数减1。如果处于已加锁或count≤0的状态,则返回-1
230      *      若当前处理器架构不支持cmpxchg,则退化为self.dec()
231      *
232      * 本函数与lockref_dec()的区别在于,当在cmpxchg()中检测到count<=0或已加锁,本函数会直接返回错误
233      * 而后者会再次尝试通过加锁来执行操作
234      *
235      * @return int  操作成功 => 返回新的引用变量值
236      *              操作失败,lockref处于已加锁或count≤0的状态 => 返回-1
237      */
dec_return(&mut self) -> Result<i32, i32>238     pub fn dec_return(&mut self) -> Result<i32, i32> {
239         let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseReturn);
240         if cmpxchg_result.is_ok() {
241             return cmpxchg_result;
242         } else if cmpxchg_result.unwrap_err() == 1 {
243             return Err(-1);
244         }
245 
246         // 由于cmpxchg超时,操作失败
247         if cmpxchg_result.unwrap_err() != -(ENOTSUP as i32) {
248             return Err(-1);
249         }
250 
251         // 能走到这里,代表架构当前不支持cmpxchg
252         // 退化为直接dec,加锁
253         return self.dec();
254     }
255 
256     /**
257      * @brief 原子地将引用计数减1。若当前的引用计数≤1,则操作失败
258      *
259      * 该函数与lockref_dec_or_lock_not_zero()的区别在于,当cmpxchg()时发现old.count≤1时,该函数会直接返回Err(-1)
260      * 而后者在这种情况下,会尝试加锁来进行操作。
261      *
262      * @return Ok(self.count) 成功将引用计数减1
263      * @return Err(-1) 如果当前的引用计数≤1,操作失败
264      */
dec_not_zero(&mut self) -> Result<i32, i32>265     pub fn dec_not_zero(&mut self) -> Result<i32, i32> {
266         {
267             let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseNotZero);
268             if cmpxchg_result.is_ok() {
269                 return cmpxchg_result;
270             } else if cmpxchg_result.unwrap_err() == 1 {
271                 return Err(-1);
272             }
273         }
274 
275         let retval: Result<i32, i32>;
276         self.lock.lock();
277         if self.count > 1 {
278             self.count -= 1;
279             retval = Ok(self.count);
280         } else {
281             retval = Err(-1);
282         }
283         self.lock.unlock();
284         return retval;
285     }
286 
287     /**
288      * @brief 原子地将引用计数减1。若当前的引用计数≤1,则操作失败
289      *
290      * 该函数与lockref_dec_not_zero()的区别在于,当cmpxchg()时发现old.count≤1时,该函数会尝试加锁来进行操作。
291      * 而后者在这种情况下,会直接返回Err(-1).
292      *
293      * @return Ok(self.count) 成功将引用计数减1
294      * @return Err(-1) 如果当前的引用计数≤1,操作失败
295      */
dec_or_lock_not_zero(&mut self) -> Result<i32, i32>296     pub fn dec_or_lock_not_zero(&mut self) -> Result<i32, i32> {
297         {
298             let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseOrLockNotZero);
299             if cmpxchg_result.is_ok() {
300                 return cmpxchg_result;
301             }
302         }
303 
304         let retval: Result<i32, i32>;
305         self.lock.lock();
306         if self.count > 1 {
307             self.count -= 1;
308             retval = Ok(self.count);
309         } else {
310             retval = Err(-1);
311         }
312         self.lock.unlock();
313         return retval;
314     }
315 
316     /**
317      * @brief 原子地将lockref变量标记为已经死亡(将count设置为负值)
318      */
mark_dead(&mut self)319     pub fn mark_dead(&mut self) {
320         self.lock.lock();
321         self.count = -128;
322         self.lock.unlock();
323     }
324 }
325 
326 /*
327 * 您可以使用以下代码测试lockref
328 
329    let mut lockref = LockRef::new();
330    kdebug!("lockref={:?}", lockref);
331    lockref.inc();
332    assert_eq!(lockref.count, 1);
333    kdebug!("lockref={:?}", lockref);
334    assert!(lockref.dec().is_ok());
335    assert_eq!(lockref.count, 0);
336 
337    assert!(lockref.dec().is_err());
338    assert_eq!(lockref.count, 0);
339 
340    lockref.inc();
341    assert_eq!(lockref.count, 1);
342 
343    assert!(lockref.dec_not_zero().is_err());
344 
345    lockref.inc();
346    assert_eq!(lockref.count, 2);
347 
348    assert!(lockref.dec_not_zero().is_ok());
349 
350    lockref.mark_dead();
351    assert!(lockref.count < 0);
352 
353    assert!(lockref.inc_not_dead().is_err());
354    kdebug!("lockref={:?}", lockref);
355 */
356