Merge branch 'patch-devfs-unregister-device'

This commit is contained in:
fslongjin 2022-10-06 14:20:24 +08:00
commit f3bd316578
4 changed files with 426 additions and 2 deletions

View 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
View 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.count0
*
* @param lock_ref lockref变量的指针
* @return int =>true
* =>false
*/
bool lockref_inc_not_zero(struct lockref *lock_ref);
/**
* @brief count0-1
*
* lockref_dec_return()cmpxchg()count<=0
*
*
* @param lock_ref lockref变量的指针
* @return int =>
* lockref处于count0 => -1
*/
int lockref_dec(struct lockref *lock_ref);
/**
* @brief count0-1
*
* lockref_dec()cmpxchg()count<=0
*
*
* @param lock_ref lockref变量的指针
* @return int =>
* lockref处于已加锁或count0 => -1
*/
int lockref_dec_return(struct lockref *lock_ref);
/**
* @brief 1
*
* lockref_dec_or_lock_not_zero()cmpxchg()old.count1false.
*
*
* @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.count1
* 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);

View File

@ -11,6 +11,7 @@
#pragma once
#include <common/glib.h>
#include <process/preempt.h>
#include <debug/bug.h>
/**
* @brief
@ -19,8 +20,7 @@
typedef struct
{
int8_t lock; // 1:unlocked 0:locked
}spinlock_t;
} spinlock_t;
/**
* @brief
@ -167,3 +167,18 @@ long spin_trylock(spinlock_t *lock)
spin_unlock(lock); \
local_irq_enable(); \
} 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
View 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.count0
*
* @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 count0-1
*
* lockref_dec_return()cmpxchg()count<=0
*
*
* @param lock_ref lockref变量的指针
* @return int =>
* lockref处于count0 => -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 count0-1
*
* lockref_dec()cmpxchg()count<=0
*
*
* @param lock_ref lockref变量的指针
* @return int =>
* lockref处于已加锁或count0 => -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.count1false.
*
*
* @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.count1
* 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;
}