DragonOS/kernel/src/libs/lockref.rs
YJwu2023 78bf93f02f
pci重构+pcie支持 (#235)
* pci重构+pcie支持

* pci重构测试完成

* 修正makefile的问题

* 小修改

* 修改函数名字
2023-04-09 12:30:02 +08:00

351 lines
11 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#![allow(dead_code)]
use super::spinlock::RawSpinlock;
use crate::{arch::asm::cmpxchg::try_cmpxchg_q, syscall::SystemError};
use core::{fmt::Debug, intrinsics::size_of};
#[cfg(target_arch = "x86_64")]
/// 由于需要cmpxchg所以整个lockref按照8字节对齐
#[repr(align(8))]
#[derive(Debug)]
pub struct LockRef {
pub lock: RawSpinlock,
pub count: i32,
}
/// 除了x86_64以外的架构不使用cmpxchg进行优化
#[cfg(not(target_arch = "x86_64"))]
pub struct LockRef {
lock: RawSpinlock,
count: i32,
}
enum CmpxchgMode {
Increase,
IncreaseNotZero,
IncreaseNotDead,
Decrease,
DecreaseReturn,
DecreaseNotZero,
DecreaseOrLockNotZero,
}
impl LockRef {
pub const INIT: LockRef = LockRef {
lock: RawSpinlock::INIT,
count: 0,
};
pub fn new() -> LockRef {
assert_eq!(size_of::<LockRef>(), 8);
return LockRef::INIT;
}
/// @brief 为X86架构实现cmpxchg循环以支持无锁操作。
///
/// @return 操作成功返回Ok(new.count)
/// @return 操作失败,原因:超时 => 返回Err(SystemError::ETIMEDOUT)
/// @return 操作失败,原因:不满足规则 => 返回Err(SystemError::E2BIG)
#[cfg(target_arch = "x86_64")]
#[inline]
fn cmpxchg_loop(&mut self, mode: CmpxchgMode) -> Result<i32, i32> {
use core::ptr::read_volatile;
use crate::arch::cpu::cpu_relax;
let mut old: LockRef = LockRef::INIT;
old.count = unsafe { read_volatile(&self.count) };
for _ in 0..100 {
if !old.lock.is_locked() {
let mut new = LockRef::INIT;
unsafe {
*(&mut new as *mut LockRef as *mut usize as *mut u64) =
read_volatile(&mut old as *mut LockRef as *mut usize as *mut u64);
new.lock.set_value(false);
}
// 根据不同情况,执行不同代码
match mode {
CmpxchgMode::Increase => {
new.count += 1;
}
CmpxchgMode::IncreaseNotZero => {
// 操作失败
if old.count <= 0 {
return Err(1);
}
new.count += 1;
}
CmpxchgMode::IncreaseNotDead => {
if old.count < 0 {
return Err(1);
}
new.count += 1;
}
CmpxchgMode::Decrease | CmpxchgMode::DecreaseReturn => {
if old.count <= 0 {
return Err(1);
}
new.count -= 1;
}
CmpxchgMode::DecreaseNotZero | CmpxchgMode::DecreaseOrLockNotZero => {
if old.count <= 1 {
return Err(1);
}
new.count -= 1;
}
}
if unsafe {
try_cmpxchg_q(
self as *mut LockRef as *mut usize as *mut u64,
&mut old as *mut LockRef as *mut usize as *mut u64,
&mut new as *mut LockRef as *mut usize as *mut u64,
)
} {
// 无锁操作成功,返回新的值
return Ok(new.count);
}
cpu_relax();
}
}
return Err(SystemError::ETIMEDOUT.to_posix_errno());
}
/// @brief 对于不支持无锁lockref的架构直接返回Err(SystemError::ENOTSUP),表示不支持
#[cfg(not(target_arch = "x86_64"))]
#[inline]
fn cmpxchg_loop(&mut self, mode: CmpxchgMode) -> Result<i32, i32> {
use crate::include::bindings::bindings::ENOTSUP;
return Err(SystemError::ENOTSUP.to_posix_errno());
}
/// @brief 原子的将引用计数加1
pub fn inc(&mut self) {
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::Increase);
if cmpxchg_result.is_ok() {
return;
}
self.lock.lock();
self.count += 1;
self.lock.unlock();
}
/**
* @brief 原子地将引用计数加1.如果原来的count≤0则操作失败。
*
* @return Ok(self.count) 操作成功
* @return Err(SystemError::EPERM) 操作失败
*/
pub fn inc_not_zero(&mut self) -> Result<i32, SystemError> {
{
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::IncreaseNotZero);
if cmpxchg_result.is_ok() {
return Ok(cmpxchg_result.unwrap());
} else if cmpxchg_result.unwrap_err() == 1 {
// 不满足not zero 的条件
return Err(SystemError::EPERM);
}
}
let mut retval = Err(SystemError::EPERM);
self.lock.lock();
if self.count > 0 {
self.count += 1;
retval = Ok(self.count);
}
self.lock.unlock();
return retval;
}
/**
* @brief 引用计数自增1。除非该lockref已经被标记为死亡
*
* @return Ok(self.count) 操作成功
* @return Err(SystemError::EPERM) 操作失败lockref已死亡
*/
pub fn inc_not_dead(&mut self) -> Result<i32, SystemError> {
{
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::IncreaseNotDead);
if cmpxchg_result.is_ok() {
return Ok(cmpxchg_result.unwrap());
} else if cmpxchg_result.unwrap_err() == 1 {
return Err(SystemError::EPERM);
}
}
// 快捷路径操作失败,尝试加锁
let mut retval = Err(SystemError::EPERM);
self.lock.lock();
if self.count >= 0 {
self.count += 1;
retval = Ok(self.count);
}
self.lock.unlock();
return retval;
}
/**
* @brief 原子地将引用计数-1。如果已处于count≤0的状态则返回SystemError::EPERM
*
* 本函数与lockref_dec_return()的区别在于当在cmpxchg()中检测到count<=0或已加锁本函数会再次尝试通过加锁来执行操作
* 而后者会直接返回错误
*
* @return Ok(self.count) 操作成功,返回新的引用变量值
* @return Err(SystemError::EPERM) 操作失败,lockref处于count≤0的状态
*/
pub fn dec(&mut self) -> Result<i32, SystemError> {
{
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::Decrease);
if cmpxchg_result.is_ok() {
return Ok(cmpxchg_result.unwrap());
}
}
let retval: Result<i32, SystemError>;
self.lock.lock();
if self.count > 0 {
self.count -= 1;
retval = Ok(self.count);
} else {
retval = Err(SystemError::EPERM);
}
self.lock.unlock();
return retval;
}
/**
* @brief 原子地将引用计数减1。如果处于已加锁或count≤0的状态则返回SystemError::EPERM
* 若当前处理器架构不支持cmpxchg则退化为self.dec()
*
* 本函数与lockref_dec()的区别在于当在cmpxchg()中检测到count<=0或已加锁本函数会直接返回错误
* 而后者会再次尝试通过加锁来执行操作
*
* @return Ok(self.count) 操作成功,返回新的引用变量值
* @return Err(SystemError::EPERM) 操作失败lockref处于已加锁或count≤0的状态
*/
pub fn dec_return(&mut self) -> Result<i32, SystemError> {
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseReturn);
if cmpxchg_result.is_ok() {
return Ok(cmpxchg_result.unwrap());
} else if *cmpxchg_result.as_ref().unwrap_err() == 1 {
return Err(SystemError::EPERM);
}
// 由于cmpxchg超时操作失败
if *cmpxchg_result.as_ref().unwrap_err() != SystemError::ENOTSUP.to_posix_errno() {
return Err(SystemError::EFAULT);
}
// 能走到这里代表架构当前不支持cmpxchg
// 退化为直接dec加锁
return self.dec();
}
/**
* @brief 原子地将引用计数减1。若当前的引用计数≤1则操作失败
*
* 该函数与lockref_dec_or_lock_not_zero()的区别在于当cmpxchg()时发现old.count≤1时该函数会直接返回Err(SystemError::EPERM)
* 而后者在这种情况下,会尝试加锁来进行操作。
*
* @return Ok(self.count) 成功将引用计数减1
* @return Err(SystemError::EPERM) 如果当前的引用计数≤1操作失败
*/
pub fn dec_not_zero(&mut self) -> Result<i32, SystemError> {
{
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseNotZero);
if cmpxchg_result.is_ok() {
return Ok(cmpxchg_result.unwrap());
} else if cmpxchg_result.unwrap_err() == 1 {
return Err(SystemError::EPERM);
}
}
let retval: Result<i32, SystemError>;
self.lock.lock();
if self.count > 1 {
self.count -= 1;
retval = Ok(self.count);
} else {
retval = Err(SystemError::EPERM);
}
self.lock.unlock();
return retval;
}
/**
* @brief 原子地将引用计数减1。若当前的引用计数≤1则操作失败
*
* 该函数与lockref_dec_not_zero()的区别在于当cmpxchg()时发现old.count≤1时该函数会尝试加锁来进行操作。
* 而后者在这种情况下会直接返回Err(SystemError::EPERM).
*
* @return Ok(self.count) 成功将引用计数减1
* @return Err(SystemError::EPERM) 如果当前的引用计数≤1操作失败
*/
pub fn dec_or_lock_not_zero(&mut self) -> Result<i32, SystemError> {
{
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseOrLockNotZero);
if cmpxchg_result.is_ok() {
return Ok(cmpxchg_result.unwrap());
}
}
let retval: Result<i32, SystemError>;
self.lock.lock();
if self.count > 1 {
self.count -= 1;
retval = Ok(self.count);
} else {
retval = Err(SystemError::EPERM);
}
self.lock.unlock();
return retval;
}
/**
* @brief 原子地将lockref变量标记为已经死亡将count设置为负值
*/
pub fn mark_dead(&mut self) {
self.lock.lock();
self.count = -128;
self.lock.unlock();
}
}
/*
* 您可以使用以下代码测试lockref
let mut lockref = LockRef::new();
kdebug!("lockref={:?}", lockref);
lockref.inc();
assert_eq!(lockref.count, 1);
kdebug!("lockref={:?}", lockref);
assert!(lockref.dec().is_ok());
assert_eq!(lockref.count, 0);
assert!(lockref.dec().is_err());
assert_eq!(lockref.count, 0);
lockref.inc();
assert_eq!(lockref.count, 1);
assert!(lockref.dec_not_zero().is_err());
lockref.inc();
assert_eq!(lockref.count, 2);
assert!(lockref.dec_not_zero().is_ok());
lockref.mark_dead();
assert!(lockref.count < 0);
assert!(lockref.inc_not_dead().is_err());
kdebug!("lockref={:?}", lockref);
*/