linux源码:READ_ONCE宏

内核版本:6.10
源码

#define READ_ONCE(x)							\
({									\
	compiletime_assert_rwonce_type(x);				\
	__READ_ONCE(x);							\
})

compiletime_assert_rwonce_type

compiletime_assert_rwonce_type的定义

#define compiletime_assert_rwonce_type(t)					\
	compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long),	\
		"Unsupported access size for {READ,WRITE}_ONCE().")

对t进行检查,有问题就停止编译

__native_word

#define __native_word(t) \
	(sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || \
	 sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))

就是对t的类型进行检查

compiletime_assert

源码

#define compiletime_assert(condition, msg) \
	_compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)

就是对_compiletime_assert的封装,__COUNTER__是编译器宏,调用一次 加一
demo

#include<stdio.h>
int main(){
	printf("%d %d\n", __COUNTER__,__COUNTER__);
    return 0;
}

执行结果

pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/linuxCode/READ_ONCE$ make
0 1

_compiletime_assert

定义

#define _compiletime_assert(condition, msg, prefix, suffix) \
	__compiletime_assert(condition, msg, prefix, suffix)

调用的__compiletime_assert
__compiletime_assert 定义

	
# define __compiletime_assert(condition, msg, prefix, suffix)		\
	do {								\
		/*							\
		 * __noreturn is needed to give the compiler enough	\
		 * information to avoid certain possibly-uninitialized	\
		 * warnings (regardless of the build failing).		\
		 */							\
		__noreturn extern void prefix ## suffix(void)		\
			__compiletime_error(msg);			\
		if (!(condition))					\
			prefix ## suffix();				\
	} while (0)

其中__compiletime_error

# define __compiletime_error(msg)       __attribute__((__error__(msg)))

用个demo解释吧

#include<stdio.h>
# define __compiletime_error(msg)       __attribute__((__error__(msg)))
#define __noreturn                      __attribute__((__noreturn__))
# define __compiletime_assert(condition, msg, prefix, suffix)		\
	do {								\
		/*							\
		 * __noreturn is needed to give the compiler enough	\
		 * information to avoid certain possibly-uninitialized	\
		 * warnings (regardless of the build failing).		\
		 */							\
		__noreturn extern void prefix ## suffix(void)		\
			__compiletime_error(msg);			\
		if (!(condition))					\
			prefix ## suffix();				\
	} while (0)
#define _compiletime_assert(condition, msg, prefix, suffix) \
	__compiletime_assert(condition, msg, prefix, suffix)
#define compiletime_assert(condition, msg) \
	_compiletime_assert(condition, msg, dss, __COUNTER__)

int main(){
    compiletime_assert(0,"here!!!!!! look");
    
    return 0;
}

把这些乱七八糟的宏展开后代码长这样(用 gcc -E main.c),就可以把宏展开
demo

int main(){
    do { __attribute__((__noreturn__)) extern void __compiletime_assert_0(void) __attribute__((__error__("here!!!!!! look"))); 
   		 if (!(0)) __compiletime_assert_0(); 
    } while (0);

    return 0;
}

__attribute__是个gcc的特性,可对函数进行修饰,调用时会有而外的反应,像这个例子,就是先声明了一个函数

extern void __compiletime_assert_0(void)

然后加了两个__attribute__:
1 attribute((noreturn))
2 attribute((error(“here!!! look”)))

就变成上面那形状了。
error__我理解就是输出某种格式的错误信息,并标记这个函数,如果用调用的地方 就停止编译,因此__attribute((error(“here!!! look”)))的作用就是告诉gcc检测到有的地方要调用__compiletime_assert_0函数,就停止编译输出错误信息。
运行结果如下

pipishuo@pipishuo-OMEN-by-HP-Laptop-16-b0xxx:~/Desktop/knowledge/technology/linuxCode/READ_ONCE$ make
gcc -std=c11 main.c
main.c: In function ‘main’:
main.c:19:45: error: call to ‘__compiletime_assert_0’ declared with attribute error: here!!!!!! look
   19 |         _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)

看 编译时就输出咱们代码写的信息,并停止了编译

__READ_ONCE(x);

#define __READ_ONCE(x)	(*(const volatile __unqual_scalar_typeof(x) *)&(x))

__unqual_scalar_typeof

代码如下

#define __scalar_type_to_expr_cases(type)				\
		unsigned type:	(unsigned type)0,			\
		signed type:	(signed type)0
		
#define __unqual_scalar_typeof(x) typeof(				\
		_Generic((x),						\
			 char:	(char)0,				\
			 __scalar_type_to_expr_cases(char),		\
			 __scalar_type_to_expr_cases(short),		\
			 __scalar_type_to_expr_cases(int),		\
			 __scalar_type_to_expr_cases(long),		\
			 __scalar_type_to_expr_cases(long long),	\
			 default: (x)))

关于_Generic 这篇博客讲的很好:https://blog.csdn.net/qq_31243065/article/details/80904613
简单来说就是根据x的类型输出不同的代码
比如 x的类型是signed int,_Generic()就变成(signed int)0,再根据typeof 就变成了signed int,感觉多此一举呢

所以__READ_ONCE(x) 的作用就是把x变量换个类型,然后取他的值,比如 int x __READ_ONCE(x) 翻译过来就是(*(const volatile int *)&(x))
关于volatile,参考链接:https://www.cnblogs.com/Goforyouqp/p/17606953.html
总结下来就是每次读这个变量,都去内存去读,而不是从缓存中读。

总结

先检查类型,然后转了一下类型然后取他的值,如果是看kernel代码,就基本没用,如果是写,还是很有用的,保证数据不混乱

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值