描述进程
进程描述符task_struct
由slab分配器分配一个thread_info结构体到进程内核栈的栈底,thread_info结构体中有一个指向task_struct的指针,task_struct中有一个int值pid来表示每个进程
进程五种状态
TASK_RUNNING:正在执行或等待执行。 TASK_INTERRUPTIBLE:处于阻塞状态,可被唤醒。 TASK_UNINTERRUPTIBLE:处于阻塞状态,不可被唤醒。 TASK_TRACED:被跟踪。 TASK_STOPPED:不在执行也不能执行。
如何组织进程
task list:进程队列,task_struct构成的双向链表。 进程树:task_struct中有一个指向它父进程的指针,还有一个存放它子进程的链表。
创建进程
写时拷贝
通过拷贝当前进程创建一个子进程。内核不复制整个地址空间,而是让父进程和子进程以只读的方式共享同一拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。实际开销只有复制父进程的页表、为子进程分配描述符。
fork()
fork() -> clone() -> do_fork() -> copy_process()
exec()
读取可执行文件,载入地址空间并开始执行。
销毁进程
exit()
1、释放占用的文件资源和部分内存; 2、为子进程寻找新的父进程; 3、打上标志EXIT_ZOMBIE,即处于不可运行状态; 4、此时它仍然占有:内核栈、thread_info结构、task_struct结构;这些是为了向父进程提供信息;
wait()
当父进程检索到这些信息,并通知内核这些已经是无用的信息时,这些内存也被释放。
线程
定义
能共享资源的进程。对线程的描述、组织和操作与进程相同。
创建线程
在调用clone()时传递一些参数来指明共享哪些资源。 共享的有:地址空间、文件系统资源、文件描述符、信号处理程序。
内核线程
独立运行在内核空间的标准进程。可以被调度,也可以被抢占。只能由内核线程创建。
进程调度
调度器类
包含多种不同的可动态添加的调度算法的模块。每种调度算法负责一类进程,按优先级排序。先选择具有最高优先级的调度算法,再由它算出执行哪个进程。
完全公平调度算法
针对普通进程。 允许每个进程运行一段时间,循环轮转,选择运行最少的进程作为下一个进程。 运行时间由目标延迟、nice值的几何加权、最小粒度决定。
时间记账
task_struct中有一个名为se的sched_entity结构体,其中有一个vruntime变量,存放程序的虚拟运行时间。虚拟运行时间的计算是经过了所有可运行进程总数的加权,单位是ns。
进程选择
目的是选择vruntime最小的进程。 使用红黑树来组织可运行进程队列,可迅速找到目标进程。
调度器入口
睡眠和唤醒
等待队列 wake_up()
上下文切换
context_switch() 1、把虚拟内存从上一个进程映射切换到新进程。 2、才上一个进程的处理器状态切换到新进程的处理器状态。包括保存、恢复栈信息和寄存器信息,还有其它任何与体系结构相关的信息。
用户抢占
1、从系统调用返回用户空间时; 2、从中断处理程序返回用户空间时。