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