new: lockref

This commit is contained in:
fslongjin
2022-10-06 14:20:03 +08:00
parent 9b37ff3e5a
commit 85719d938d
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))