Linux设备驱动程序 之 per-cpu变量
数组形式
支持SMP的现代操作系统使用每个cpu上的数据,对于给定的处理器其数据是唯一的;一般来说,每个cpu的数据存放在一个数组中,数组总的每一项对应着系统上的一个存在的处理器;按当前处理器号确定这个数组的当前元素;使用方式如下:
unsigned long my_percpu[NR_CPUS]; int cpu; cpu = get_cpu(); /* 获取当前处理器,并禁止抢占 */
my_percpu[cpu]++; /* 对变量做处理 */
put_cpu(); /* 激活内核抢占 */
上面代码并没有出现锁,这是因为所操作的数据对当前处理器来说是唯一的;除了当前处理器之外,没有其他处理器可接触到这个数据,不存在并发访问的问题,所以当前处理器可以再不用锁的情况下安全访问它;
现在,内核抢占成了唯一需要关注的问题了,内核抢占会引起下面的两个问题:
1. 如果代码被其他处理器抢占并重新调度,那么这时cpu变量就会无效,因为它指向的是错误的处理器;(通常,代码获得当前处理器后是不可以睡眠的);
2. 如果另一个任务抢占了代码,那么有可能在同一处理器上发生并发访问my_percpu的情况,显然属于一个竞态;
上述代码中在调用get_put()时,禁止了内核抢占;相对的调用put_cpu()时又会重新激活当前处理器号;
新的接口
2.6内核开始为了方便创建和操作每个cpu数据,而引进了新的操作接口,称为percpu,该接口归纳了前面所述的操作行为,简化了创建和操作每个cpu的数据;
但前面说的创建和访问每个cpu的方法仍然有效,不过大型对称多处理器计算机要求对每个cpu数据操作更简单,功能更强大,所以新接口应运而生;
编译时的每个cpu数据
编译期间定义每个cpu变量:
DEFINE_PER_CPU(type,name)
这个语句为系统中每个cpu都创建了一个类型为type,名称为name的变量实例,如果需要在别处声明变量,则应该使用下面的宏:
DECLARE_PER_CPU(type,name)
可以利用get_cpu_var()和put_cpu_var()函数来操作变量;
get_cpu_var(name)++; /*禁止抢占,操作cpu变量*/
put_cpu_var(name); /*完成,重新激活内核抢占*/
还可以通过per_cpu(name, cpu)获取别的处理器上的每个cpu数据:
per_cpu(name, cpu)++;/* 增加指定处理器上的数据值 */
注意:per_cpu()函数既不会禁止内核抢占,也不会提供任何形式的锁保护;如果一个处理器可以接触到其他处理器上的数据,那就必须给数据上锁;
运行时的每个cpu数据
#define alloc_percpu(type) \
(typeof(type) __percpu *)__alloc_percpu(sizeof(type), \
__alignof__(type)) void __percpu *__alloc_percpu(size_t size, size_t align) void free_percpu(void __percpu *__pdata)
alloc_percpu()给系统中每个处理器分配一个指定类型对象的实例,它是__alloc_percpu的一个封装,原始函数接收两个参数:一个是要分配的实际字节数,一个是分配时要按多少字节对齐;而封装后的alloc_percpu()是按照字节对齐–按照给定的类型的自然边界对齐;
free_percpu()将释放所有处理器上指定的每个cpu数据;
alloc_percpu()或者是__alloc_percpu()会返回一个指针,它用来间接引用动态创建的每个cpu数据,内核提供了两个宏利用指针来获取每个cpu数据:
/*
* Must be an lvalue. Since @var must be a simple identifier,
* we force a syntax error here if it isn't.
*/
#define get_cpu_var(var) \
(*({ \
preempt_disable(); \
this_cpu_ptr(&var); \
})) /*
* The weird & is necessary because sparse considers (void)(var) to be
* a direct dereference of percpu variable (var).
*/
#define put_cpu_var(var) \
do { \
(void)&(var); \
preempt_enable(); \
} while ()
get_cpu_var()返回一个指向当前处理器数据的特殊实例,它同时会禁止内核抢占;而在put_cpu_var()中会重新激活内核抢占;
每个cpu数据好处
1. 减少了数据锁定;每个处理器访问每个处理器的数据,可以不需要任何锁;
2. 大大减少了缓存失败;percpu接口缓存对齐所有数据,以便确保在访问一个处理器的数据时,不会将林我国一个处理器的数据带入同一个缓存线上;
注意:不能再访问每个cpu数据过程中睡眠,否则,醒来之后可能已经到达其他处理器上了;
最新文章
- (转)maven配置之pom.xml配置
- Introduction of Open CASCADE Foundation Classes
- Docker Hub仓库注册,使用
- 南阳OJ----Binary String Matching
- Hibernate从入门到精通(十一)多对多双向关联映射
- 利用 Ant 和 Eclipse 有效地提高部署工作效率
- Windows Azure Platform 系列文章目录
- [iOS基础控件 - 6.10.1] PickerView 餐点搭配Demo
- 原生js怎么为动态生成的标签添加各种事件
- hihoCoder挑战赛11 A 随机斐波那契
- 颜色的RGB值表示法
- 在NOARCHIVELOG和ARCHIVELOG模式之间选择
- python 之 configparser 模块
- Ubuntu中让归档管理器支持rar和7z格式
- PHP实现字符串转义和还原
- 最佳运动类APP-Keep设计与欣赏
- Socket网络编程--FTP客户端(2)(Windows)
- drupal7 模糊查询接口
- OpenFoam+CFDEM+Liggghts安装耦合
- SIP UserAgent (B2BUA client)——pjsip
热门文章
- RAII Theory &;&; auto_ptr
- [转]Spring Security Oauth2 认证流程
- pymysql 1064, 'You have an error in your SQL syntax; check the manual that corresponds to
- deep_learning_Github_初学者教程
- java_字符串
- java基础:多态过程中的动态绑定
- [转载]npm 与 package.json 快速入门教程
- 二、vue基础--计算属性和监听器
- java判断文件是否为图片
- BZOJ 1299: [LLH邀请赛]巧克力棒 【SG函数/博弈分析/高斯消元】