一步一步走进字符驱动--原子操作
闲聊
有一阵子没跟新博客了,最近发现我以前好多的代码都不见了.诶..都怪我没有及时备份.在这里提醒下,一定要多备份你们的代码资料.到时候别硬盘打不开之类的悲剧也降临了,近几天群里有个朋友问我要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;
}