Android 筆記-Linux Kernel SMP (Symmetric Multi-Processors) 開機流程解析 Part(4) Linux 多核心啟動流程-kthreadd 與相關的核

本文详细介绍了Linux内核2.6版本引入的kthreadd任务,它是通过kthread_create机制产生Kernel Thread的父任务。kthreadd负责检查kthread_create_list队列并创建所需的任务。同时,文章提到了kthreadd与kernel_thread的区别,并列举了一些基于kthread创建的内核任务,如文件系统Journaling、中断BottomHalf、Kernel USB-Hub等。
摘要由CSDN通过智能技术生成

Android 筆記-LinuxKernel SMP (Symmetric Multi-Processors) 開機流程解析 Part(4)Linux 多核心啟動流程-kthreadd與相關的核心模組


by  loda

hlchou@mail2000.com.tw

Loda's Blog

App BizOrz

Android/Linux Source Code Tags
App BizOrz 
BizOrz.COM 
BizOrz Blog


kthread第一次出現在LinuxKernel中是在Kernel版本2.6.4,一開始的實作尚未有本文提到的kthreaddTask的具體架構,隨著版本的演進,除了這部份的設計完整外,需要產生KernelThread的實作也都已經改用kthread機制.


本文會先針對kthreaddTask行為加以說明,並會以在啟動後,屬於KernelMode產生的KernelThread的個別行為與功能做一個介紹,由於這部份涉及的範圍不少,筆者會以自己的角度選擇認為值得加以說明的項目,相信應該足以涵蓋大多數人對於LinuxKernel Mode Tasks所需的範圍.如果有所不足之處,也請透過LinuxKernel Hacking加以探索.


簡要來說,位於KernelModeTasks產生,除了直接透過kernel_thread函式外,還可以有兩個來源,一個是透過kthread_create(實作上,也是透過函式Kernel_Thread)產生的KernelThread,另一個則是透過WorkQueue機制產生的KernelThread,前者可以依據設計者自己對系統架構的掌握,去設計多工機制(例如,使用稍後提到的LinkedList Queue).而後者,則是由LinuxKernel提供延遲處理工作的機制,讓每個核心的Tasks可以透過WorkQueue機制把要延遲處理/指定處理器/指定延遲時間的工作,交派給WorkQueue.


在實際的應用上,WorkQueue還可以用以實現中斷的BottomHalf機制,讓中斷觸發時對Timing要求高的部分(TopHalf)可以在InterruptHandler中盡快執行完畢,透過WorkQueue把需要較長時間執行的部分(BottomHalf)交由WorkQueue延遲執行實現.(等同於RTOS下的LISR/HISR).


LinuxKernel的基礎Tasks.


LinuxKernel中有三個最基礎的Tasks,分別為PID=0IdleTask,PID=1負責初始化所有使用者環境與行程的init Task,PID=2負責產生KernelMode行程的kthreaddTask.


其中,IdleTask主要用來在系統沒有其他工作執行時,可以執行省電機制(PMIdle)或透過IdleMigration把多核心其它處理器上的工作進行重分配(LoadBalance),讓處於Idle的處理器可以分擔Task工作,充分利用系統運算資源.


initTask是所有UserMode Tasks的父行程,包含啟動時的ShellScript執行,或是載入必要的應用程式,都會基於initTask的執行來實現.


再來就是本文主要談的kthreaddTask,這是在LinuxKernel 2.6所引入的機制,在這之前要產生KernelThread需直接使用函式kernel_thread,而所產生的KernelThread父行程會是當下產生KernelThread的行程(或該父行程結束後,改為initTask(PID=1)).kthreadd的機制下,UserModeKernelMode Task的產生方式做了調整,並讓kthreaddTask成為使用kthread_create產生的KernelThread統一的父行程.也因此,在這機制實現下的LinuxKernel,屬於UserMode行程最上層的父行程為initTask (PID=1),而屬於KernelMode行程最上層的父行程為kthreaddTask (PID=2),而這兩個行程共同的父行程就是idle Task (PID=0).



kthreadd



