信号量机制中的down和up函数
轉自:https://blog.csdn.net/fzubbsc/article/details/37737159
參考:
https://blog.csdn.net/liuxd3000/article/details/17913363
http://blog.chinaunix.net/uid-25845340-id-3017214.html?
https://blog.csdn.net/xiao229404041/article/details/7031776
查閱文件:
kernel\linux\linux-4.4.3\kernel\locking\semaphore.c
kernel\linux\linux-4.4.3\include\linux\semaphore.h
DOWN操作:linux內核中,對信號量的DOWN操作有如下幾種:
1、void down(struct semaphore *sem); //不可中斷
down接口用于請求一個信號量。此函數的調用將會到致調用線程的睡眠,??直到獲取到信號。同時,該函數的調用不允許中斷。
在此函數中首先進行信號量資源數的查看,如果信號量數據(count)不為0,則把其減1,并返回,調用成功;否則調用__down進行等待,調用者進行睡眠。
2、int down_interruptible(struct semaphore *sem);//可中斷
該函數功能和down類似,不同之處為,down不會被信號(signal)打斷,但down_interruptible能被信號打斷,因此該函數有返回值來區分是正常返回還是被信號中斷,如果返回0,表示獲得信號量正常返回,如果被信號打斷,返回-EINTR。
?
3、int down_killable(struct semaphore *sem);//睡眠的進程可以因為受到致命信號而被喚醒,中斷獲取信號量的操作。
down_killable與down_interruptible相近,最終傳入的__down_common的實參有所不同(TASK_KILLABLE和TASK_INTERRUPTIBLE),所以,在此不再進行分析。
4、int down_trylock(struct semaphore *sem);//試圖獲取信號量,若無法獲得則直接返回1而不睡眠。返回0則 表示獲取到了信號量
down_trylock接口用于試著獲取一個信號量,但是,此接口不會引起調用者的睡眠。不管有無可用信號量,都馬上進行返回,如果返回0,則獲取信號量成功,如果返回1,則獲取失敗。所以,在調用此接口時,必須進行返回的值的查看,看是否獲取成功。
5、int down_timeout(struct semaphore *sem,long jiffies);//表示睡眠時間是有限制的,如果在jiffies指明的時間到期時仍然無法獲得信號量,則將返回錯誤碼。
down_timeout接口的實現過程與down接口的實現過程差不多,只是此接口?可以自定義超時時間,也就是如果在超時間內不能得到信號量,調用者會因為超時而自行喚醒。其實現過程如下,請注意超時參數的傳入。其中TASK_UNINTERRUPTIBLE
在以上五種函數中,驅動程序使用的最頻繁的就是down_interruptible函數,以下將對該函數進行分析。
down_interruptible函數的定義如下:
函數分析:函數首先通過spin_lock_irqsave的調用來保證對sem->count操作的原子性。如果count>0,表示當前進程可以獲得信號量,將count的值減1然后退出。如果count不大于0,表明當前進程無法獲取信號量,則調用__down_interruptible,后者會繼續調用__down_common。
__down_common 函數定義如下:
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;}函數分析:在__down_common函數數執行了以下操作。
(1)將當前進程放到信號量成員變量wait_list所管理的隊列中。
(2)在一個for循環中把當前的進程狀態這是為TASK_INTERRUPTIBLE,在調用schedule_timeout使當前進程進入睡眠狀態,函數將停留在schedule_timeout調用上,知道再次被調度執行。
(3) 當該進程再一次被調度時,按原因執行相應的操作:如果waiter.up不為0說明進程被該信號量的up操作所喚醒,進程可以獲得信號量。如果進程是因為被用戶空間的信號所中斷或超時信號所引起的喚醒,則返回相應的錯誤代碼。?
UP操作:LINUX內核只提供了一個up函數
up函數定義如下:
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);}函數分析:如果sem的wait_list隊列為空,則表明沒有其他進程正在等待該信號量,那么只需要把sem的count加1即可。如果wait_list隊列不為空,則說明有其他進程正睡眠在wait_list上等待該信號,此時調用__up(sem)來喚醒進程:
__up()函數定義如下:
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);}函數分析:在函數中,調用了wake_up_process來喚醒進程,這樣進程就從之前的__down_interruptible調用中的timeout=schedule_timeout(timeout)處醒來,wait-up=1, __down_interruptible返回0,進程獲得了信號量。
up()與down()函數之間的聯系:由上面對兩個函數的分析可以知道,__down_common函數中timeout=schedule_timeout(timeout) 有著很重要的作用。
Note:一個進程在調用down_interruptible()之后,如果sem<0,那么就進入到可中斷的睡眠狀態并調度其它進程運行, 但是一旦該進程收到信號,那么就會從down_interruptible函數中返回。并標記錯誤號為:-EINTR。一個形象的比喻:傳入的信號量為1好比天亮,如果當前信號量為0,進程睡眠,直到(信號量為1)天亮才醒,但是可能中途有個鬧鈴(信號)把你鬧醒。又如:小強下午放學回家,回家了就要開始吃飯嘛,這時就會有兩種情況:情況一:飯做好了,可以開始吃;情況二:當他到廚房去的時候發現媽媽還在做,媽媽就對他說:“你先去睡會,待會做好了叫你。”小強就答應去睡會,不過又說了一句:“睡的這段時間要是小紅來找我玩,你可以叫醒我。”小強就是down_interruptible,想吃飯就是獲取信號量,睡覺對應這里的休眠,而小紅來找我玩就是中斷休眠。
使用可被中斷的信號量版本的意思是,萬一出現了semaphore的死鎖,還有機會用ctrl+c發出軟中斷,讓等待這個內核驅動返回的用戶態進程退出。而不是把整個系統都鎖住了。在休眠時,能被中斷信號終止,這個進程是可以接受中斷信號的!比如你在命令行中輸入# sleep 10000,按下ctrl + c,就給上面的進程發送了進程終止信號。信號發送給用戶空間,然后通過系統調用,會把這個信號傳給遞給驅動。信號只能發送給用戶空間,無權直接發送給內核的,那1G的內核空間,我們是無法直接去操作的。 --------------------- 本文來自 liuxd3000 的CSDN 博客 ,全文地址請點擊:https://blog.csdn.net/liuxd3000/article/details/17913363?utm_source=copy
總結
以上是生活随笔為你收集整理的信号量机制中的down和up函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 智能打印SDK---官方博客
- 下一篇: 【网易】字符迷阵