Linux进程 (Linux内核设计与实现学习笔记)

1. 进程描述符和任务结构

内核把进程的列表放在叫做任务队列(task list)的双向循环队列中,链表中的每一项都是一个类型位task_struct、称为进程描述符(process descriptor)的数据结构,该结构定义在中,进程描述符包括了进程所有的信息,包括打开的文件、进程地址空间、进程状态,还有其他更多信息(如下图所示)。

Linux进程 (Linux内核设计与实现学习笔记)_第1张图片

2.分配进程描述符

Linux通过slab分配器分配task_struct结构,这样能达到对象复用和缓存着色的目的。内存中普通对象的初始化时间超过了对其进行分配和释放所需的时间,因此不应该将内存释放回一个全局的内存池,而是将内存保持为针对特定目的而初始化的状态,后续的内存分配不需要执行这个初始化函数,因为从上次释放和调用析构之后,它已经处于所需的状态中了。Linux slab 分配器使用了这种思想和其他一些思想来构建一个在空间和时间上都具有高效性的内存分配器。slab分配器由物理上一个或几个连续的页组成,一般情况下,也就由一个页组成。每个slab对象中包括了一些被缓存的数据结构,slab处于三种状态:满、部分满和空。当内核需要一个新的对象时,先从部分满的slab中进行分配,如果没有部分满的就从空的slab中分配,若是没有空的slab就创建一个新的slab。这种策略能减少碎片。

Linux进程 (Linux内核设计与实现学习笔记)_第2张图片

slab分配task_struct时,只需在栈底(向下增长的栈)或栈顶(向上增长的栈)创建一个新的结构struct thread_info。通过预先分配和重复使用task_struct,可以避免动态分配和释放所带来的开销。

Linux进程 (Linux内核设计与实现学习笔记)_第3张图片           Linux进程 (Linux内核设计与实现学习笔记)_第4张图片

3. 进程描述符的存放

在内核中,访问任务通常需要获得其指向task_struct的指针,因此通过current宏查找到当前正在运行进程的进程描述符的速度就尤为重要。对于X86结构,只能在内核栈的尾端创建thread_info结构,通过计算偏移间接地查找task_struct。current把栈指针后13位有效位屏蔽掉,用来计算thread_info的偏移。该操作是通过current_thread_info()函数实现的,汇编代码如下:

movl $-8192, %eax

andl %esp, %eax

这里假设栈的大小是8K,若是4K,就用4096。(-8129=2的32次方减去8192就是二进制的11111111111111111110000000000000。这就是-8192在内存中的存储。这个值再与上 $sp 就是只保留上面的19位,也就是-8k也就是两页的最低地址

你可能感兴趣的:(Linux进程 (Linux内核设计与实现学习笔记))