0号进程
0号进程,被叫做idle进程或swapper进程,是内核初始化完后的第一个进程,也是唯一一个不由fork或kernel_thread创建的进程。当然,“内核初始化完成后的第一个进程”这种说法并不准确,0号进程本身就是内核的一部分。
多处理系统上,一个cpu有着一个0号进程。
Linux系统在初始化的时候,会使用INIT_TASK静态创建一个进程描述符
struct task_struct init_task = INIT_TASK(init_task);
INIT_TASK是一个宏定义,静态创建其实就是在声明并初始化 init_task 这个结构体 (init_task是全局变量,故而也可将其看作是内核初始化进程的进程描述符,虽然这时候还没有进程这一概念)
在内核初始化的中间阶段(start_kernel的中间),会调用 sched_init() 进行调度初始化,其中会调用 idle_init() 进行 idle 进程的初始化,其中除了设置一些进程参数以外,另一个很重要的目的就是将当前进程的进程描述符赋值给rq结构体的idle进程的进程描述符(rq即runningqueue,运行队列,是一个结构体,每个cpu独有一个,在较旧的内核版本中,idle进程是放在调度队列中和其他进程一同调度的,在较新的内核中,则设置了idle进程描述符指针,指向idle进程的进程描述符,当无其他进程可调度时则调度idle进程)
void __init sched_init(void)
···
init_idle(current, smp_processor_id());
void __cpuinit init_idle(struct task_struct *idle, int cpu)
...
rq->curr = rq->idle = idle;
在内核初始化的最后阶段(start_kernel的最后),内核会调用 rest_init(),其中进行了 kernel_init 进程和 kthreadd 进程的创建,并将当前进程的调度类置为idle调度类
最后调用 cpu_idle() 后,这个内核初始化的进程就彻底蜕变为了 idle 进程(也就是说idle进程的任务就是cpu_idle()中的while循环)
值得一提的是,这里的idle进程仅是主处理器的idle进程,其他处理器的idle进程是在init进程中创建的。
ps:现在仍然不是很明白的是,init_task和current很明显是有关系的,但仍然没找到将二者关联起来的地方,只是知道在arm架构下,current是通过sp指针得到thread_info中的task,至于init_task是何时进入一个thread_info结构体,又何时入栈的,尚且不明