内核线程kthreadd详解
linux-dash
A beautiful web dashboard for Linux
项目地址:https://gitcode.com/gh_mirrors/li/linux-dash
免费下载资源
·
linux在初始化的时候,除了静态的idle线程,还会创建kernel_init线程和kthreadd线程。kthreadd线程为2号线程,该线程专门用来负责为kernel创建其他线程。下面看一下如何利用kthreadd创建一个内核线程。
struct kthread_create_info
{
/* Information passed to kthread() from kthreadd. */
int (*threadfn)(void *data); //要创建的线程的执行函数
void *data;
int node;
/* Result passed back to kthread_create() from kthreadd. */
struct task_struct *result; //用来向线程申请者返回task_struct
struct completion done;//向申请者通知创建完成
struct list_head list;//挂载进kthreadd的处理队列
};
为了容易区分,我们把需要创建新线程的叫做申请者,具体负责创建新进程的叫做执行者,这边执行者就是kthreadd线程。kthread_create_info数据结构用来在申请者和执行者之间传递对象。
1 新线程创建的申请
struct kthread_create_info create;
struct task_struct *task;
create.threadfn = threadfn;//新建线程的执行函数
create.data = data;
create.node = node;
init_completion(&create.done);//初始化完成量
spin_lock(&kthread_create_lock);
list_add_tail(&create.list, &kthread_create_list);//添加到kthreadd执行队列
spin_unlock(&kthread_create_lock);
wake_up_process(kthreadd_task);//唤醒kthreadd线程
wait_for_completion(&create.done);//等待kthreadd线程完成线程创建
task=create.result;//返回新建线程的描述符
wake_up_process(task);//唤醒新建线程
2 新线程创建
kthreadd_task是kthreadd线程的进程描述符,在系统初始化的时候创建:
static noinline void __init_refok rest_init(void)
{
........................................
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
........................................
}
下面看一下kthreadd的具体实现:
int kthreadd(void *unused)
{
struct task_struct *tsk = current;
/* Setup a clean context for our children to inherit. */
set_task_comm(tsk, "kthreadd");
ignore_signals(tsk);
set_cpus_allowed_ptr(tsk, cpu_all_mask);
set_mems_allowed(node_states[N_MEMORY]);
current->flags |= PF_NOFREEZE;
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);//先从队列上删除该create
spin_unlock(&kthread_create_lock);
create_kthread(create);//为申请者创建线程
spin_lock(&kthread_create_lock);
}
spin_unlock(&kthread_create_lock);
}
return 0;
}
可以看到,在kthread_create_list链表中获取到申请者传过来的kthread_create_info结构,利用该信息调用create_kthread来创建线程。
static void create_kthread(struct kthread_create_info *create)
{
int pid;
#ifdef CONFIG_NUMA
current->pref_node_fork = create->node;
#endif
/* We want our own signal handler (we take no signals by default). */
pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
if (pid < 0) {
create->result = ERR_PTR(pid);
complete(&create->done);
}
}
调用kernel_thread创建kthread线程,参数为create,看一下kernel_thread是如何执行的:
static int kthread(void *_create)
{
/* Copy data: it's on kthread's stack */
struct kthread_create_info *create = _create;
int (*threadfn)(void *data) = create->threadfn;
void *data = create->data;
struct kthread self;
int ret;
self.flags = 0;
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(&create->done);//告诉申请者,线程创建完成
schedule();
ret = -EINTR;
if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) {
__kthread_parkme(&self);
ret = threadfn(data);//申请者提供的线程执行函数
}
/* we can't just return, we must preserve "self" on stack */
do_exit(ret);
}
可以看到kthread是kthreadd函数创建的线程的入口地址,该函数最终执行到申请者提供的的threadfn函数,至此创建者完成了自己的使命,申请者开始有了自己的新线程,并执行threadfn任务
GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e
added ecosystem file for PM2 4 年前
5def40a3
Add host customization support for the NodeJS version 4 年前
更多推荐
已为社区贡献4条内容
所有评论(0)