中斷屏蔽:
disable_irq(unsigned int irq);
--關中斷
enable_irq(unsigned int irq); --開中斷
local_irq_disable(); --關全部中斷
local_irq_enable(); --使能全部中斷
local_bh_disable();
--禁止中斷底半部
local_bh_enable(); --使能中斷底半部
local_irq_save(flags);
--保存cpu中斷位信息
local_irq_restore(x); --恢復cpu中斷位信息
原子操作:
(整型原子操作)
atomic_t --原子變量類型
atomic_set(v,i); --設置原子變量爲i
atomic v = ATOMIC_INIT(0); --定義並初始化v
atomic_read(v); --讀取原子變量的值
atomic_add(i,v); --加i
atomic_sub(i,v); --減i
atomic_inc_and_test(v); --
atomic_dec_and_test(v); --
atomic_sub_and_test(i,v); --
atomic_add_return(i,v);
atomic_sub_return(i,v);
atomic_inc_return(v);
atomic_dec_return(v);
(位原子操作)
set_bit(nr,addr); --置1
clear_bit(nr,addr); --清0
change_bit(nr,addr); --反轉
test_bit(nr,addr); --測試
test_and_set_bit(nr, addr);
test_and_clear_bit(nr,addr);
test_and_change_bit(nr,addr);
(使用原子變量實現設備只能被一個進程打開,或保護臨界資源)
static void open(.....)
{
//防止進程被多個設備打開
if( !atomic_dec_and_test(v) )
{
atomic_inc(v);
}
}
static void release(....)
{
//釋放設備
atomic_inc(v);
}
自旋鎖:
(關於使用自旋鎖時要避免使用引起進程調度的操作,例如copy_from_user(), copy_to_user(), kmalloc(), msleep()等有可能導致進程阻塞,所以不能用。具體原因還爲明白?)
spinlock_t lock;
spin_lock_init(lock);
spin_lock(lock); --沒有獲得鎖則在原地自旋
spin_trylock(lock); --沒有獲得鎖則立刻返回假
spin_unlock(lock);
(保護臨界區資源)
void fun()
{
spinlock_t lock;
spin_lock_init(lock);
.....
spin_lock(lock);
//臨界區,如果臨界區較大不適合用自旋鎖
spin_unlock(lock);
.....
}
能阻止搶佔進程的打擾,但不能防止中斷和底半部。需要結合中斷屏蔽使用,下面是完整版
spin_lock_irq(lock) = spin_lock(lock) + local_irq_disable();
spin_unlock_irq(lock) = spin_unlock(lock)+ local_irq_enable();
spin_lock_irqsave(lock,flags) = spin_lock(lock) + local_irq_save(flags);
spin_unlock_irqrestore(lock,flags) = spin_unlock(lock) + local_irq_restore(x);
spin_lock_bh(lock) = spin_lock(lock) + local_bh_disable(void);
spin_unlock_bh(lock) = spin_unlock(lock) + local_bh_enable(void);
static int open(...)
{
//實現設備只能被一個進程打開
spin_lock_irq(lock);
if( cnt > 0 )
{
spin_unlock_irq(lock);
return -EBUSY;
}
cnt ++;
spin_unlock_irq(lock);
......
return 0;
}
static int release(...)
{
//釋放資源
spin_lock_irq(lock);
cnt--;
spin_unlock_irq(lock);
.....
return 0;
}
一般的自旋鎖同時鎖定讀寫操作,實際上讀操作是允許多個同時進行的。 讀寫自旋鎖允許讀的併發訪問,禁止寫的併發訪問,禁止讀與寫的共同發生。
rwlock_t lock; (讀寫自旋鎖)
rwlock_init(&lock);
/** 讀鎖定*/
read_lock(lock);
read_lock_irqsave(lock,flags);
read_lock_irq(lock);
= read_lock(lock) + local_irq_disable;
read_lock_bh(lock);
/** 讀解鎖*/
read_unlock(lock);
read_unlock_irq(lock) =
read_unlock(lock) + local_irq_enable;
read_unlock_irqrestore(lock,flags);
read_unlock_bh(lock);
/** 寫鎖定*/
write_lock(lock);
write_lock_irq(lock);
write_lock_bh(lock);
write_lock_irqsave(lock,flags);
write_trylock(lock);
/** 寫解鎖*/
write_unlock(lock);
write_unlock_bh(lock);
write_unlock_irq(lock);
write_unlock_irqrestore(lock,flags);
void example()
{
rwlock_t lock;
rwlock_init( &lock );
/** 使用讀鎖*/
read_lock(lock);
//臨界區資源
read_unlock(lock);
/** 使用寫鎖*/
write_lock_irqsave( &lock, flag);
//臨界區資源
write_unlock_irqrestore( &lock, flag);
}
還有一種RCU(read copy update)的方式。讀操作時不加鎖,寫操作時先對拷貝數據進行寫,然後使用回調機制在共享數據空閒時再將修改的數據寫回。這對讀操作較多的系統比較有利。
rcu_read_lock();
rcu_read_lock_bh();
rcu_read_unlock();
rcu_read_unlock_bh();
synchronize_rcu(void);
synchronize_sched();
call_rcu(struct rcu_head * head,void(* func)(struct rcu_head * rcu));
call_rcu_bh();
RCU還提供了一些爲 list_head 和 hlist_head的共享數據訪問工作的函數。
信號量:
//信號量會導致睡眠,所以不能在中斷上下文使用
struct semaphore sem;
sema_init( &sem, 1);
DECLARE_MUTEX( sem); = struct semaphore sem = sema_init( temp, 1);
down( &sem); --睡眠後不能被信號打斷
down_interruptible( &sem); --睡眠後可被信號打斷
down_trylock( &sem); --不成功則直接返回
up( &sem);
static struct semaphore sem;
sema_init( &sem, 1);
static int open(....)
{
//使設備只能被打開一次
if( down_trylock( &sem))
{
return -EBUSY;
}
...
return 0;
}
static int release(...)
{
//釋放
up( &sem);
return 0;
}
完成量:
struct completion com;
init_completion( &com);
DECLARE_COMPLETION( com); --declare and init a @completion
wait_for_completion( &com);
complete( &com); --rouse a @completion
complete_all( &com); --rouse all @completion
互斥體:
struct mutex mut;
mutex_init( &mutex);
mutex_lock( &mut);
mutex_trylock( &mut);
mutex_lock_interruptible( &mut);
mutex_unlock( &mut);
使用例子:
struct mutex mut;
mutex_init( &mut);
mutex_lock( &mut);
//....
mutex_unlock( &mut);
等待隊列:
//定義等待隊列
wait_queue_head_t wq;
init_waitqueue_head( &wq);
DECLARE_WAIT_QUEUE_HEAD( wq);
DECLARE_WAITQUEUE( wait, current);
//添加隊列
add_wait_queue( &wq, &wait);
remove_wait_queue( &wq, &wait);
//相關操作
schedule( );
set_current_state( TASK_INTERRUPTIBLE);
__set_current_state( TASK_RUNNING);
wake_up( &wq);
wait_event( wq, condition);
static wait_queue_head_t wq;
void init(.....) //用來初始化等待隊列
{
init_waitqueue_head( &wq);
}
void read(.....)
{
DECLARE_WAITQUEUE( wait, current); //用來定義一個實體
......
add_wait_queue( &wq, &wait); //添加進隊列
......
set_current_state( TASK_INTERRUPTIBLE);
schedule( ); // 進程退出點 and 迴歸點
......
remove_wait_queue( &wq, &wait); //從隊列裏移除
set_current_state( TASK_RUNNING);
......
}
void fun(...)
{
wake_up( &wq); //喚醒阻塞的進程
}
輪詢:
在應用層的使用例子
void AppFun(....)
{
fd_set rfds;
int fd_1, fd_2;
fd_1 = open( "/dev/fifo1", O_RDONLY|O_NONBLOCK);
fd_2 = open( "/dev/fifo2", O_RDONLY|O_NONBLOCK);
while(1)
{
FD_ZERO( &rfds);
FD_SET( fd_1, &rfds);
FD_SET( fd_2, &rfds);
select( MAX(fd_1, fd_2), &rfds, NULL, NULL, NULL);
if( FD_ISSET( fd_1, &rfds))
{
.....
}
if( FD_SET( fd_2, &rfds))
{
.....
}
}
}
而在驅動層的使用和原理還有待研究:
()