一步一步走進字符驅動--原子操作
閒聊
有一陣子沒跟新博客了,最近發現我以前好多的代碼都不見了.誒..都怪我沒有及時備份.在這裏提醒下,一定要多備份你們的代碼資料.到時候別硬盤打不開之類的悲劇也降臨了,近幾天羣裏有個朋友問我要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;
}