kthread_run创建内核线程的原理
生活随笔
收集整理的這篇文章主要介紹了
kthread_run创建内核线程的原理
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
kthread_run是一個(gè)宏,用來創(chuàng)建一個(gè)進(jìn)程,并且將其喚醒,其定義在頭文件include/linux/kthread.h中.
#define kthread_run(threadfn, data, namefmt, ...)?? ??? ??? ??? \
({?? ??? ??? ??? ??? ??? ??? ??? ??? ??? \
?? ?struct task_struct *__k?? ??? ??? ??? ??? ??? ??? \
?? ??? ?= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
?? ?if (!IS_ERR(__k))?? ??? ??? ??? ??? ??? ??? \
?? ??? ?wake_up_process(__k);?? ??? ??? ??? ??? ??? \
?? ?__k;?? ??? ??? ??? ??? ??? ??? ??? ??? \
})
?? ?先來看看這個(gè)宏的參數(shù),threadfn是該線程的執(zhí)行函數(shù),data是執(zhí)行函數(shù)的傳入?yún)?shù),namefmt是該線程的printf風(fēng)格的線程名,最后的...類似printf的可變參數(shù)列表.從這個(gè)宏的實(shí)現(xiàn)可以看出kthread_run是通過kthread_create來創(chuàng)建一個(gè)進(jìn)程,并返回一個(gè)task_struct,然后使用wake_up_process函數(shù)將新創(chuàng)建的進(jìn)程喚醒.下面需要關(guān)注一下kthread_create的實(shí)現(xiàn),其實(shí)它也是一個(gè)宏,同樣也定義在頭文件include/linux/kthread.h中.
#define kthread_create(threadfn, data, namefmt, arg...) \
?? ?kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
?? ?該宏的參數(shù)同kthread_run,不解釋了,其實(shí)現(xiàn)就是調(diào)用了函數(shù)kthread_create_on_node,下面來看該函數(shù)的實(shí)現(xiàn).
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
?? ??? ??? ??? ??? ??? void *data, int node,
?? ??? ??? ??? ??? ??? const char namefmt[],
?? ??? ??? ??? ??? ??? ...)
{
?? ?DECLARE_COMPLETION_ONSTACK(done);
?? ?struct task_struct *task;
?? ?struct kthread_create_info *create = kmalloc(sizeof(*create), GFP_KERNEL);
?? ?if (!create)
?? ??? ?return ERR_PTR(-ENOMEM);
?? ?create->threadfn = threadfn;//線程執(zhí)行函數(shù)
?? ?create->data = data;//線程執(zhí)行函數(shù)的參數(shù)
?? ?create->node = node;//NUMA系統(tǒng)上會(huì)用到,這里不介紹.
?? ?create->done = &done;//completion結(jié)構(gòu),一會(huì)兒會(huì)通過它判斷該線程的創(chuàng)建是否完成.
?? ?spin_lock(&kthread_create_lock);
?? ?list_add_tail(&create->list, &kthread_create_list);
?? ?spin_unlock(&kthread_create_lock);
?? ?wake_up_process(kthreadd_task);//喚醒kthreadd_task內(nèi)核線程.
?? ?if (unlikely(wait_for_completion_killable(&done))) {//進(jìn)入睡眠,等待線程創(chuàng)建的完成.
?? ??? ?if (xchg(&create->done, NULL))
?? ??? ??? ?return ERR_PTR(-EINTR);
?? ??? ?wait_for_completion(&done);
?? ?}
?? ?task = create->result;
?? ?if (!IS_ERR(task)) {
?? ??? ?static const struct sched_param param = { .sched_priority = 0 };
?? ??? ?va_list args;
?? ??? ?va_start(args, namefmt);
?? ??? ?vsnprintf(task->comm, sizeof(task->comm), namefmt, args);//設(shè)置線程名字
?? ??? ?va_end(args);
?? ?
?? ??? ?sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m);
?? ??? ?set_cpus_allowed_ptr(task, cpu_all_mask);
?? ?}
?? ?kfree(create);
?? ?return task;
}
?? ?該函數(shù)首先創(chuàng)建一個(gè)kthread_create_info結(jié)構(gòu),該結(jié)構(gòu)封裝了要?jiǎng)?chuàng)建的內(nèi)核進(jìn)程所需要的信息,然后將該結(jié)構(gòu)添加到鏈表kthread_create_list的末尾,接著該函數(shù)調(diào)用wake_up_process函數(shù)喚醒kthreadd_task所表示的內(nèi)核線程,然后調(diào)用wait_for_completion系列的函數(shù)使當(dāng)前進(jìn)程進(jìn)入睡眠狀態(tài),在這里我們可以猜想kthreadd_task表示的內(nèi)核線程應(yīng)該會(huì)從鏈表kthread_create_list中依次的取下每個(gè)節(jié)點(diǎn)根據(jù)對(duì)應(yīng)的kthread_create_info結(jié)構(gòu)中的線程信息來創(chuàng)建內(nèi)核線程,然后通過completion函數(shù)喚醒當(dāng)前線程,這時(shí)kthread_create_info中的result應(yīng)該已經(jīng)被賦值為剛創(chuàng)建的內(nèi)核線程的task_struct結(jié)構(gòu)了,kthread_create_on_node函數(shù)會(huì)檢查該task_struct結(jié)構(gòu),判斷內(nèi)核線程創(chuàng)建是否成功,如果成功,會(huì)進(jìn)一步設(shè)置線程task的名稱,以及調(diào)度器,最后返回新創(chuàng)建的task_struct結(jié)構(gòu)體.
?? ?剛才猜想了kthreadd_task表示的內(nèi)核線程的作用是從鏈表kthread_create_list上依次的取下kthread_create_info結(jié)構(gòu),然后創(chuàng)建相應(yīng)的內(nèi)核線程.現(xiàn)在來驗(yàn)證這個(gè)猜想.在內(nèi)核源碼中搜索kthreadd_task,會(huì)在init/main.c文件中找到為kthreadd_task賦值的地方.在函數(shù)rest_init中.
static noinline void __init_refok rest_init(void)
{
?? ?int pid;
?? ?rcu_scheduler_starting();
?? ?
?? ?kernel_thread(kernel_init, NULL, CLONE_FS);
?? ?numa_default_policy();
?? ?pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
?? ?rcu_read_lock();
?? ?kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
?? ?rcu_read_unlock();
?? ?complete(&kthreadd_done);
?? ?
?? ?......
}
?? ?rest_init算是kernel再啟動(dòng)函數(shù)start_kernel中執(zhí)行的最后一個(gè)函數(shù),kthreadd_task表示的內(nèi)核線程就是在這里創(chuàng)建的,這行代碼kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns)是通過pid來查找其對(duì)應(yīng)的task_struct的結(jié)構(gòu)體,再看pid是上面的這行代碼產(chǎn)生的pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES),kernel_thread函數(shù)是通過do_fork來創(chuàng)建線程的,然后返回該線程的pid,從這里可以看出kthreadd_task表示的內(nèi)核線程的執(zhí)行函數(shù)是kthreadd,下面來看這個(gè)函數(shù)的實(shí)現(xiàn).
int kthreadd(void *unused)
{
?? ?struct task_struct *tsk = current;
?? ?......
?? ?for (;;) {
?? ??? ?set_current_state(TASK_INTERRUPTIBLE);
?? ??? ?if (list_empty(&kthread_create_list))
?? ??? ??? ?schedule();
?? ??? ?__set_current_state(TASK_RUNNING);
?? ??? ?spin_lock(&kthread_create_lock);
?? ??? ?while (!list_empty(&kthread_create_list)) {
?? ??? ??? ?struct kthread_create_info *create;
?? ??? ??? ?create = list_entry(kthread_create_list.next, struct kthread_create_info, list);
?? ??? ??? ?list_del_init(&create->list);
?? ??? ??? ?spin_unlock(&kthread_create_lock);
?? ??? ??? ?create_kthread(create);
?? ??? ??? ?spin_lock(&kthread_create_lock);
?? ??? ?}
?? ??? ?spin_unlock(&kthread_create_lock);
?? ?}
?? ?return 0;
}
?? ?可以看出這個(gè)函數(shù)的主體是一個(gè)for循環(huán),重點(diǎn)是其中的那個(gè)while循環(huán),很明顯是在遍歷鏈表kthread_create_list,獲取將其上面的每個(gè)節(jié)點(diǎn)所表示的kthread_create_info結(jié)構(gòu),然后將該結(jié)構(gòu)傳遞給函數(shù)create_kthread,顧名思義,該函數(shù)就是來創(chuàng)建線程的,下面看看create_kthread的代碼.
static void create_kthread(struct kthread_create_info *create)
{
?? ?int pid;
?? ?......
?? ?pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
?? ?if (pid < 0) {//線程如果創(chuàng)建失敗,下面的代碼是錯(cuò)誤處理,不是重點(diǎn)
?? ??? ?/* If user was SIGKILLed, I release the structure. */
?? ??? ?struct completion *done = xchg(&create->done, NULL);
?? ??? ?if (!done) {
?? ??? ??? ?kfree(create);
?? ??? ??? ?return;
?? ??? ?}
?? ??? ?create->result = ERR_PTR(pid);
?? ??? ?complete(done);
?? ?}
}
該函數(shù)調(diào)用了kernel_thread函數(shù)創(chuàng)建了一個(gè)以kthread函數(shù)為線程執(zhí)行函數(shù),以kthread_create_info結(jié)構(gòu)為執(zhí)行函數(shù)參數(shù)的內(nèi)核線程,其實(shí)這個(gè)新創(chuàng)建的線程就是最終需要?jiǎng)?chuàng)建的那個(gè)內(nèi)核線程,那為什么執(zhí)行函數(shù)是kthread,而不是kthread_create_info結(jié)構(gòu)中指定的線程執(zhí)行函數(shù).看完kthread函數(shù)的實(shí)現(xiàn)就知道了.
static int kthread(void *_create)
{
?? ?struct kthread_create_info *create = _create;
?? ?int (*threadfn)(void *data) = create->threadfn;//獲取線程執(zhí)行函數(shù)賦值給函數(shù)指針threadfn
?? ?void *data = create->data;//線程執(zhí)行函數(shù)的參數(shù)
?? ?struct completion *done;
?? ?struct kthread self;
?? ?int ret;
?? ?......
?? ?
?? ?done = xchg(&create->done, NULL);可以理解為將create->done賦值給done
?? ?if (!done) {
?? ??? ?kfree(create);
?? ??? ?do_exit(-EINTR);
?? ?}
?? ?
?? ?__set_current_state(TASK_UNINTERRUPTIBLE);
?? ?create->result = current;//將該線程的task_struct結(jié)構(gòu)賦值給create->result
?? ?complete(done);//調(diào)用complete函數(shù)喚醒調(diào)用kthread_create_on_node的那個(gè)線程,通知它創(chuàng)建的線程已經(jīng)創(chuàng)建完畢.
?? ?schedule();//調(diào)用schedule交出處理器,給剛喚醒的調(diào)用kthread_create_on_node的線程以運(yùn)行的機(jī)會(huì),使其繼續(xù)執(zhí)行kthread_create_on_node函數(shù)剩下的代碼.
?? ?
?? ?//再次調(diào)度到該線程,從這里開始執(zhí)行.
?? ?ret = -EINTR;
?? ?if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {//判斷如果該線程沒有被停止掉.
?? ??? ?......
?? ??? ?ret = threadfn(data);//我們通過kthread_create_on_node函數(shù)傳遞進(jìn)來的線程執(zhí)行函數(shù)最終是在這個(gè)位置被執(zhí)行的.
?? ?}
?? ?do_exit(ret);
}
?? ?可以看出,如果在kthread函數(shù)調(diào)用schedule交出處理器和再次調(diào)度到該線程之間的這段時(shí)間里,在別的地方調(diào)用了kthread_stop函數(shù)停止了該函數(shù)的話,那么線程執(zhí)行函數(shù)是得不到執(zhí)行的,該線程就直接退出了.
?? ?以上就是通過kthread_run和kthread_create創(chuàng)建線程的整個(gè)過程.可以看出,它們并不直接創(chuàng)建線程,而是將要?jiǎng)?chuàng)建的線程的相關(guān)信息打包到kthread_create_info結(jié)構(gòu)中,然后委托給內(nèi)核線程kthreadd來做的,從函數(shù)kthreadd也可以看出,該線程的主要工作就是遍歷鏈表kthread_create_list創(chuàng)建線程.
#define kthread_run(threadfn, data, namefmt, ...)?? ??? ??? ??? \
({?? ??? ??? ??? ??? ??? ??? ??? ??? ??? \
?? ?struct task_struct *__k?? ??? ??? ??? ??? ??? ??? \
?? ??? ?= kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
?? ?if (!IS_ERR(__k))?? ??? ??? ??? ??? ??? ??? \
?? ??? ?wake_up_process(__k);?? ??? ??? ??? ??? ??? \
?? ?__k;?? ??? ??? ??? ??? ??? ??? ??? ??? \
})
?? ?先來看看這個(gè)宏的參數(shù),threadfn是該線程的執(zhí)行函數(shù),data是執(zhí)行函數(shù)的傳入?yún)?shù),namefmt是該線程的printf風(fēng)格的線程名,最后的...類似printf的可變參數(shù)列表.從這個(gè)宏的實(shí)現(xiàn)可以看出kthread_run是通過kthread_create來創(chuàng)建一個(gè)進(jìn)程,并返回一個(gè)task_struct,然后使用wake_up_process函數(shù)將新創(chuàng)建的進(jìn)程喚醒.下面需要關(guān)注一下kthread_create的實(shí)現(xiàn),其實(shí)它也是一個(gè)宏,同樣也定義在頭文件include/linux/kthread.h中.
#define kthread_create(threadfn, data, namefmt, arg...) \
?? ?kthread_create_on_node(threadfn, data, -1, namefmt, ##arg)
?? ?該宏的參數(shù)同kthread_run,不解釋了,其實(shí)現(xiàn)就是調(diào)用了函數(shù)kthread_create_on_node,下面來看該函數(shù)的實(shí)現(xiàn).
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
?? ??? ??? ??? ??? ??? void *data, int node,
?? ??? ??? ??? ??? ??? const char namefmt[],
?? ??? ??? ??? ??? ??? ...)
{
?? ?DECLARE_COMPLETION_ONSTACK(done);
?? ?struct task_struct *task;
?? ?struct kthread_create_info *create = kmalloc(sizeof(*create), GFP_KERNEL);
?? ?if (!create)
?? ??? ?return ERR_PTR(-ENOMEM);
?? ?create->threadfn = threadfn;//線程執(zhí)行函數(shù)
?? ?create->data = data;//線程執(zhí)行函數(shù)的參數(shù)
?? ?create->node = node;//NUMA系統(tǒng)上會(huì)用到,這里不介紹.
?? ?create->done = &done;//completion結(jié)構(gòu),一會(huì)兒會(huì)通過它判斷該線程的創(chuàng)建是否完成.
?? ?spin_lock(&kthread_create_lock);
?? ?list_add_tail(&create->list, &kthread_create_list);
?? ?spin_unlock(&kthread_create_lock);
?? ?wake_up_process(kthreadd_task);//喚醒kthreadd_task內(nèi)核線程.
?? ?if (unlikely(wait_for_completion_killable(&done))) {//進(jìn)入睡眠,等待線程創(chuàng)建的完成.
?? ??? ?if (xchg(&create->done, NULL))
?? ??? ??? ?return ERR_PTR(-EINTR);
?? ??? ?wait_for_completion(&done);
?? ?}
?? ?task = create->result;
?? ?if (!IS_ERR(task)) {
?? ??? ?static const struct sched_param param = { .sched_priority = 0 };
?? ??? ?va_list args;
?? ??? ?va_start(args, namefmt);
?? ??? ?vsnprintf(task->comm, sizeof(task->comm), namefmt, args);//設(shè)置線程名字
?? ??? ?va_end(args);
?? ?
?? ??? ?sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m);
?? ??? ?set_cpus_allowed_ptr(task, cpu_all_mask);
?? ?}
?? ?kfree(create);
?? ?return task;
}
?? ?該函數(shù)首先創(chuàng)建一個(gè)kthread_create_info結(jié)構(gòu),該結(jié)構(gòu)封裝了要?jiǎng)?chuàng)建的內(nèi)核進(jìn)程所需要的信息,然后將該結(jié)構(gòu)添加到鏈表kthread_create_list的末尾,接著該函數(shù)調(diào)用wake_up_process函數(shù)喚醒kthreadd_task所表示的內(nèi)核線程,然后調(diào)用wait_for_completion系列的函數(shù)使當(dāng)前進(jìn)程進(jìn)入睡眠狀態(tài),在這里我們可以猜想kthreadd_task表示的內(nèi)核線程應(yīng)該會(huì)從鏈表kthread_create_list中依次的取下每個(gè)節(jié)點(diǎn)根據(jù)對(duì)應(yīng)的kthread_create_info結(jié)構(gòu)中的線程信息來創(chuàng)建內(nèi)核線程,然后通過completion函數(shù)喚醒當(dāng)前線程,這時(shí)kthread_create_info中的result應(yīng)該已經(jīng)被賦值為剛創(chuàng)建的內(nèi)核線程的task_struct結(jié)構(gòu)了,kthread_create_on_node函數(shù)會(huì)檢查該task_struct結(jié)構(gòu),判斷內(nèi)核線程創(chuàng)建是否成功,如果成功,會(huì)進(jìn)一步設(shè)置線程task的名稱,以及調(diào)度器,最后返回新創(chuàng)建的task_struct結(jié)構(gòu)體.
?? ?剛才猜想了kthreadd_task表示的內(nèi)核線程的作用是從鏈表kthread_create_list上依次的取下kthread_create_info結(jié)構(gòu),然后創(chuàng)建相應(yīng)的內(nèi)核線程.現(xiàn)在來驗(yàn)證這個(gè)猜想.在內(nèi)核源碼中搜索kthreadd_task,會(huì)在init/main.c文件中找到為kthreadd_task賦值的地方.在函數(shù)rest_init中.
static noinline void __init_refok rest_init(void)
{
?? ?int pid;
?? ?rcu_scheduler_starting();
?? ?
?? ?kernel_thread(kernel_init, NULL, CLONE_FS);
?? ?numa_default_policy();
?? ?pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
?? ?rcu_read_lock();
?? ?kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
?? ?rcu_read_unlock();
?? ?complete(&kthreadd_done);
?? ?
?? ?......
}
?? ?rest_init算是kernel再啟動(dòng)函數(shù)start_kernel中執(zhí)行的最后一個(gè)函數(shù),kthreadd_task表示的內(nèi)核線程就是在這里創(chuàng)建的,這行代碼kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns)是通過pid來查找其對(duì)應(yīng)的task_struct的結(jié)構(gòu)體,再看pid是上面的這行代碼產(chǎn)生的pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES),kernel_thread函數(shù)是通過do_fork來創(chuàng)建線程的,然后返回該線程的pid,從這里可以看出kthreadd_task表示的內(nèi)核線程的執(zhí)行函數(shù)是kthreadd,下面來看這個(gè)函數(shù)的實(shí)現(xiàn).
int kthreadd(void *unused)
{
?? ?struct task_struct *tsk = current;
?? ?......
?? ?for (;;) {
?? ??? ?set_current_state(TASK_INTERRUPTIBLE);
?? ??? ?if (list_empty(&kthread_create_list))
?? ??? ??? ?schedule();
?? ??? ?__set_current_state(TASK_RUNNING);
?? ??? ?spin_lock(&kthread_create_lock);
?? ??? ?while (!list_empty(&kthread_create_list)) {
?? ??? ??? ?struct kthread_create_info *create;
?? ??? ??? ?create = list_entry(kthread_create_list.next, struct kthread_create_info, list);
?? ??? ??? ?list_del_init(&create->list);
?? ??? ??? ?spin_unlock(&kthread_create_lock);
?? ??? ??? ?create_kthread(create);
?? ??? ??? ?spin_lock(&kthread_create_lock);
?? ??? ?}
?? ??? ?spin_unlock(&kthread_create_lock);
?? ?}
?? ?return 0;
}
?? ?可以看出這個(gè)函數(shù)的主體是一個(gè)for循環(huán),重點(diǎn)是其中的那個(gè)while循環(huán),很明顯是在遍歷鏈表kthread_create_list,獲取將其上面的每個(gè)節(jié)點(diǎn)所表示的kthread_create_info結(jié)構(gòu),然后將該結(jié)構(gòu)傳遞給函數(shù)create_kthread,顧名思義,該函數(shù)就是來創(chuàng)建線程的,下面看看create_kthread的代碼.
static void create_kthread(struct kthread_create_info *create)
{
?? ?int pid;
?? ?......
?? ?pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
?? ?if (pid < 0) {//線程如果創(chuàng)建失敗,下面的代碼是錯(cuò)誤處理,不是重點(diǎn)
?? ??? ?/* If user was SIGKILLed, I release the structure. */
?? ??? ?struct completion *done = xchg(&create->done, NULL);
?? ??? ?if (!done) {
?? ??? ??? ?kfree(create);
?? ??? ??? ?return;
?? ??? ?}
?? ??? ?create->result = ERR_PTR(pid);
?? ??? ?complete(done);
?? ?}
}
該函數(shù)調(diào)用了kernel_thread函數(shù)創(chuàng)建了一個(gè)以kthread函數(shù)為線程執(zhí)行函數(shù),以kthread_create_info結(jié)構(gòu)為執(zhí)行函數(shù)參數(shù)的內(nèi)核線程,其實(shí)這個(gè)新創(chuàng)建的線程就是最終需要?jiǎng)?chuàng)建的那個(gè)內(nèi)核線程,那為什么執(zhí)行函數(shù)是kthread,而不是kthread_create_info結(jié)構(gòu)中指定的線程執(zhí)行函數(shù).看完kthread函數(shù)的實(shí)現(xiàn)就知道了.
static int kthread(void *_create)
{
?? ?struct kthread_create_info *create = _create;
?? ?int (*threadfn)(void *data) = create->threadfn;//獲取線程執(zhí)行函數(shù)賦值給函數(shù)指針threadfn
?? ?void *data = create->data;//線程執(zhí)行函數(shù)的參數(shù)
?? ?struct completion *done;
?? ?struct kthread self;
?? ?int ret;
?? ?......
?? ?
?? ?done = xchg(&create->done, NULL);可以理解為將create->done賦值給done
?? ?if (!done) {
?? ??? ?kfree(create);
?? ??? ?do_exit(-EINTR);
?? ?}
?? ?
?? ?__set_current_state(TASK_UNINTERRUPTIBLE);
?? ?create->result = current;//將該線程的task_struct結(jié)構(gòu)賦值給create->result
?? ?complete(done);//調(diào)用complete函數(shù)喚醒調(diào)用kthread_create_on_node的那個(gè)線程,通知它創(chuàng)建的線程已經(jīng)創(chuàng)建完畢.
?? ?schedule();//調(diào)用schedule交出處理器,給剛喚醒的調(diào)用kthread_create_on_node的線程以運(yùn)行的機(jī)會(huì),使其繼續(xù)執(zhí)行kthread_create_on_node函數(shù)剩下的代碼.
?? ?
?? ?//再次調(diào)度到該線程,從這里開始執(zhí)行.
?? ?ret = -EINTR;
?? ?if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {//判斷如果該線程沒有被停止掉.
?? ??? ?......
?? ??? ?ret = threadfn(data);//我們通過kthread_create_on_node函數(shù)傳遞進(jìn)來的線程執(zhí)行函數(shù)最終是在這個(gè)位置被執(zhí)行的.
?? ?}
?? ?do_exit(ret);
}
?? ?可以看出,如果在kthread函數(shù)調(diào)用schedule交出處理器和再次調(diào)度到該線程之間的這段時(shí)間里,在別的地方調(diào)用了kthread_stop函數(shù)停止了該函數(shù)的話,那么線程執(zhí)行函數(shù)是得不到執(zhí)行的,該線程就直接退出了.
?? ?以上就是通過kthread_run和kthread_create創(chuàng)建線程的整個(gè)過程.可以看出,它們并不直接創(chuàng)建線程,而是將要?jiǎng)?chuàng)建的線程的相關(guān)信息打包到kthread_create_info結(jié)構(gòu)中,然后委托給內(nèi)核線程kthreadd來做的,從函數(shù)kthreadd也可以看出,該線程的主要工作就是遍歷鏈表kthread_create_list創(chuàng)建線程.
總結(jié)
以上是生活随笔為你收集整理的kthread_run创建内核线程的原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux SPI总线和设备驱动架构之四
- 下一篇: kthread_work和kthread