诗和远方

Linux下2号进程kthreadd

kthreadd作用是管理调度其它的内核线程。它在内核初始化的时候被创建,会循环运行一个叫做kthreadd的函数,该函数的作用是运行kthread_create_list全局链表中维护的kthread。

调用kthread_create创建一个kthread,它会被加入到kthread_create_list链表中,同时kthread_create会weak up kthreadd_task(增链表)。kthreadd在执行kthread会调用老的接口——kernel_thread运行一个名叫“kthread”的内核线程去运行创建的kthread,被执行过的kthread会从kthread_create_list链表中删除(减链表),并且kthreadd会不断调用scheduler 让出CPU。这个线程不能关闭。


在linux启动的C阶段start_kernel()的最后,rest_init()会开启两个进程:kernel_init,kthreadd,之后主线程变成idle线程,init/main.c。


内核线程,实际上是由kernel_thread函数创建的一个进程,有自己独立的task_struct结构并可被调度器调度,这种进程的特殊之处在于它只在内核态运行。

init/main.c中的rest_init()中就开始调用kernel_thread来构造内核线程了,比如:

kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);


kernel_thread函数的最后一行是调用do_fork来生成一个进程框架(主体结构是task_struct),在do_fork中会将新生成的进程执行入口点设置为ret_from_fork()。这样,当新进程被调度器调度时,将从ret_from_fork()函数开始执行。在ret_from_fork中,会调用kernel_thread函数中设置的ARM_pc,也就是说调用kernel_thread_helper。


kthreadd的核心是一for和while循环体。在for循环中,如果发现kthread_create_list是一空链表,则调用schedule调度函数,因为此前已经将该进程的状态设置为TASK_INTERRUPTIBLE,所以schedule的调用将会使当前进程进入睡眠。如果kthread_create_list不为空,则进入while循环,在该循环体中会遍历该kthread_create_list列表,对于该列表上的每一个entry,都会得到对应的类型为struct kthread_create_info的节点的指针create。

然后函数在kthread_create_list中删除create对应的列表entry,接下来以create指针为参数调用create_kthread(create).

在create_kthread()函数中,会调用kernel_thread来生成一个新的进程,该进程的内核函数为kthread,调用参数为create:

kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);


kthread会将其所在进程的状态设为TASK_UNINTERRUPTIBLE,然后调用schedule函数。所以,kthread将会使其所在的进程进入休眠状态,直到被别的进程唤醒。如果被唤醒,将会调用create->threadfn(create->data);


其中的kthread_should_stop()如果返回真,表明对于当前进程p,有别的进程调用了kthread_stop(p),否则kthread_should_stop返回假。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Catalog
标签列表
最新
最热
常用网站
站点信息
  • 文章总数:2010
  • 页面总数:1
  • 分类总数:17
  • 标签总数:517
  • 评论总数:0
  • 浏览总数:533686
Archives
Copyright © 2017-2019 www.my889.com Some Rights Reserved.
推荐使用 Chrome 浏览器浏览本站
沪ICP备17052342号
Sitemap XML