select 在內(nèi)核中大致實現(xiàn)的一個解說: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執(zhí)行對應(yīng)的poll操作,poll是file operation (fp)的一個函數(shù)指針,具體實現(xiàn)由指向的fp_poll函數(shù)實現(xiàn)。fp_poll的核心是調(diào)用poll_wait,poll_wait 把當(dāng)前進程掛到對應(yīng)fd的設(shè)備等待隊列,
具體是執(zhí)行:poll_table*p;p->_qproc 函數(shù), 這個_qproc 是指向 __pollwait 函數(shù) 。 這個函數(shù)才是真正意義上把 當(dāng)前進程掛到設(shè)備等待隊列里面,主要是 調(diào)用 add_wait_queue(wait_queue_head_t*q,wait_queue_t*wait),? 主要是把wait 加入到wait_queue_head_t里面。其中wait_queue_t 結(jié)構(gòu)體 包括 private (進程信息相關(guān)),wait_queue_func_t (進程喚醒后執(zhí)行的回調(diào)函數(shù),一般由設(shè)備驅(qū)動程序的中斷程序執(zhí)行)。
當(dāng)把所有的fd和對應(yīng)的進程都掛到對應(yīng)的等待隊列后,再檢查一下fd有沒相關(guān)的事件,沒有的話,如果沒有信號中斷的情況下,調(diào)用 poll_schedule_timeout 函數(shù) 進程就會進入休眠,等待喚醒狀態(tài)。
等待隊列的 等待/喚醒:
等待:
等待其實就是把對應(yīng)的進程信息、喚醒回調(diào)函數(shù)? 包裝進入 wati_queue_t 結(jié)構(gòu)體, 然后再由 add_wait_queue 函數(shù)把 wait_queue_t 添加到 wait_queue_head_t 里面, wait_queue_head_t 是個鏈表結(jié)構(gòu),用來管理wait_queue_t 單元的。
具體底層操作主要是:wait_event_interruptible 函數(shù)實現(xiàn),這個函數(shù)會調(diào)用 prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); 通過__add_wait_queue把相關(guān)的wait 添加到 wait_queue_head_t , 并且把進程的狀態(tài)置為:TASK_INTERRUPTIBLE 。
以上的操作并不會使進程進入休眠,只把進程掛入等待隊列。
接著調(diào)用:schedule_timeout 函數(shù),使進程進入休眠,讓出CPU。
喚醒:
對于設(shè)備驅(qū)動來講,通常是在中斷處理函數(shù)內(nèi)喚醒該設(shè)備的等待隊列。__wake_up(wait_queue_head_t *q, unsignedintmode,intnr_exclusive,void*key) 函數(shù) 會被中斷程序執(zhí)行,此函數(shù)調(diào)用 __wake_up_common ,遍歷 傳進來的 wait_queue_head_t , 依次執(zhí)行 wait_queue_t 對應(yīng)的喚醒回調(diào)函數(shù),。
最后 從喚醒函數(shù)執(zhí)行后,finish_wait 函數(shù)會被調(diào)用,清理相關(guān)的信息和資源(從等待隊列刪除之類的),然后把進程狀態(tài)置為:TASK_RUNNING