mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-10 20:36:48 +00:00
Merge branch 'patch-devfs-unregister-device'
This commit is contained in:
commit
f3bd316578
81
kernel/arch/x86_64/asm/cmpxchg.h
Normal file
81
kernel/arch/x86_64/asm/cmpxchg.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <common/compiler.h>
|
||||||
|
#include <arch/x86_64/asm/asm.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 通过extern不存在的函数,来让编译器报错。以防止不符合要求的代码的产生。
|
||||||
|
*/
|
||||||
|
extern void __cmpxchg_wrong_size(void) __compiletime_error("Bad argument size for cmpxchg");
|
||||||
|
|
||||||
|
// 定义常量:操作符涉及到的字节数
|
||||||
|
#define __X86_CASE_B 1
|
||||||
|
#define __X86_CASE_W 2
|
||||||
|
#define __X86_CASE_L 4
|
||||||
|
#define __X86_CASE_Q 8
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief lock cmpxchg指令的包装。
|
||||||
|
* 将_ptr指向的值与old_ptr指向的值做比较,如果相等,则将_new指向的值,加载到_ptr指向的值中。
|
||||||
|
*/
|
||||||
|
#define __raw_try_cmpxchg(_ptr, _old_ptr, _new, size) \
|
||||||
|
({ \
|
||||||
|
bool is_success = false; \
|
||||||
|
typeof(_ptr) _old = (typeof(_ptr))(_old_ptr); \
|
||||||
|
typeof(*(_ptr)) __old = *_old; \
|
||||||
|
typeof(*(_ptr)) __new = (_new); \
|
||||||
|
switch (size) \
|
||||||
|
{ \
|
||||||
|
case __X86_CASE_B: \
|
||||||
|
{ \
|
||||||
|
volatile uint8_t *__ptr = (volatile uint8_t *)(_ptr); \
|
||||||
|
asm volatile("lock cmpxchgb %[new], %[ptr]\n\t" \
|
||||||
|
: CC_OUT(z)(is_success), \
|
||||||
|
[ptr] "+m"(*__ptr), \
|
||||||
|
[old] "+a"(__old) \
|
||||||
|
: [new] "q"(__new) \
|
||||||
|
: "memory"); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case __X86_CASE_W: \
|
||||||
|
{ \
|
||||||
|
volatile uint16_t *__ptr = (volatile uint16_t *)(_ptr); \
|
||||||
|
asm volatile("lock cmpxchgw %[new], %[ptr]\n\t" \
|
||||||
|
: CC_OUT(z)(is_success), \
|
||||||
|
[ptr] "+m"(*__ptr), \
|
||||||
|
[old] "+a"(__old) \
|
||||||
|
: [new] "q"(__new) \
|
||||||
|
: "memory"); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case __X86_CASE_L: \
|
||||||
|
{ \
|
||||||
|
volatile uint32_t *__ptr = (volatile uint32_t *)(_ptr); \
|
||||||
|
asm volatile("lock cmpxchgl %[new], %[ptr]\n\t" \
|
||||||
|
: CC_OUT(z)(is_success), \
|
||||||
|
[ptr] "+m"(*__ptr), \
|
||||||
|
[old] "+a"(__old) \
|
||||||
|
: [new] "q"(__new) \
|
||||||
|
: "memory"); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
case __X86_CASE_Q: \
|
||||||
|
{ \
|
||||||
|
volatile uint64_t *__ptr = (volatile uint64_t *)(_ptr); \
|
||||||
|
asm volatile("lock cmpxchgq %[new], %[ptr]\n\t" \
|
||||||
|
: CC_OUT(z)(is_success), \
|
||||||
|
[ptr] "+m"(*__ptr), \
|
||||||
|
[old] "+a"(__old) \
|
||||||
|
: [new] "q"(__new) \
|
||||||
|
: "memory"); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
default: \
|
||||||
|
__cmpxchg_wrong_size(); \
|
||||||
|
} \
|
||||||
|
if (unlikely(is_success == false)) \
|
||||||
|
*_old = __old; \
|
||||||
|
likely(is_success); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define arch_try_cmpxchg(ptr, old_ptr, new_ptr) \
|
||||||
|
__raw_try_cmpxchg((ptr), (old_ptr), (new_ptr), sizeof(*ptr))
|
104
kernel/common/lockref.h
Normal file
104
kernel/common/lockref.h
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common/sys/types.h>
|
||||||
|
#include <common/spinlock.h>
|
||||||
|
|
||||||
|
#if ARCH(X86_64)
|
||||||
|
// 仅在x64架构下启用cmpxchg
|
||||||
|
#define __LOCKREF_ENABLE_CMPXCHG__
|
||||||
|
#endif
|
||||||
|
struct lockref
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
#ifdef __LOCKREF_ENABLE_CMPXCHG__
|
||||||
|
aligned_u64 lock_count; // 通过该变量的声明,使得整个lockref按照8字节对齐
|
||||||
|
#endif
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
spinlock_t lock;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 原子的将引用计数加1
|
||||||
|
*
|
||||||
|
* @param lock_ref 要被操作的lockref变量
|
||||||
|
*/
|
||||||
|
void lockref_inc(struct lockref *lock_ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 原子地将引用计数加1.如果原来的count≤0,则操作失败。
|
||||||
|
*
|
||||||
|
* @param lock_ref 指向要被操作的lockref变量的指针
|
||||||
|
* @return int 操作成功=>true
|
||||||
|
* 操作失败=>false
|
||||||
|
*/
|
||||||
|
bool lockref_inc_not_zero(struct lockref *lock_ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 将lockref变量标记为已经死亡(将count设置为负值)
|
||||||
|
*
|
||||||
|
* @param lock_ref 指向要被操作的lockref变量的指针
|
||||||
|
*/
|
||||||
|
void lockref_mark_dead(struct lockref * lock_ref);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 自增引用计数。(除非该lockref已经死亡)
|
||||||
|
*
|
||||||
|
* @param lock_ref 指向要被操作的lockref变量的指针
|
||||||
|
* @return true 操作成功
|
||||||
|
* @return false 操作失败,lockref已死亡
|
||||||
|
*/
|
||||||
|
bool lockref_inc_not_dead(struct lockref *lock_ref);
|
@ -11,6 +11,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <common/glib.h>
|
#include <common/glib.h>
|
||||||
#include <process/preempt.h>
|
#include <process/preempt.h>
|
||||||
|
#include <debug/bug.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 定义自旋锁结构体
|
* @brief 定义自旋锁结构体
|
||||||
@ -19,8 +20,7 @@
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int8_t lock; // 1:unlocked 0:locked
|
int8_t lock; // 1:unlocked 0:locked
|
||||||
}spinlock_t;
|
} spinlock_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 自旋锁加锁
|
* @brief 自旋锁加锁
|
||||||
@ -167,3 +167,18 @@ long spin_trylock(spinlock_t *lock)
|
|||||||
spin_unlock(lock); \
|
spin_unlock(lock); \
|
||||||
local_irq_enable(); \
|
local_irq_enable(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 判断自旋锁是否已经加锁
|
||||||
|
*
|
||||||
|
* @param lock 待判断的自旋锁
|
||||||
|
* @return true 已经加锁
|
||||||
|
* @return false 尚未加锁
|
||||||
|
*/
|
||||||
|
static inline bool spin_is_locked(const spinlock_t *lock)
|
||||||
|
{
|
||||||
|
int x = READ_ONCE(lock->lock);
|
||||||
|
return (x == 0) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define assert_spin_locked(lock) BUG_ON(!spin_is_locked(lock))
|
224
kernel/lib/lockref.c
Normal file
224
kernel/lib/lockref.c
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#include <common/lockref.h>
|
||||||
|
#include <common/compiler.h>
|
||||||
|
|
||||||
|
#ifdef __LOCKREF_ENABLE_CMPXCHG__
|
||||||
|
#include <arch/x86_64/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 int 操作成功=>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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user