核心的同步機制(原子鎖)
轉自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)。