字元裝置中的同步、互斥和阻塞操作
下面的內容對學習過程中做一個簡單的總結,方便以後回憶,內容可能過於簡陋
1. 原子操作
如果我們希望字元驅動程式每次只能給一個應用程式開啟,就需要加鎖,比如在驅動程式中加一個整型的全域性變數canopen: 1代表可以open,0代表不能open。 但是我們不能簡單的給整型變數canopen++或者canopen--,因為程式碼中簡單的自加動作,在彙編程式碼中就要分成3步完成: ldr ... 讀出 add ... 加操作 str ... 回寫值
假如A、B兩個程式同時操作變數canopen = 1,在多工的情況下就會有問題,比如:
A B 讀出canopen,此時值為1 被切換出執行佇列 讀出canopen,此時值為1 canopen--,此時值為0 open字元裝置成功 此時A程式重新開始執行,進行canopen--,值為0 open字元裝置也成功
由上面的分析可知,簡單的加減是不可靠的,可以使用原子操作:
原子操作指的是在執行過程中不會被別的程式碼路徑所中斷的操作。 常用原子操作函式舉例:
atomic_t v = ATOMIC_INIT(0); //定義原子變數v並初始化為0 atomic_read(atomic_t *v); //返回原子變數的值 void atomic_inc(atomic_t *v); //原子變數增加1 void atomic_dec(atomic_t *v); //原子變數減少1 int atomic_dec_and_test(atomic_t *v); //自減操作後測試其是否為0,為0則返回true,否則返回false。
2. 訊號量
訊號量(semaphore)是用於保護臨界區的一種常用方法,只有得到訊號量的程序才能執行臨界區程式碼。 當獲取不到訊號量時,程序進入休眠等待狀態。
定義訊號量 struct semaphore sem; 初始化訊號量 void sema_init (struct semaphore *sem, int val); void init_MUTEX(struct semaphore *sem);//初始化為0 也可以用下面的巨集定義: static DECLARE_MUTEX(button_lock); //定義互斥鎖 open時獲得訊號量: void down(struct semaphore * sem); //down(&button_lock) //非第一個獲取訊號量的程式都要進入休眠狀態,直到第一個獲取訊號量的程式釋放鎖 int down_interruptible(struct semaphore * sem); //加了interruptible,說明就算休眠了也能被別人打斷 int down_trylock(struct semaphore * sem); //down_trylock(&button_lock) close時釋放訊號量: void up(struct semaphore * sem); //up(&button_lock);
3. 阻塞
阻塞操作 是指在執行裝置操作時若不能獲得資源則掛起程序,直到滿足可操作的條件後再進行操作。 被掛起的程序進入休眠狀態,被從排程器的執行佇列移走,直到等待的條件被滿足。
非阻塞操作 程序在不能進行裝置操作時並不掛起,它或者放棄,或者不停地查詢,直至可以進行操作為止。
fd = open("...", O_RDWR | O_NONBLOCK); //傳入O_NONBLOCK標誌位給底層驅動程式
在驅動程式中就可以這麼使用:
if (file->f_flags & O_NONBLOCK)
{
if (沒有檢測事件的發生)
return -EBUSY;
}
else
{
//進入休眠的狀態
wait_event_interruptible(...);
}