mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
新增rust版本的lockref (#135)
* new:Rust封装cpu_relax(),通过pause指令,让cpu休息一会儿。降低空转功耗 * new: Rust版本的lockref * Rust的RawSpinlock新增is_locked()和set_value()方法。 * lockref文档
This commit is contained in:
parent
2726f101b4
commit
61de2cdc3f
@ -3,8 +3,31 @@
|
||||
|
||||
  lockref是将自旋锁与引用计数变量融合在连续、对齐的8字节内的一种技术。
|
||||
|
||||
## lockref结构
|
||||
  目前,DragonOS中,通过C、Rust各实现了一个版本的lockref。请注意,二者不兼容。对于新的功能模块,请使用Rust版本的lockref。随着代码重构工作的进行,我们将会删除C版本的lockref。
|
||||
|
||||
## 1. lockref结构
|
||||
|
||||
### 1.1. Rust版本
|
||||
```rust
|
||||
/// 仅在x86_64架构下使用cmpxchg
|
||||
#[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,
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2. C版本
|
||||
```c
|
||||
struct lockref
|
||||
{
|
||||
@ -21,15 +44,138 @@ struct lockref
|
||||
};
|
||||
};
|
||||
```
|
||||
## 特性描述
|
||||
|
||||
## 2. 特性描述
|
||||
  由于在高负载的情况下,系统会频繁的执行“锁定-改变引用变量-解锁”的操作,这期间很可能出现spinlock和引用计数跨缓存行的情况,这将会大大降低性能。lockref通过强制对齐,尽可能的降低缓存行的占用数量,使得性能得到提升。
|
||||
|
||||
  并且,在x64体系结构下,还通过cmpxchg()指令,实现了无锁快速路径。不需要对自旋锁加锁即可更改引用计数的值,进一步提升性能。当快速路径不存在(对于未支持的体系结构)或者尝试超时后,将会退化成“锁定-改变引用变量-解锁”的操作。此时由于lockref强制对齐,只涉及到1个缓存行,因此性能比原先的spinlock+ref_count的模式要高。
|
||||
|
||||
## 关于cmpxchg_loop
|
||||
## 3. 关于cmpxchg_loop
|
||||
|
||||
  在改变引用计数时,cmpxchg先确保没有别的线程持有锁,然后改变引用计数,同时通过`lock cmpxchg`指令验证在更改发生时,没有其他线程持有锁,并且当前的目标lockref的值与old变量中存储的一致,从而将新值存储到目标lockref。这种无锁操作能极大的提升性能。如果不符合上述条件,在多次尝试后,将退化成传统的加锁方式来更改引用计数。
|
||||
|
||||
## 4. Rust版本的API
|
||||
|
||||
### 4.1. 引用计数自增
|
||||
|
||||
- `pub fn inc(&mut self)`
|
||||
- `pub fn inc_not_zero(&mut self) -> Result<i32, i32>`
|
||||
- `pub fn inc_not_dead(&mut self) -> Result<i32, i32>`
|
||||
|
||||
#### 4.1.1. inc
|
||||
|
||||
##### 说明
|
||||
|
||||
  原子的将引用计数加1。
|
||||
|
||||
##### 返回值
|
||||
|
||||
  无
|
||||
|
||||
#### 4.1.2. inc_not_zero
|
||||
|
||||
##### 说明
|
||||
|
||||
  原子地将引用计数加1.如果原来的count≤0,则操作失败。
|
||||
|
||||
##### 返回值
|
||||
|
||||
| 返回值 | 说明 |
|
||||
| :--- | :--- |
|
||||
| Ok(self.count) | 成功,返回新的引用计数 |
|
||||
| Err(-1) | 失败,返回-1 |
|
||||
|
||||
#### 4.1.3. inc_not_dead
|
||||
|
||||
##### 说明
|
||||
|
||||
  引用计数自增1。(除非该lockref已经被标记为死亡)
|
||||
|
||||
##### 返回值
|
||||
|
||||
| 返回值 | 说明 |
|
||||
| :--- | :--- |
|
||||
| Ok(self.count) | 成功,返回新的引用计数 |
|
||||
| Err(-1) | 失败,返回-1 |
|
||||
|
||||
### 4.2. 引用计数自减
|
||||
- `pub fn dec(&mut self) -> Result<i32, i32>`
|
||||
- `pub fn dec_return(&mut self) -> Result<i32, i32>`
|
||||
- `pub fn dec_not_zero(&mut self) -> Result<i32, i32>`
|
||||
- `pub fn dec_or_lock_not_zero(&mut self) -> Result<i32, i32>`
|
||||
|
||||
#### 4.2.1. dec
|
||||
|
||||
##### 说明
|
||||
|
||||
  原子地将引用计数-1。如果已处于count≤0的状态,则返回Err(-1)
|
||||
|
||||
  本函数与`lockref_dec_return()`的区别在于,当在`cmpxchg()`中检测到`count<=0`或已加锁,本函数会再次尝试通过加锁来执行操作,而`lockref_dec_return()`会直接返回错误
|
||||
|
||||
##### 返回值
|
||||
|
||||
| 返回值 | 说明 |
|
||||
| :--- | :--- |
|
||||
| Ok(self.count) | 成功,返回新的引用计数 |
|
||||
| Err(-1) | 失败,返回-1 |
|
||||
|
||||
#### 4.2.2. dec_return
|
||||
|
||||
  原子地将引用计数减1。如果处于已加锁或count≤0的状态,则返回-1
|
||||
|
||||
  本函数与`lockref_dec()`的区别在于,当在`cmpxchg()`中检测到`count<=0`或已加锁,本函数会直接返回错误,而`lockref_dec()`会再次尝试通过加锁来执行操作.
|
||||
|
||||
:::{note}
|
||||
若当前处理器架构不支持cmpxchg,则退化为`self.dec()`
|
||||
:::
|
||||
|
||||
##### 返回值
|
||||
|
||||
| 返回值 | 说明 |
|
||||
| :--- | :--- |
|
||||
| Ok(self.count) | 成功,返回新的引用计数 |
|
||||
| Err(-1) | 失败,返回-1 |
|
||||
|
||||
#### 4.2.3. dec_not_zero
|
||||
|
||||
##### 说明
|
||||
|
||||
  原子地将引用计数减1。若当前的引用计数≤1,则操作失败.
|
||||
|
||||
  该函数与`lockref_dec_or_lock_not_zero()`的区别在于,当`cmpxchg()`时发现`old.count≤1`时,该函数会直接返回`Err(-1)`,而`lockref_dec_or_lock_not_zero()`在这种情况下,会尝试加锁来进行操作。
|
||||
|
||||
##### 返回值
|
||||
|
||||
| 返回值 | 说明 |
|
||||
| :--- | :--- |
|
||||
| Ok(self.count) | 成功,返回新的引用计数 |
|
||||
| Err(-1) | 失败,返回-1 |
|
||||
|
||||
|
||||
#### 4.2.4. dec_or_lock_not_zero
|
||||
|
||||
##### 说明
|
||||
|
||||
  原子地将引用计数减1。若当前的引用计数≤1,则操作失败.
|
||||
|
||||
  该函数与`lockref_dec_not_zero()`的区别在于,当cmpxchg()时发现`old.count≤1`时,该函数会尝试加锁来进行操作,而`lockref_dec_not_zero()`在这种情况下,会直接返回`Err(-1)`.
|
||||
|
||||
##### 返回值
|
||||
|
||||
| 返回值 | 说明 |
|
||||
| :--- | :--- |
|
||||
| Ok(self.count) | 成功,返回新的引用计数 |
|
||||
| Err(-1) | 失败,返回-1 |
|
||||
|
||||
### 4.3. 其他
|
||||
- `pub fn mark_dead(&mut self)`
|
||||
|
||||
#### 4.3.1. mark_dead
|
||||
|
||||
##### 说明
|
||||
|
||||
  将引用计数原子地标记为死亡状态.
|
||||
|
||||
## 参考资料
|
||||
|
||||
  [Introducing lockrefs - LWN.net, Jonathan Corbet](https://lwn.net/Articles/565734/)
|
||||
|
7
kernel/src/arch/x86_64/asm/cmpxchg.c
Normal file
7
kernel/src/arch/x86_64/asm/cmpxchg.c
Normal file
@ -0,0 +1,7 @@
|
||||
#include <arch/x86_64/include/asm/cmpxchg.h>
|
||||
|
||||
bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr)
|
||||
{
|
||||
bool success = __raw_try_cmpxchg(ptr, old_ptr, *new_ptr, 8);
|
||||
return success;
|
||||
}
|
12
kernel/src/arch/x86_64/asm/cmpxchg.rs
Normal file
12
kernel/src/arch/x86_64/asm/cmpxchg.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// 该函数在cmpxchg.c中实现
|
||||
extern "C" {
|
||||
fn __try_cmpxchg_q(ptr: *mut u64, old_ptr: *mut u64, new_ptr: *mut u64) -> bool;
|
||||
}
|
||||
|
||||
/// @brief 封装lock cmpxchg指令
|
||||
/// 由于Rust实现这部分的内联汇编比较麻烦(实在想不出办法),因此使用C的实现。
|
||||
#[inline]
|
||||
pub unsafe fn try_cmpxchg_q(ptr: *mut u64, old_ptr: *mut u64, new_ptr: *mut u64) -> bool {
|
||||
let retval = __try_cmpxchg_q(ptr, old_ptr, new_ptr);
|
||||
return retval;
|
||||
}
|
@ -2,4 +2,5 @@ pub mod irqflags;
|
||||
#[macro_use]
|
||||
pub mod current;
|
||||
pub mod ptrace;
|
||||
pub mod bitops;
|
||||
pub mod bitops;
|
||||
pub mod cmpxchg;
|
@ -14,3 +14,10 @@ pub fn arch_current_apic_id() -> u8 {
|
||||
}
|
||||
return (cpuid_res >> 24) as u8;
|
||||
}
|
||||
|
||||
/// @brief 通过pause指令,让cpu休息一会儿。降低空转功耗
|
||||
pub fn cpu_relax() {
|
||||
unsafe {
|
||||
asm!("pause");
|
||||
}
|
||||
}
|
||||
|
@ -79,3 +79,5 @@ extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size fo
|
||||
|
||||
#define arch_try_cmpxchg(ptr, old_ptr, new_ptr) \
|
||||
__raw_try_cmpxchg((ptr), (old_ptr), (new_ptr), sizeof(*ptr))
|
||||
|
||||
bool __try_cmpxchg_q(uint64_t *ptr, uint64_t *old_ptr, uint64_t *new_ptr);
|
@ -29,8 +29,6 @@ mod sched;
|
||||
mod smp;
|
||||
mod time;
|
||||
|
||||
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use mm::allocator::KernelAllocator;
|
||||
@ -39,6 +37,7 @@ use mm::allocator::KernelAllocator;
|
||||
use crate::{
|
||||
arch::asm::current::current_pcb,
|
||||
include::bindings::bindings::{process_do_exit, BLACK, GREEN},
|
||||
libs::lockref::LockRef,
|
||||
};
|
||||
|
||||
// 声明全局的slab分配器
|
||||
@ -85,5 +84,6 @@ pub fn panic(info: &PanicInfo) -> ! {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_demo_func() -> i32 {
|
||||
printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
355
kernel/src/libs/lockref.rs
Normal file
355
kernel/src/libs/lockref.rs
Normal file
@ -0,0 +1,355 @@
|
||||
#![allow(dead_code)]
|
||||
use super::spinlock::RawSpinlock;
|
||||
use crate::{
|
||||
arch::asm::cmpxchg::try_cmpxchg_q,
|
||||
include::bindings::bindings::{ENOTSUP, ETIMEDOUT},
|
||||
};
|
||||
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(-ETIMEDOUT)
|
||||
/// @return 操作失败,原因:不满足规则 => 返回Err(1)
|
||||
#[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(-(ETIMEDOUT as i32));
|
||||
}
|
||||
|
||||
/// @brief 对于不支持无锁lockref的架构,直接返回Err(-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(-(ENOTSUP as i32));
|
||||
}
|
||||
|
||||
/// @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 Result<i32, i32> 操作成功=>Ok(self.count)
|
||||
* 操作失败=>Err(-1)
|
||||
*/
|
||||
pub fn inc_not_zero(&mut self) -> Result<i32, i32> {
|
||||
{
|
||||
let cmpxchg_res = self.cmpxchg_loop(CmpxchgMode::IncreaseNotZero);
|
||||
if cmpxchg_res.is_ok() {
|
||||
return cmpxchg_res;
|
||||
} else if cmpxchg_res.unwrap_err() == 1 {
|
||||
// 不满足not zero 的条件
|
||||
return Err(-1);
|
||||
}
|
||||
}
|
||||
|
||||
let mut retval = Err(-1);
|
||||
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(-1) 操作失败,lockref已死亡
|
||||
*/
|
||||
pub fn inc_not_dead(&mut self) -> Result<i32, i32> {
|
||||
{
|
||||
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::IncreaseNotDead);
|
||||
if cmpxchg_result.is_ok() {
|
||||
return cmpxchg_result;
|
||||
} else if cmpxchg_result.unwrap_err() == 1 {
|
||||
return Err(-1);
|
||||
}
|
||||
}
|
||||
// 快捷路径操作失败,尝试加锁
|
||||
let mut retval = Err(-1);
|
||||
|
||||
self.lock.lock();
|
||||
if self.count >= 0 {
|
||||
self.count += 1;
|
||||
retval = Ok(self.count);
|
||||
}
|
||||
self.lock.unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 原子地将引用计数-1。如果已处于count≤0的状态,则返回Err(-1)
|
||||
*
|
||||
* 本函数与lockref_dec_return()的区别在于,当在cmpxchg()中检测到count<=0或已加锁,本函数会再次尝试通过加锁来执行操作
|
||||
* 而后者会直接返回错误
|
||||
*
|
||||
* @return int 操作成功 => 返回新的引用变量值
|
||||
* 操作失败lockref处于count≤0的状态 => 返回-1
|
||||
*/
|
||||
pub fn dec(&mut self) -> Result<i32, i32> {
|
||||
{
|
||||
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::Decrease);
|
||||
if cmpxchg_result.is_ok() {
|
||||
return cmpxchg_result;
|
||||
}
|
||||
}
|
||||
let retval: Result<i32, i32>;
|
||||
self.lock.lock();
|
||||
|
||||
if self.count > 0 {
|
||||
self.count -= 1;
|
||||
retval = Ok(self.count);
|
||||
} else {
|
||||
retval = Err(-1);
|
||||
}
|
||||
|
||||
self.lock.unlock();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 原子地将引用计数减1。如果处于已加锁或count≤0的状态,则返回-1
|
||||
* 若当前处理器架构不支持cmpxchg,则退化为self.dec()
|
||||
*
|
||||
* 本函数与lockref_dec()的区别在于,当在cmpxchg()中检测到count<=0或已加锁,本函数会直接返回错误
|
||||
* 而后者会再次尝试通过加锁来执行操作
|
||||
*
|
||||
* @return int 操作成功 => 返回新的引用变量值
|
||||
* 操作失败,lockref处于已加锁或count≤0的状态 => 返回-1
|
||||
*/
|
||||
pub fn dec_return(&mut self) -> Result<i32, i32> {
|
||||
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseReturn);
|
||||
if cmpxchg_result.is_ok() {
|
||||
return cmpxchg_result;
|
||||
} else if cmpxchg_result.unwrap_err() == 1 {
|
||||
return Err(-1);
|
||||
}
|
||||
|
||||
// 由于cmpxchg超时,操作失败
|
||||
if cmpxchg_result.unwrap_err() != -(ENOTSUP as i32) {
|
||||
return Err(-1);
|
||||
}
|
||||
|
||||
// 能走到这里,代表架构当前不支持cmpxchg
|
||||
// 退化为直接dec,加锁
|
||||
return self.dec();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 原子地将引用计数减1。若当前的引用计数≤1,则操作失败
|
||||
*
|
||||
* 该函数与lockref_dec_or_lock_not_zero()的区别在于,当cmpxchg()时发现old.count≤1时,该函数会直接返回Err(-1)
|
||||
* 而后者在这种情况下,会尝试加锁来进行操作。
|
||||
*
|
||||
* @return Ok(self.count) 成功将引用计数减1
|
||||
* @return Err(-1) 如果当前的引用计数≤1,操作失败
|
||||
*/
|
||||
pub fn dec_not_zero(&mut self) -> Result<i32, i32> {
|
||||
{
|
||||
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseNotZero);
|
||||
if cmpxchg_result.is_ok() {
|
||||
return cmpxchg_result;
|
||||
} else if cmpxchg_result.unwrap_err() == 1 {
|
||||
return Err(-1);
|
||||
}
|
||||
}
|
||||
|
||||
let retval: Result<i32, i32>;
|
||||
self.lock.lock();
|
||||
if self.count > 1 {
|
||||
self.count -= 1;
|
||||
retval = Ok(self.count);
|
||||
} else {
|
||||
retval = Err(-1);
|
||||
}
|
||||
self.lock.unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 原子地将引用计数减1。若当前的引用计数≤1,则操作失败
|
||||
*
|
||||
* 该函数与lockref_dec_not_zero()的区别在于,当cmpxchg()时发现old.count≤1时,该函数会尝试加锁来进行操作。
|
||||
* 而后者在这种情况下,会直接返回Err(-1).
|
||||
*
|
||||
* @return Ok(self.count) 成功将引用计数减1
|
||||
* @return Err(-1) 如果当前的引用计数≤1,操作失败
|
||||
*/
|
||||
pub fn dec_or_lock_not_zero(&mut self) -> Result<i32, i32> {
|
||||
{
|
||||
let cmpxchg_result = self.cmpxchg_loop(CmpxchgMode::DecreaseOrLockNotZero);
|
||||
if cmpxchg_result.is_ok() {
|
||||
return cmpxchg_result;
|
||||
}
|
||||
}
|
||||
|
||||
let retval: Result<i32, i32>;
|
||||
self.lock.lock();
|
||||
if self.count > 1 {
|
||||
self.count -= 1;
|
||||
retval = Ok(self.count);
|
||||
} else {
|
||||
retval = Err(-1);
|
||||
}
|
||||
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);
|
||||
*/
|
@ -5,4 +5,5 @@ pub mod ffi_convert;
|
||||
pub mod refcount;
|
||||
pub mod atomic;
|
||||
pub mod wait_queue;
|
||||
pub mod list;
|
||||
pub mod list;
|
||||
pub mod lockref;
|
@ -57,6 +57,10 @@ pub fn spin_unlock_irq(lock: *mut spinlock_t) {
|
||||
sti();
|
||||
}
|
||||
|
||||
/// 原始的Spinlock(自旋锁)
|
||||
/// 请注意,这个自旋锁和C的不兼容。
|
||||
///
|
||||
/// @param self.0 这个AtomicBool的值为false时,表示没有被加锁。当它为true时,表示自旋锁已经被上锁。
|
||||
#[derive(Debug)]
|
||||
pub struct RawSpinlock(AtomicBool);
|
||||
|
||||
@ -107,6 +111,21 @@ impl RawSpinlock {
|
||||
sti();
|
||||
}
|
||||
|
||||
/// @brief 判断自旋锁是否被上锁
|
||||
///
|
||||
/// @return true 自旋锁被上锁
|
||||
/// @return false 自旋锁处于解锁状态
|
||||
pub fn is_locked(&self)->bool
|
||||
{
|
||||
return self.0.load(Ordering::Relaxed).into();
|
||||
}
|
||||
|
||||
/// @brief 强制设置自旋锁的状态
|
||||
/// 请注意,这样操作可能会带来未知的风险。因此它是unsafe的。(尽管从Rust语言本身来说,它是safe的)
|
||||
pub unsafe fn set_value(&mut self, value:bool){
|
||||
self.0.store(value, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
// todo: spin_lock_irqsave
|
||||
// todo: spin_unlock_irqrestore
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user