Linux-算法学习(分配pid)

该分配进程pid的函数被定义在:kernel/pid.c
数据定义:
typedef struct pidmap {
     atomic_t nr_free;//当前空闲的pid的个数
      void *page;//用数组代表位图,每一项为一个字长,用位来表示是否该pid被分配.
 } pidmap_t;
BITS_PE_PAGE:一个页面中可以表示的数的个数,32位的为2^15(页面大小4KB)
BITS_PE_PAGE_MASK:BITS_PE_PAGE-1

代码解析
int alloc_pidmap(void)
{
	int i, offset, max_scan, pid, last = last_pid;
	pidmap_t *map;

	pid = last + 1;//last为全局变量,表示上次分配pid时分出去的
	if (pid >= pid_max)
		pid = RESERVED_PIDS;//300,前300个pid是固定的,不可以分配的
	offset = pid & BITS_PER_PAGE_MASK;//找出pid在某一个页面中的偏移量
	map = &pidmap_array[pid/BITS_PER_PAGE];//&pidmap_array[i]表示的是第i个描述pid使用状况的页面的地址.
        //pid/BITS_PER_PAGE代表的是该pid在第几个描述pid的页面
	max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset;//获得pid号在内存中表示占用的页面个数,32位的为1
	//seem the page number
	for (i = 0; i <= max_scan; ++i) {//对每个页面进行扫描
		if (unlikely(!map->page)) {//如果map所指的页的物理地址为空
			unsigned long page = get_zeroed_page(GFP_KERNEL);//在内存中分配一个物理页面
			//GFP_KERNEL wait|io|fs
			/*
			 * Free the page if someone raced with us
			 * installing it:
			 */
			spin_lock(&pidmap_lock);
			if (map->page)//因为可能是多处理器,或者进程的交叉执行,所以需要再次判断map所指的物理页面是否为空
				free_page(page);//为空的话就把刚刚申请的页面释放
			else
				map->page = (void *)page;
			spin_unlock(&pidmap_lock);
			if (unlikely(!map->page))//如果页面指针还是为空,分配失败,跳出循环,返回-1
				break;// cannot alloc pid
		}
		if (likely(atomic_read(&map->nr_free))) {//如果该页面的空闲pid的个数不为0的话
			do {
				if (!test_and_set_bit(offset, map->page)) {//判断该页面中offset偏移量表示的pid是否为空
					atomic_dec(&map->nr_free);//为空在空闲的pid个数--
					last_pid = pid;//全局变量更新
					return pid;
				}
				offset = find_next_offset(map, offset);//失败则寻找下一个pid
				pid = mk_pid(map, offset);//根据map和offset的值获得pid
				//new pid
			/*
			 * find_next_offset() found a bit, the pid from it
			 * is in-bounds, and if we fell back to the last
			 * bitmap block and the final block was the same
			 * as the starting point, pid is before last_pid.
			 */
			} while (offset < BITS_PER_PAGE && pid < pid_max &&//判断offset是否超过一个页面可以表示的最大的pid数或者最大的pid
					(i != max_scan || pid < last ||//如果i==max_scan的话,如果pid>=last因为之前已经判断过,就没必要了
					    !((last+1) & BITS_PER_PAGE_MASK)));
                       //对于max_scan等于1,也需要对其扫描两编,第一次是last之后的,第二次是last之前的.
		}
		if (map < &pidmap_array[(pid_max-1)/BITS_PER_PAGE]) {
			++map;//如果map没有超过最大的pid所占的页面的地址
			offset = 0;
		} else {
			map = &pidmap_array[0];//对于分配地一个pid的页面,前300是固定的,所以offset需要赋值为非0
			offset = RESERVED_PIDS;
			if (unlikely(last == offset))
				break;
		}
		pid = mk_pid(map, offset);//重新计算pid的值
	}
	return -1;
}


你可能感兴趣的:(Linux-算法)