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