一步一步走进字符驱动--原子操作
闲聊
有一阵子没跟新博客了,最近发现我以前好多的代码都不见了.诶..都怪我没有及时备份.在这里提醒下,一定要多备份你们的代码资料.到时候别硬盘打不开之类的悲剧也降临了,近几天群里有个朋友问我要D3D的代码..我好久没接触那东西了,于是乎去找.结果发现找不到了..悲剧死....好了,言归正传.开始今天的教程..
原子操作
原子操作是指在执行过程中不会被别的代码路劲中断的操作.
在linux中又支持两类原子操作,一类是整形变量.一类是位变量.它们的共同点都是原子操作.内核代码可以安全的调用它们而不会被打断.
整形原子操作
原子操作定义: arm/include/asm/atomic.h
typedef struct { int counter; } atomic_t;
1:设置原子变量的值
void atomic_set(atomic_t *v,int i); //设置原子变量的值为i atomic_t v = ATOMIC_INIT(i); //定义原子变量并初始化为0
2:获取原子变量的值
atomic_read(v); //返回原子变量的值
3:原子变量加/减
static inline void atomic_add(int i, atomic_t *v); //原子变量加i static inline void atomic_sub(int i, atomic_t *v); //原子变量减i
4:原子变量自增/自减
void atomic_add(1, v); //原子变量自增1 void atomic_sub(1, v); //原子变量自减1
5:操作并测试
#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) #define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) #define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
上述原子变量对自身进行操作之后与0进行比较.==0返回true,否则返回false
注:此处没有加操作
6:操作并返回
static inline int atomic_add_return(int i, atomic_t *v); static inline int atomic_sub_return(int i, atomic_t *v); #define atomic_inc_return(v) (atomic_add_return(1, v)) #define atomic_dec_return(v) (atomic_sub_return(1, v))
上述操作是对原子变量先进行自增自减和加减操作,后返回新的值
位原子操作
所属头文件:asm/bitops.h
1:设置位
void set_bit(nr,void*addr)
设置addr地址的第nr位为1
2清除位
void clear_bit(nr,void*addr)
设置addr地址的第nr位为0
3:改变位
void change_bit(nr,void* addr)
设置addr地址的第nr位为反置
4:测试位
test_bit(nr,void*addr)
返回addr地址的第nr位的值
5:测试并操作位
int test_and_set_bit(nr,void*addr) int test_and_clear_bit(nr,void*addr) int test_and_change_bit(nr,void*addr)
上述操作相当于执行test_bit后执行相应的操作
下面给出一份代码--实现设备只能被打开一次
struct device_dev{ struct cdev cdev; atomic_t atomic; }; //初始化原子操作 atomic_set(&g_devp->atomic,1); int atomic_open(struct inode *_pinod, struct file *_pfile) { printk(KERN_INFO "%d\n",atomic_read(&g_devp->atomic)); //atomic被初始化为1.那么第一次条件测试的时候,if(false),那么就成功打开,否则.永远失败 //初始化在模块加载函数内.atomic_set(&g_devp->atomic,1); if(!atomic_dec_and_test(&g_devp->atomic)){ atomic_inc(&g_devp->atomic); printk(KERN_INFO "error %d\n",atomic_read(&g_devp->atomic)); return -EBUSY; } printk(KERN_INFO "successful %d\n",atomic_read(&g_devp->atomic)); return 0; } int atomic_release(struct inode *_pinod, struct file *_pfile) { atomic_inc(&g_devp->atomic); return 0; }