转自https://blog.csdn.net/fenglifeng1987/article/details/8172975
摘自《linux设备驱动开发详解》第七章
1.设置原子变量的值
void atomic_set(atomic_t *v, int i); //设置原子变量的值为i
atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
2.获取原子变量的值
atomic_read(atomic_t *v); //返回原子变量的值
3.原子变量加/减
void atomic_add(int i, atomic_t *v); //原子变量增加i
void atomic_sub(int i, atomic_t *v); //原子变量减少i
4.原子变量自增/自减
void atomic_inc(atomic_t *v); //原子变量增加1
void atomic_dec(atomic_t *v); //原子变量减少1
5.操作并测试
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i, atomic_t *v);
上述操作对原子变量执行自增、自减和减操作后(注意没有加)测试其是否为0,
为0 则返回true,否则返回false。
6.操作并返回
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);
上述操作对原子变量进行加/减和自增/自减操作,并返回新的值。
atomic。在atomic.h中有着它的定义以及操作函数。
-
typedef struct { volatile int counter; } atomic_t;
-
#define ATOMIC_INIT(i) { (i) }
-
/*
-
* atomic_read - read atomic variable
-
* @v: pointer of type atomic_t
-
*
-
* Atomically reads the value of @v.
-
*/
-
#define atomic_read(v) ((v)->counter)
-
/*
-
* atomic_set - set atomic variable
-
* @v: pointer of type atomic_t
-
* @i: required value
-
*
-
* Atomically sets the value of @v to @i.
-
*/
-
#define atomic_set(v,i) ((v)->counter = (i))
-
/*
-
* atomic_add - add integer to atomic variable
-
* @i: integer value to add
-
* @v: pointer of type atomic_t
-
*
-
* Atomically adds @i to @v.
-
*/
-
static __inline__ void atomic_add(int i, atomic_t * v)
-
{
-
if (cpu_has_llsc && R10000_LLSC_WAR) {
-
unsigned long temp;
-
__asm__ __volatile__(
-
" .set mips3 \n"
-
"1: ll %0, %1 # atomic_add \n"
-
" addu %0, %2 \n"
-
" sc %0, %1 \n"
-
" beqzl %0, 1b \n"
-
" .set mips0 \n"
-
: "=&r" (temp), "=m" (v->counter)
-
: "Ir" (i), "m" (v->counter));
-
} else if (cpu_has_llsc) {
-
unsigned long temp;
-
__asm__ __volatile__(
-
" .set mips3 \n"
-
"1: ll %0, %1 # atomic_add \n"
-
" addu %0, %2 \n"
-
" sc %0, %1 \n"
-
" beqz %0, 2f \n"
-
" .subsection 2 \n"
-
"2: b 1b \n"
-
" .previous \n"
-
" .set mips0 \n"
-
: "=&r" (temp), "=m" (v->counter)
-
: "Ir" (i), "m" (v->counter));
-
} else {
-
unsigned long flags;
-
raw_local_irq_save(flags);
-
v->counter += i;
-
raw_local_irq_restore(flags);
-
}
-
}
-
/*
-
* atomic_sub - subtract the atomic variable
-
* @i: integer value to subtract
-
* @v: pointer of type atomic_t
-
*
-
* Atomically subtracts @i from @v.
-
*/
-
static __inline__ void atomic_sub(int i, atomic_t * v)
-
{
-
if (cpu_has_llsc && R10000_LLSC_WAR) {
-
unsigned long temp;
-
__asm__ __volatile__(
-
" .set mips3 \n"
-
"1: ll %0, %1 # atomic_sub \n"
-
" subu %0, %2 \n"
-
" sc %0, %1 \n"
-
" beqzl %0, 1b \n"
-
" .set mips0 \n"
-
: "=&r" (temp), "=m" (v->counter)
-
: "Ir" (i), "m" (v->counter));
-
} else if (cpu_has_llsc) {
-
unsigned long temp;
-
__asm__ __volatile__(
-
" .set mips3 \n"
-
"1: ll %0, %1 # atomic_sub \n"
-
" subu %0, %2 \n"
-
" sc %0, %1 \n"
-
" beqz %0, 2f \n"
-
" .subsection 2 \n"
-
"2: b 1b \n"
-
" .previous \n"
-
" .set mips0 \n"
-
: "=&r" (temp), "=m" (v->counter)
-
: "Ir" (i), "m" (v->counter));
-
} else {
-
unsigned long flags;
-
raw_local_irq_save(flags);
-
v->counter -= i;
-
raw_local_irq_restore(flags);
-
}
-
}
-
/*
-
* atomic_sub_and_test - subtract value from variable and test result
-
* @i: integer value to subtract
-
* @v: pointer of type atomic_t
-
*
-
* Atomically subtracts @i from @v and returns
-
* true if the result is zero, or false for all
-
* other cases.
-
*/
-
#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
-
/*
-
* atomic_inc_and_test - increment and test
-
* @v: pointer of type atomic_t
-
*
-
* Atomically increments @v by 1
-
* and returns true if the result is zero, or false for all
-
* other cases.
-
*/
-
#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
-
/*
-
* atomic_dec_and_test - decrement by 1 and test
-
* @v: pointer of type atomic_t
-
*
-
* Atomically decrements @v by 1 and
-
* returns true if the result is 0, or false for all other
-
* cases.
-
*/
-
#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
其实就是设置一个整形变量,对这个整形变量进行加减操作。可应用于对引用资源的计数。
在对这个整形变量进行加减的过程中,是在原子状态下进行的,汇编语言先不管,那几段少的可怜的c代码中,v->count进行加减的时候都是要关中断的。确保当前process占用内核。
原子锁也可以用于同步。比如下面的程序,至允许在一个进程中打开资源。程序也是摘自《linux设备驱动详解》
-
static atomic_t xxx_available = ATOMIC_INIT(1); /*定义原子变量*/
-
static int xxx_open(struct inode *inode, struct file *filp)
-
{
-
...
-
if (!atomic_dec_and_test(&xxx_available)) //如果xxx_available=0,返回1
-
{
-
atomic_inc(&xxx_available);
-
return - EBUSY; /*已经打开*/
-
}
-
...
-
return 0; /* 成功*/
-
}
-
static int xxx_release(struct inode *inode, struct file *filp)
-
{
-
atomic_inc(&xxx_available); /* 释放设备*/
-
return 0;
-
}
还有位操作的的原子锁,原理跟上面的差不多,只不过这是用bit操作,这样操作更简洁明了,非0即1,就是缺少了计数这个功能。
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_and_xxx_bit(nr, void *addr)操作等同于执行test_bit (nr, void *addr)后
再执行xxx_bit(nr, void *addr)。