1 /**
2 * @file atomic.h
3 * @author fslongjin (longjin@RinGoTek.cn)
4 * @brief 原子变量
5 * @version 0.1
6 * @date 2022-04-12
7 *
8 * @copyright Copyright (c) 2022
9 *
10 */
11 #pragma once
12 #include <arch/x86_64/include/asm/cmpxchg.h>
13
14 #define atomic_read(atomic) ((atomic)->value) // 读取原子变量
15 #define atomic_set(atomic,val) (((atomic)->value) = (val)) // 设置原子变量的初始值
16
17 typedef struct
18 {
19 volatile long value;
20 } atomic_t;
21
22 /**
23 * @brief 原子变量增加值
24 *
25 * @param ato 原子变量对象
26 * @param val 要增加的值
27 */
atomic_add(atomic_t * ato,long val)28 inline void atomic_add(atomic_t *ato, long val)
29 {
30 asm volatile("lock addq %1, %0 \n\t"
31 : "=m"(ato->value)
32 : "m"(val)
33 : "memory");
34 }
35
36 /**
37 * @brief 原子变量减少值
38 *
39 * @param ato 原子变量对象
40 * @param val 要减少的值
41 */
atomic_sub(atomic_t * ato,long val)42 inline void atomic_sub(atomic_t *ato, long val)
43 {
44 asm volatile("lock subq %1, %0 \n\t"
45 : "=m"(ato->value)
46 : "m"(val)
47 : "memory");
48 }
49
50 /**
51 * @brief 原子变量自增
52 *
53 * @param ato 原子变量对象
54 */
atomic_inc(atomic_t * ato)55 void atomic_inc(atomic_t *ato)
56 {
57 asm volatile("lock incq %0 \n\t"
58 : "=m"(ato->value)
59 : "m"(ato->value)
60 : "memory");
61 }
62
63 /**
64 * @brief 原子变量自减
65 *
66 * @param ato 原子变量对象
67 */
atomic_dec(atomic_t * ato)68 void atomic_dec(atomic_t *ato)
69 {
70 asm volatile("lock decq %0 \n\t"
71 : "=m"(ato->value)
72 : "m"(ato->value)
73 : "memory");
74 }
75
76 /**
77 * @brief 设置原子变量的mask
78 *
79 * @param ato 原子变量对象
80 */
atomic_set_mask(atomic_t * ato,long mask)81 inline void atomic_set_mask(atomic_t *ato, long mask)
82 {
83 __asm__ __volatile__("lock orq %1, %0 \n\t"
84 : "=m"(ato->value)
85 : "r"(mask)
86 : "memory");
87 }
88
89 /**
90 * @brief 清除原子变量的mask
91 *
92 * @param ato 原子变量对象
93 */
atomic_clear_mask(atomic_t * ato,long mask)94 inline void atomic_clear_mask(atomic_t *ato, long mask)
95 {
96 __asm__ __volatile__("lock andq %1, %0 \n\t"
97 : "=m"(ato->value)
98 : "r"(mask)
99 : "memory");
100 }
101
102 // cmpxchgq 比较并交换
atomic_cmpxchg(atomic_t * ato,long oldval,long newval)103 inline long atomic_cmpxchg(atomic_t *ato, long oldval, long newval)
104 {
105 bool success = arch_try_cmpxchg(&ato->value, &oldval, newval);
106 return success ? oldval : newval;
107 }
108