目錄
一、linux的2號程序
二、kthreadd程序的建立
三、kthreadd程序執行體
四、create_kthread函式
五、小結
說起linux程序,學習linux系統的大部分人都知道1號程序為init程序,人們就是這樣只記得第一,卻很少人記得第二。(經典問題:第乙個太空飛行員是加加林,第二呢? 世界最高峰為珠穆朗瑪峰,第
二、第三、第四呢?…經典翻車問題)。下面直接看看2號程序:
uid pid ppid c stime tty time cmd
root 1 0 0 11月21 ? 00:00:17/sbin/initsplash
root 2 0 0 11月21 ? 00:00:00[kthreadd]
root 3 2 0 11月21 ? 00:00:00 [rcu_gp]
root 4 2 0 11月21 ? 00:00:00 [rcu_par_gp]
root 6 2 0 11月21 ? 00:00:00 [kworker/0:0h-kb]
root 10 2 0 11月21 ? 00:00:15 [ksoftirqd/0]
root 24 2 0 11月21 ? 00:00:00 [khugepaged]
root 71 2 0 11月21 ? 00:00:00 [kblockd]
root 78 2 0 11月21 ? 00:00:00 [watchdogd]
root 138 2 0 11月21 ? 00:00:00 [kworker/u257:0]
root 151 2 0 11月21 ? 00:00:00 [charger_manager]
root 228 2 0 11月21 ? 00:00:01 [irq/16-vmwgfx]
root 229 2 0 11月21 ? 00:00:00 [scsi_tmf_7]
root 230 2 0 11月21 ? 00:00:00 [ttm_swap]
是的,kthreadd就是linux的2號程序,這個程序在linux核心中非常的重要,他是其他核心執行緒的父程序或者祖先程序(這個可以通過上面的ppid為2的程序可以看出,這些重要執行緒包括kworker、kblockd、khugepaged…),下面便慢慢來介紹下kthreadd程序。
核心中的其他執行緒ppid都是2, 說明這些執行緒都是由kthreadd程序建立的,因此可以說kthreadd程序負責核心執行緒的建立、維護等工作,是其他執行緒的基礎。實際上也確實如此,kthreadd就是專門負責核心執行緒管理工作的。
static noinline void __refrest_init(void)
/*linux-4.19*/
由於linux-2.6.12版本中rest_init函式中只建立了init程序,而kthreadd程序的建立我沒有找到,因此這裡引用了linux-4.19版本中的rest_init函式部分**。這個版本中清楚的顯示了建立init程序和kthreadd程序。
建立完畢後,linux系統需要借助ktheadd程序實現騰飛,因此在這裡等待kthreadd程序建立完畢。
在建立執行緒時,是需要傳遞執行緒執行函式的,從rest_init()中使用kernel_thread建立執行緒可知kthreadd執行緒執行體是kthreadd()函式。
int kthreadd(void *unused)
spin_unlock(&kthread_create_lock);/*去鎖*/
} return 0;
}
從上述**中可以看出:kthreadd
程序的任務就是等待建立執行緒,如果任務隊列為空,則執行緒主動讓出
cpu(呼叫
schedule
後會讓出
cpu,
本執行緒會睡眠):如果不為空,則依次從任務佇列中取出任務,然後建立相應的執行緒。如此往復,直到永遠…
在create_kthread函式中會通過呼叫kernel_thread函式來建立新程序,且新程序的執行函式為kthread(所有經過
kthreadd
程序建立的程序執行體都為
kthead, 看名字有點暈哈…)。
static void create_kthread(struct kthread_create_info *create)
create->result = err_ptr(pid);
complete(done);
}}
kernel_thread介面剛才在rest_init介面中遇到過,核心就是通過kernel_thread介面建立的init程序和kthreadd程序。這裡再次使用它建立新執行緒,新的執行緒執行體統一為kthead。下面我們看看kthread函式的內容:
static int kthread(void *_create)
if (!self)
self->data = data;
init_completion(&self->exited);
init_completion(&self->parked);
current->vfork_done = &self->exited;
/* ok, tell user we're spawned, wait for stop or wakeup */
__set_current_state(task_uninterruptible);
create->result = current;
complete(done);
schedule();/*睡眠,一直。直到被喚醒*/
ret = -eintr;
if (!test_bit(kthread_should_stop, &self->flags))
do_exit(ret);
}
從kthread函式可以看出,新執行緒建立成功後,會一直睡眠(使用schedule主動讓出cpu並睡眠),直到有人喚醒它(wake_up_process);執行緒被喚醒後,並且不需要stop, 則執行指定的函式體( threadfn(data) )。
我使用一幅圖來簡單的描述下核心中kthreadd的工作流程:
上圖中顯示了核心建立執行緒的基本流程:
①某乙個執行緒a(左上那個圈)呼叫kthread_create函式來建立新執行緒,呼叫後阻塞;kthread_create會將任務封裝後新增到kthreadd監控的工作佇列中;
②kthreadd程序檢測到工作佇列中有任務,則結束休眠狀態,通過呼叫create_kthread函式建立執行緒,最後呼叫到kernel_thread--> do_fork來建立執行緒,且新執行緒執行體為kthead
③新執行緒建立成功後,執行kthead,kthreadd執行緒則繼續睡眠等待建立新程序;
④執行緒a呼叫kthread_create返回後,在合適的時候通過wake_up_process(pid)來喚醒新建立的執行緒
⑤新建立的執行緒在kthead執行體中被喚醒,檢測到是否需要stop,在不需要stop時,執行使用者指定的執行緒執行體。(執行緒執行體發生了變化:先執行預設的kthead,然後才是使用者指定的threadfn,當然也可能直接執行do_exit退出執行緒)
linux 核心學習(2)
linux核心原始碼樹大體結構 由於linux的原 持續在變化,所以不可能給出太詳細的內容,只能指出乙個特殊的驅動大概會出現在什麼地方。makefile 這是整個的原始碼樹的最頂層的makefile。它定義了很多的有用的變數和規則,如預設的gcc編譯標誌。arch 所有的特殊的體系結構的 都在這個目...
linux核心學習筆記2
選擇符用來查詢段描述符的,其中有一位會標明是去全域性描述符表中查詢還是去區域性描述符表中查詢。實模式下 直接在段暫存器中存放段基位址。每乙個段暫存器 即選擇符 都有乙個高速緩衝暫存器,為了加快訪問速度。為了避免每次儲存器訪問時,都要訪問描述符表,讀取描述符並對段進行解碼得到描述符本身的各種資訊,每個...
筆記 Linux核心學習 三 之程序排程
程序排程 在可執行態程序之間分配有限處理器時間資源的核心子系統。1程序型別 i o消耗型程序 大部分時間用來提交i o請求或是等待i o請求,經常處於可執行狀態,但執行時間短,等待請求過程時處於阻塞狀態。如互動式程式。處理器消耗型程序 時間大都用在執行 上,除非被搶占否則一直不停的執行。綜合型 既是...