DOWN操作:linux內(nèi)核中,對信號量的DOWN操作有如下幾種:
void down(struct semaphore *sem); //不可中斷
int down_interruptible(struct semaphore *sem);//可中斷
int down_killable(struct semaphore *sem);//睡眠的進(jìn)程可以因為受到致命信號而被喚醒,中斷獲取信號量的操作。
int down_trylock(struct semaphore *sem);//試圖獲取信號量,若無法獲得則直接返回1而不睡眠。返回0則 表示獲取到了信號量
int down_timeout(struct semaphore *sem,long jiffies);//表示睡眠時間是有限制的,如果在jiffies指明的時間到期時仍然無法獲得信號量,則將返回錯誤碼。
在以上四種函數(shù)中,驅(qū)動程序使用的最頻繁的就是down_interruptible函數(shù),以下將對該函數(shù)進(jìn)行分析。
down_interruptible函數(shù)的定義如下:
int down_interruptible(struct semaphore *sem)
{
unsigned long flags;
int result = 0;
spin_lock_irqsave(&sem->lock,flags);
if (likely(sem->count> 0))
sem->count--;
else
result =__down_interruptible(sem);
spin_unlock_irqrestore(&sem->lock,flags);
return result;
}
函數(shù)分析:函數(shù)首先通過spin_lock_irqsave的調(diào)用來保證對sem->count操作的原子性。如果count>0,表示當(dāng)前進(jìn)程可以獲得信號量,將count的值減1然后退出。如果count不大于0,表明當(dāng)前進(jìn)程無法獲取信號量,則調(diào)用__down_interruptible,后者會繼續(xù)調(diào)用__down_common。
__down_common 函數(shù)定義如下:
static inline int __sched __down_common(struct semaphore *sem, longstate,
longtimeout)
{
struct task_struct *task= current;
struct semaphore_waiterwaiter;
list_add_tail(&waiter.list,&sem->wait_list);
waiter.task = task;
waiter.up = 0;
for (;;) {
if(signal_pending_state(state, task))
gotointerrupted;
if (timeout <=0)
gototimed_out;
__set_task_state(task,state);
spin_unlock_irq(&sem->lock);
timeout =schedule_timeout(timeout);
spin_lock_irq(&sem->lock);
if (waiter.up)
return 0;
}
timed_out:
list_del(&waiter.list);
return -ETIME;
interrupted:
list_del(&waiter.list);
return -EINTR;
}
函數(shù)分析:在__down_common函數(shù)數(shù)執(zhí)行了以下操作。
(1)將當(dāng)前進(jìn)程放到信號量成員變量wait_list所管理的隊列中。
(2)在一個for循環(huán)中把當(dāng)前的進(jìn)程狀態(tài)這是為TASK_INTERRUPTIBLE,在調(diào)用schedule_timeout使當(dāng)前進(jìn)程進(jìn)入睡眠狀態(tài),函數(shù)將停留在schedule_timeout調(diào)用上,知道再次被調(diào)度執(zhí)行。
(3) 當(dāng)該進(jìn)程再一次被調(diào)度時,按原因執(zhí)行相應(yīng)的操作:如果waiter.up不為0說明進(jìn)程被該信號量的up操作所喚醒,進(jìn)程可以獲得信號量。如果進(jìn)程是因為被用戶空間的信號所中斷或超時信號所引起的喚醒,則返回相應(yīng)的錯誤代碼。
UP操作:LINUX內(nèi)核只提供了一個up函數(shù)
up函數(shù)定義如下:
void up(struct semaphore *sem)
{
unsigned long flags;
spin_lock_irqsave(&sem->lock,flags);
if(likely(list_empty(&sem->wait_list)))
sem->count++;
else
__up(sem);
spin_unlock_irqrestore(&sem->lock,flags);
}
函數(shù)分析:如果sem的wait_list隊列為空,則表明沒有其他進(jìn)程正在等待該信號量,那么只需要把sem的count加1即可。如果wait_list隊列不為空,則說明有其他進(jìn)程正睡眠在wait_list上等待該信號,此時調(diào)用__up(sem)來喚醒進(jìn)程:
__up()函數(shù)定義如下:
static noinline void __sched __up(struct semaphore *sem)
{
struct semaphore_waiter*waiter = list_first_entry(&sem->wait_list,
structsemaphore_waiter, list);
list_del(&waiter->list);
waiter->up = 1;
wake_up_process(waiter->task);
}
函數(shù)分析:在函數(shù)中,調(diào)用了wake_up_process來喚醒進(jìn)程,這樣進(jìn)程就從之前的__down_interruptible調(diào)用中的timeout=schedule_timeout(timeout)處醒來,wait-up=1, __down_interruptible返回0,進(jìn)程獲得了信號量。
up()與down()函數(shù)之間的聯(lián)系:由上面對兩個函數(shù)的分析可以知道,__down_common函數(shù)中timeout=schedule_timeout(timeout) 有著很重要的作用。
-
Linux
+關(guān)注
關(guān)注
87文章
11329瀏覽量
209969 -
down
+關(guān)注
關(guān)注
0文章
5瀏覽量
9875 -
信號量
+關(guān)注
關(guān)注
0文章
53瀏覽量
8364
發(fā)布評論請先 登錄
相關(guān)推薦
評論