Linux内核设计与实现总结(3) —— 进程管理与进程调度
进程与线程
Linux内核是不区分线程与进程的,线程只是一种特殊的进程,被视为与其他进程共享地址空间的进程。与windows这种在内核专门提供线程支持的操作系统不一样。
task_struct与thread_struct
task_struct(进程描述符)描述了一个进程的所有信息
,包含进程打开的文件、挂起的信号、进程的状态、进程的pid等。它保存在tasks双向循环链表中(见上一节的链表结构体总结),因此可以从一个进程结构体出发,索引到任何其他进程结构体。目前内核中,进程描述符是用slab分配器动态生成的,并且task_struct有一个void *stack变量指向进程的内核栈。
thread_struct是与体系强相关的,存放了一些进程切换时的 上下文。
早期内核代码中,在X86体系并且CONFIG_THREAD_INFO_IN_TASK设置为N时,进程的thread_struct存放在进程的内核栈。如果是向上增长的栈,thread_struct则在栈顶。在thread_struct中,有一个struct task_struct *task变量。后来内核代码把X86的thread_struct结构体中的task指针给去掉了(Move thread_info into task_struct),因为这个变量本来是为了寄存器在不够多的体系上,可以通过内核栈与偏移找到进程描述符。但是X86一直使用的是per_cpu的变量来保存正在使用cpu的进程的进程描述符:
1 | DECLARE_PER_CPU(struct task_struct *, current_task); |
所以thread_struct中的task变量可有可无,就去掉了。
在进程调度时,会更新这个变量:
1 | this_cpu_write(current_task, next_p); |