DragonOS/kernel/src/libs/lockref.c
LoGin 4fda81ce81
使得DragonOS kernel 能为riscv64编译通过(尚未能启动) (#457)
* 使得DragonOS kernel 能为riscv64编译通过(尚未能启动)

* 修正了系统调用号声明不正确的问题,同时添加了编译配置文档
2023-11-25 12:07:39 +08:00

249 lines
7.7 KiB
C
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.

#include <arch/arch.h>
#if ARCH(I386) || ARCH(X86_64)
#include <common/lockref.h>
#include <common/compiler.h>
#ifdef __LOCKREF_ENABLE_CMPXCHG__
#include <asm/cmpxchg.h>
#define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \
{ \
int retry = 100; \
struct lockref old; \
BUILD_BUG_ON(sizeof(old) != sizeof(uint64_t)); \
old.lock_count = READ_ONCE(__lock_ref->lock_count); \
while (likely(!spin_is_locked(&old.lock))) \
{ \
struct lockref new = old; \
CODE; \
if (likely(arch_try_cmpxchg(&__lock_ref->lock_count, &old.lock_count, new.lock_count))) \
{ \
SUCCESS; \
} \
if (!--retry) \
break; \
pause(); \
} \
}
#else
#define CMPXCHG_LOOP(__lock_ref, CODE, SUCCESS) \
do \
{ \
} while (0)
#endif
/**
* @brief 原子的将引用计数加1
*
* @param lock_ref 指向要被操作的lockref变量的指针
*/
void lockref_inc(struct lockref *lock_ref)
{
// 先尝试使用cmpxchg进行无锁操作若成功则返回
CMPXCHG_LOOP(lock_ref, ++new.count;, return;);
// 无锁操作超时,或当前是上锁的状态,则退化为有锁操作
spin_lock(&lock_ref->lock);
++lock_ref->count;
spin_unlock(&lock_ref->lock);
}
/**
* @brief 原子地将引用计数加1.如果原来的count≤0则操作失败。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return bool 操作成功=>true
* 操作失败=>false
*/
bool lockref_inc_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 0)
return false;
++new.count;
},
{ return true; })
bool retval;
spin_lock(&lock_ref->lock);
retval = false;
if (lock_ref->count > 0)
{
++lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @brief 原子地减少引用计数。如果已处于count≤0的状态则返回-1
*
* 本函数与lockref_dec_return()的区别在于当在cmpxchg()中检测到count<=0或已加锁本函数会再次尝试通过加锁来执行操作
* 而后者会直接返回错误
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功 => 返回新的引用变量值
* lockref处于count≤0的状态 => 返回-1
*/
int lockref_dec(struct lockref *lock_ref)
{
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 0)
break;
--new.count;
},
{ return new.count; })
// 如果xchg时处于已加锁的状态或者检测到old.count <= 0则采取加锁处理
int retval = -1;
spin_lock(&lock_ref->lock);
if (lock_ref->count > 0)
{
--lock_ref->count;
retval = lock_ref->count;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @brief 原子地减少引用计数。如果处于已加锁或count≤0的状态则返回-1
*
* 本函数与lockref_dec()的区别在于当在cmpxchg()中检测到count<=0或已加锁本函数会直接返回错误
* 而后者会再次尝试通过加锁来执行操作
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return int 操作成功 => 返回新的引用变量值
* lockref处于已加锁或count≤0的状态 => 返回-1
*/
int lockref_dec_return(struct lockref *lock_ref)
{
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 0)
return -1;
--new.count;
},
{ return new.count; })
return -1;
}
/**
* @brief 原子地减少引用计数。若当前的引用计数≤1则操作失败
*
* 该函数与lockref_dec_or_lock_not_zero()的区别在于当cmpxchg()时发现old.count≤1时该函数会直接返回false.
* 而后者在这种情况下,会尝试加锁来进行操作。
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 成功将引用计数减1
* @return false 如果当前的引用计数≤1操作失败
*/
bool lockref_dec_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 1)
return false;
--new.count;
},
{ return true; })
bool retval = false;
spin_lock(&lock_ref->lock);
if (lock_ref->count > 1)
{
--lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @brief 原子地减少引用计数。若当前的引用计数≤1则操作失败
*
* 该函数与lockref_dec_not_zero()的区别在于当cmpxchg()时发现old.count≤1时该函数会尝试加锁来进行操作。
* 而后者在这种情况下会直接返回false.
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 成功将引用计数减1
* @return false 如果当前的引用计数≤1操作失败
*/
bool lockref_dec_or_lock_not_zero(struct lockref *lock_ref)
{
CMPXCHG_LOOP(
lock_ref,
{
if (old.count <= 1)
break;
--new.count;
},
{ return true; });
bool retval = false;
spin_lock(&lock_ref->lock);
if (lock_ref->count > 1)
{
--lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
/**
* @brief 将lockref变量标记为已经死亡将count设置为负值
*
* @param lock_ref 指向要被操作的lockref变量的指针
*/
void lockref_mark_dead(struct lockref *lock_ref)
{
// 需要自旋锁先被加锁,若没有被加锁,则会抛出错误信息
assert_spin_locked(&lock_ref->lock);
lock_ref->count = -128;
}
/**
* @brief 自增引用计数。除非该lockref已经死亡
*
* @param lock_ref 指向要被操作的lockref变量的指针
* @return true 操作成功
* @return false 操作失败lockref已死亡
*/
bool lockref_inc_not_dead(struct lockref *lock_ref)
{
CMPXCHG_LOOP(
lock_ref,
{
if (old.count < 0)
return false;
++new.count;
},
{ return true; })
bool retval = false;
// 快捷路径操作失败,尝试加锁
spin_lock(&lock_ref->lock);
if (lock_ref->count >= 0)
{
++lock_ref->count;
retval = true;
}
spin_unlock(&lock_ref->lock);
return retval;
}
#endif