zoukankan      html  css  js  c++  java
  • 内核线程

    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;
    };
  • 相关阅读:
    驱动中回溯函数的调用关系
    CSI-MIPI学习笔记
    1920*1080分辨率和1080p,1080i的关系
    V4L2驱动内核文档翻译(一)
    signal()信号操作
    617. Merge Two Binary Trees
    Java中的集合
    Switch能否用string做参数
    Java面试题
    八种基本数据类型的大小,以及他们的封装类
  • 原文地址:https://www.cnblogs.com/yangjiguang/p/8474412.html
Copyright © 2011-2022 走看看