xref: /DragonOS/kernel/src/common/compiler.h (revision 182b778a3ca8c633b605ae7dd90a5e9f1131cc6d)
1 #pragma once
2 
3 #include <common/compiler_attributes.h>
4 
5 #define likely(x) __builtin_expect(!!(x), 1)
6 #define unlikely(x) __builtin_expect(!!(x), 0)
7 
8 #ifndef barrier
9 // 内存屏障
10 #define barrier() __asm__ __volatile__("" :: \
11                                            : "memory");
12 #endif
13 
14 /**
15  * @brief 编译时断言,如果condition不为1,则输出msg
16  *
17  * @param prefix 一个“不存在的函数名”的前缀
18  * @param suffix 一个“不存在的函数名”的后缀
19  */
20 #define __compiletime_assert(condition, msg, prefix, suffix)                                          \
21     do                                                                                                \
22     {                                                                                                 \
23         /**                                                                                           \
24          * 声明一个不存在的函数的extern,如果assert失败,就调用它,从而导致 \
25          * 链接时出错,进而达到“编译时断言”的功能。                            \
26          */                                                                                           \
27         __noreturn extern void prefix##suffix(void)                                                   \
28             __compiletime_error(msg);                                                                 \
29         if (!(condition))                                                                             \
30             prefix##suffix();                                                                         \
31     } while (0)
32 
33 /**
34  * @brief 当condition是false时,中断编译,并输出指定的错误信息
35  *
36  * @param condition assert的情况
37  * @param msg condition为false时输出的错误信息
38  */
39 #define complietime_assert(condition, msg)  \
40     __compiletime_assert(condition, msg, __compiletime_assert__, __COUNTER__)
41 
42 /**
43  * @brief 从src读取数据到dst,该过程避免编译器优化。
44  *
45  * @param dst 目标地址指针
46  * @param src 源地址指针
47  * @param size 要读取的数据大小(建议1、2、4、8字节,若不满足要求,则采用memcpy读取。)
48  */
49 static __always_inline void __read_once_size(void *dst, const volatile void *src, int size)
50 {
51     switch (size)
52     {
53     case 1:
54         *(__u8_alias_t *)dst = *(volatile __u8_alias_t *)src;
55         break;
56     case 2:
57         *(__u16_alias_t *)dst = *(volatile __u16_alias_t *)src;
58         break;
59     case 4:
60         *(__u32_alias_t *)dst = *(volatile __u32_alias_t *)src;
61         break;
62     case 8:
63         *(__u64_alias_t *)dst = *(volatile __u64_alias_t *)src;
64         break;
65     default:
66         barrier();
67         __builtin_memcpy((void *)dst, (const void *)src, size);
68         barrier();
69         break;
70     }
71 }
72 
73 /**
74  * @brief 把src处的数据到dst,该过程避免编译器优化。
75  *
76  * @param dst 目标地址指针
77  * @param src 源地址指针
78  * @param size 要写入的数据大小(建议1、2、4、8字节,若不满足要求,则采用memcpy传输。)
79  */
80 static __always_inline void __write_once_size(volatile void *dst, void *src, int size)
81 {
82     switch (size)
83     {
84     case 1:
85         *(volatile __u8_alias_t *)dst = *(__u8_alias_t *)src;
86         break;
87     case 2:
88         *(volatile __u16_alias_t *)dst = *(__u16_alias_t *)src;
89         break;
90     case 4:
91         *(volatile __u32_alias_t *)dst = *(__u32_alias_t *)src;
92         break;
93     case 8:
94         *(volatile __u64_alias_t *)dst = *(__u64_alias_t *)src;
95         break;
96     default:
97         barrier();
98         __builtin_memcpy((void *)dst, (const void *)src, size);
99         barrier();
100         break;
101     }
102 }
103 
104 /**
105  * 这两个宏能够避免编译器重排序、合并涉及到的读写操作,从而避免由于编译器优化导致的多线程读写顺序错误。
106  * 通过将有顺序要求的两个读/写操作放置在READ_ONCE()和WRITE_ONCE()之中,能够让编译器知道这些操作具有顺序要求。
107  *
108  * 这两个宏同样适用于Union或struct。如果要访问的数据大小不是1、2、4、8字节,则会使用memcpy来处理。
109  *
110  * 这两个宏的主要使用场景:
111  * 1.两个进程或者中断处理函数之间的信息交流与沟通
112  * 2.确保编译器不会折叠、旋转或以其他方式对代码进行优化,从而破坏数据访问顺序。
113  *
114  * 这两个宏的union __u内的__c用作这个union的地址的指针
115  *
116  * 关于READ_ONCE和WRITE_ONCE的简单说明,请转到:https://bbs.dragonos.org/forum.php?mod=viewthread&tid=24
117  */
118 
119 /**
120  * @brief 读取变量x (避免编译器优化)
121  */
122 #define READ_ONCE(x)                                \
123     ({                                              \
124         union                                       \
125         {                                           \
126             typeof(x) __val;                        \
127             char __c[1];                            \
128         } __u = {.__c = {0}};                       \
129         __read_once_size(__u.__c, &(x), sizeof(x)); \
130         __u.__val;                                  \
131     })
132 
133 /**
134  * @brief 将val写入变量x (避免编译器优化)
135  */
136 #define WRITE_ONCE(x, val)                           \
137     ({                                               \
138         union                                        \
139         {                                            \
140             typeof(x) __val;                         \
141             char __c[1];                             \
142         } __u = {.val = (val)};                      \
143         __write_once_size(&(x), __u.__c, sizeof(x)); \
144         __u.__val;                                   \
145     })
146