内核线程

Linux内核线程只运行在内核态,使用PAGE_OFFSET的线性地址空间。

下面的函数负责创建一个内核线程,可以看到关键代码是使用CLONE_VM|CLONE_UNTRACED参数调用do_fork函数。

pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
    struct pt_regs regs;

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

    regs.ARM_r1 = (unsigned long)arg;
    regs.ARM_r2 = (unsigned long)fn;
    regs.ARM_r3 = (unsigned long)do_exit;
    regs.ARM_pc = (unsigned long)kernel_thread_helper;
    regs.ARM_cpsr = SVC_MODE;

    return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}

1. kthreadd内核线程PID==2,该线程负责启动其它内核线程。

static noinline void __init_refok rest_init(void)
    /*这里的pid==2,对应kthreadd内核线程*/
    -->pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
        -->int kthreadd(void *unused)
            -->set_task_comm(tsk, "kthreadd");/*设置进程显示的名字,PID=2,[kthreadd]*/
            -->休眠等待唤醒
            -->唤醒后遍历kthread_create_list链表,找到每一个struct kthread_create_info *create
            /*正式创建内核线程*/
            -->create_kthread(create);
                /*在这个例子中,创建ksoftirqd/0内核线程*/
                -->pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);
                    -->static int kthread(void *_create)
                        -->create->result = current; /*设定kthread_create_info指定的task_struct结构体*/
                        -->complete(&create->started);
                        -->schedule(); /*进程切换*/
                        -->create->threadfn;/*执行对应的函数,以ksoftirqd为例*/
                        即static int ksoftirqd(void * __bind_cpu)
                            -->睡眠,等待被唤醒
                            -->唤醒,处理软中断,继续睡眠    
                /*等待kthread函数开始执行*/
                -->wait_for_completion(&create->started);
                /*通知kthread_create函数返回*/
                -->complete(&create->done);
            -->休眠等待唤醒
    -->kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);

等待被kthreadd启动的内核线程挂载全局链表kthread_create_list上,那么这个链表上的节点是何时挂上去的呢?

2.内核通过kthread_create函数在kthread_create_list上添加节点并唤醒kthreadd线程。

struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char namefmt[],...)

下面以ksoftirqd/0内核线程的创建为例说明这一过程,

/*在这里向kthread_create_list链表挂载kthread_create_info结构体*/
struct task_struct *p = kthread_create(ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu);
    -->struct kthread_create_info create;//声明局部变量并赋值
            -->create.threadfn = ksoftirqd /*static int ksoftirqd(void * __bind_cpu)*/
            -->create.data = hcpu; /*存储cpu号*/
            -->init_completion(&create.started);
            -->init_completion(&create.done);
    /*在这里加入链表*/
    -->list_add_tail(&create.list, &kthread_create_list);
    -->wake_up_process(kthreadd_task);
    /*阻塞在这里等待完成*/
    -->wait_for_completion(&create.done);
    /*赋值给task_struct->comm,用于显示进程名字*/
    -->vsnprintf(create.result->comm, sizeof(create.result->comm),namefmt, args);

3.关键结构体

struct kthread_create_info
{
    /* Information passed to kthread() from kthreadd. */
    int (*threadfn)(void *data);
    void *data;
    struct completion started;

    /* Result passed back to kthread_create() from kthreadd. */
    struct task_struct *result;
    struct completion done;

    struct list_head list;
};

 

posted @ 2018-02-26 17:46  bluebluebluesky  阅读(389)  评论(0编辑  收藏  举报