内核线程
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(®s, 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, ®s, 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; };