Linux允许用户使用一个叫做进程标识符process ID(pid)的数来标识进程,PID存放在进程描述符的pid字段。pid的值有一个上限,举个例子:默认情况下,最大的PID号为32767。那么内核是如何管理这些pid的呢?能不能用数组?可以,不过效率不高,存在循环,比较耗CPU,而且需要空间较大;内核中使用位图来管理这些pid,由于使用内嵌的汇编语言扫描位图(跟循环有质的区别),所以效率较高,数据结构为pidmap-array,内核使用页框来存放位图,一个页框包含32768个位,所以32位体系结构中pidmap-array位图存放在一个单独的页中。然而,在64位体系结构中,可能需要为PID位图增加更多的页,pidmap及pidmap_array定义如下:
/*
* nr_free为页框中空闲位的个数
* page存放页框的地址
*/
typedef struct pidmap {
atomic_t nr_free;
void *page;
} pidmap_t;
/*
* pidmap_array中存放的是所有pidmap位图
*/
static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
{ [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } };
/*
* BITS_PER_PAGE正如字面意思,表示一个页框中位的个数
*/
#define BITS_PER_PAGE (PAGE_SIZE*8)
#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
内核使用alloc_pidmap()来为进程分配一个pid,代码如下:
int alloc_pidmap(void)
{
/*
* last_pid为全局变量,表示上次分配的pid
*/
int i, offset, max_scan, pid, last = last_pid;
pidmap_t *map;
pid = last + 1;
/*
* RESERVED_PIDS为300,前300个PID是固定的,不可以分配
*/
if (pid >= pid_max)
pid = RESERVED_PIDS;
/*
* offset为pid在页框中的偏移量,因为pid可能大于一个页框所能容纳的最大位数,即BITS_PER_PAGE
* 所以pid要对BITS_PER_PAGE取模,下面即是实现取模操作
*/
offset = pid &