select 在內核中大致實現的一個解說:http://janfan.github.io/chinese/2015/01/05/select-poll-impl-inside-the-kernel.html
等待隊列的一些理解:http://www.cnblogs.com/zhuyp1015/archive/2012/06/09/2542894.html
do_select => poll =>fp_poll.
do_select 會對每個fd執行對應的poll操作,poll是file operation (fp)的一個函數指針,具體實現由指向的fp_poll函數實現。fp_poll的核心是調用poll_wait,poll_wait 把當前進程掛到對應fd的設備等待隊列,
具體是執行:poll_table*p;p->_qproc 函數, 這個_qproc 是指向 __pollwait 函數 。 這個函數才是真正意義上把 當前進程掛到設備等待隊列里面,主要是 調用 add_wait_queue(wait_queue_head_t*q,wait_queue_t*wait),? 主要是把wait 加入到wait_queue_head_t里面。其中wait_queue_t 結構體 包括 private (進程信息相關),wait_queue_func_t (進程喚醒后執行的回調函數,一般由設備驅動程序的中斷程序執行)。
當把所有的fd和對應的進程都掛到對應的等待隊列后,再檢查一下fd有沒相關的事件,沒有的話,如果沒有信號中斷的情況下,調用 poll_schedule_timeout 函數 進程就會進入休眠,等待喚醒狀態。
等待隊列的 等待/喚醒:
等待:
等待其實就是把對應的進程信息、喚醒回調函數? 包裝進入 wati_queue_t 結構體, 然后再由 add_wait_queue 函數把 wait_queue_t 添加到 wait_queue_head_t 里面, wait_queue_head_t 是個鏈表結構,用來管理wait_queue_t 單元的。
具體底層操作主要是:wait_event_interruptible 函數實現,這個函數會調用 prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); 通過__add_wait_queue把相關的wait 添加到 wait_queue_head_t , 并且把進程的狀態置為:TASK_INTERRUPTIBLE 。
以上的操作并不會使進程進入休眠,只把進程掛入等待隊列。
接著調用:schedule_timeout 函數,使進程進入休眠,讓出CPU。
喚醒:
對于設備驅動來講,通常是在中斷處理函數內喚醒該設備的等待隊列。__wake_up(wait_queue_head_t *q, unsignedintmode,intnr_exclusive,void*key) 函數 會被中斷程序執行,此函數調用 __wake_up_common ,遍歷 傳進來的 wait_queue_head_t , 依次執行 wait_queue_t 對應的喚醒回調函數,。
最后 從喚醒函數執行后,finish_wait 函數會被調用,清理相關的信息和資源(從等待隊列刪除之類的),然后把進程狀態置為:TASK_RUNNING