kthreaddKernel Thread主要實作在檔案kernel/kthread.c,入口函式為kthreadd(宣告為intkthreadd(void *unused) ),主要負責的工作是檢視目前LinkedList Queue "kthread_create_list"是否有要產生KernelThread的需求,若有,就呼叫函式create_kthread進行後續的產生工作.而要透過kthreadd產生KernelThread需求,就可以透過呼叫kthread_create(與其他衍生的kthread函式,ex:kthread_create_on_node....etc.)把需求加入到LinkedList Queue "kthread_create_list",WakeUpkthreadd Task,就可以使用目前kthreadd新設計的機制.


有關函式kthreadd內部的運作流程,概述如下


1,執行set_task_comm(tsk,"kthreadd"),設定Task的執行檔名稱,會把"kthreadd"複製給task_struct中的comm (structtask_struct宣告在include/linux/sched.h).

2,執行ignore_signals(tsk),其中tsk= current,會設定讓Taskkthreadd忽略所有的Signals

3,設定kthreadd可以在所有處理器上執行.

4,進入kthreaddfor(;;)無窮迴圈,

4-1,透過函式list_empty確認kthread_create_list是否為空,若為空,就觸發Task排程

4-2,透過list_entry,取出要產生的KernelThread的”structkthread_create_info” Pointer

4-3,呼叫create_kthread產生KernelThread.

4-3-1,create_kthread中會以"pid= kernel_thread(kthread, create, CLONE_FS | CLONE_FILES |SIGCHLD);"呼叫函式kernel_thread(inarch/arm/kernel/process.c),其中,入口函式為kthread,新產生的Task的第一個函式參數為create.

4-3-1-1,在函式kernel_thread,會執行如下的程式碼,把最後新產生的KernelThread入口函式指給新Task的暫存器r5,要傳遞給該入口函式的變數只給暫存器r4,而該入口函式結束時要返回的函式kernel_thread_exit位址指給暫存器r7,並透過透過do_fork產生新的行程時,暫存器PC(Program Counter)指向函式kernel_thread_helper.也就是說每一個KernelThread的第一個函式統一都是kernel_thread_helper,而結束函式統一都為kernel_thread_exit.函式kernel_thread的參考程式碼如下所示

/*

*Create a kernel thread.

*/

pid_tkernel_thread(int (*fn)(void *), void *arg, unsigned long flags)

{

structpt_regs regs;

memset(&regs,0, sizeof(regs));

regs.ARM_r4= (unsigned long)arg;

regs.ARM_r5= (unsigned long)fn;

regs.ARM_r6= (unsigned long)kernel_thread_exit;

regs.ARM_r7= SVC_MODE | PSR_ENDSTATE | PSR_ISETSTATE;

regs.ARM_pc= (unsigned long)kernel_thread_helper;

regs.ARM_cpsr= regs.ARM_r7 | PSR_I_BIT;

returndo_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);

}


產生的Task會執行函式kernel_thread_helper,並把結束函式由暫存器r6指給暫存器LR(LinkerRegister),把入口函式的第一個參數指給暫存器r0,Task的入口函式由暫存器r5指給暫存器PC,開始新Task的執行.有關函式kernel_thread_helper的參考程式碼如下所示


externvoid kernel_thread_helper(void);

asm( ".pushsection .text\n"

" .align\n"

" .type kernel_thread_helper, #function\n"

"kernel_thread_helper:\n"

#ifdefCONFIG_TRACE_IRQFLAGS

" bl trace_hardirqs_on\n"

#endif

" msr cpsr_c, r7\n"

" mov r0, r4\n"

" mov lr, r6\n"

" mov pc, r5\n"

" .size kernel_thread_helper, . - kernel_thread_helper\n"

" .popsection");


由於新Task的入口函式統一為"kthread",第一個函式參數統一為”structkthread_create_info*create”,檢視函式kthread的實作,可以看到在新行程由kernel_thread_helper呼叫進入kthread,就會執行函式參數create中的create->threadfn函式指標,執行其他應用透過kthread_create產生KernelThread時的最終函式入口,參考代碼如下所示


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值