设为首页 加入收藏

TOP

Linux下2号进程的kthreadd--Linux进程的管理与调度(七)(一)
2019-09-01 23:09:36 】 浏览:52
Tags:Linux 进程 kthreadd--Linux 管理 调度

2号进程

内核初始化rest_init函数中,由进程 0 (swapper 进程)创建了两个process

  • init 进程 (pid = 1, ppid = 0)
  • kthreadd (pid = 2, ppid = 0)

所有其它的内核线程的ppid 都是 2,也就是说它们都是由kthreadd thread创建的

所有的内核线程在大部分时间里都处于阻塞状态(TASK_INTERRUPTIBLE)只有在系统满足进程需要的某种资源的情况下才会运行

它的任务就是管理和调度其他内核线程kernel_thread, 会循环执行一个kthreadd的函数,该函数的作用就是运行kthread_create_list全局链表中维护的kthread, 当我们调用kernel_thread创建的内核线程会被加入到此链表中,因此所有的内核线程都是直接或者间接的以kthreadd为父进程

2号进程的创建

在rest_init函数中创建2号进程的代码如下

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);

2号进程的事件循环

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);            //  允许kthreadd在任意CPU上运行
    set_mems_allowed(node_states[N_MEMORY]);

    current->flags |= PF_NOFREEZE;

    for (;;) {
            /*  首先将线程状态设置为 TASK_INTERRUPTIBLE, 如果当前
            没有要创建的线程则主动放弃 CPU 完成调度.此进程变为阻塞态*/
            set_current_state(TASK_INTERRUPTIBLE);
            if (list_empty(&kthread_create_list))  //  没有需要创建的内核线程
                    schedule();                                 //   什么也不做, 执行一次调度, 让出CPU

             /*  运行到此表示 kthreadd 线程被唤醒(就是我们当前)
            设置进程运行状态为 TASK_RUNNING */
            __set_current_state(TASK_RUNNING);

            spin_lock(&kthread_create_lock);                    //  加锁,
            while (!list_empty(&kthread_create_list)) {
                    struct kthread_create_info *create;

                    /*  从链表中取得 kthread_create_info 结构的地址,在上文中已经完成插入操作(将
                    kthread_create_info 结构中的 list 成员加到链表中,此时根据成员 list 的偏移
                    获得 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;
}

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的过程如下

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). 
    其实就是调用首先构造一个假的上下文执行环境,最后调用 do_fork()
    返回进程 id, 创建后的线程执行 kthread 函数
    */
    pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
    if (pid < 0) {
            /* 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);
    }
}

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

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

我们可以看到,创建的内核线程执行的事件kthread

此时回到 kthreadd thread,它在完成了进程的创建后继续循环,检查 kthread_create_list 链表,如果为空,则 kthreadd 内核线程昏睡过去

那么我们现在回想我们的操作
我们在内核中通过kernel_create或者其他方式创建一个内核线程, 然后kthreadd内核线程被唤醒, 来执行内核线程创建的真正工作,于是这里有三个线程

  1. kthreadd已经光
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇基于STM32的简易数码相册 下一篇Linux下1号进程的前世(kernel_ini..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目