回收pid

static void free_pidmap( struct upid *upid)
{
         /* 获得进程号即是用户空间的pid号 */
         int nr = upid->nr;
         /* 在该upid的名字空间中找到对应的map, nr / BITS_PER_PAGE 计算出该pid号所在的
             是第几张表,比如:nr=44563,BITS_PER_PAGE=32768,那就是第二张表;nr=1000,BITS_PER_PAGE=32768,那就是第一张表 */

         struct pidmap *map = upid->ns->pidmap + nr / BITS_PER_PAGE;
         /* 计算出该pid在对应表内的偏移量,比如:nr=44563, BITS_PER_PAGE_MASK=32767,则offset=11795;nr=1000,BITS_PER_PAGE_MASK=32767,offset=1000;也就是说当nr > BITS_PER_PAGE_MASK的时候,offset就是nr-32768,否则就直接是offset=nr */
         int offset = nr & BITS_PER_PAGE_MASK;

         /* 清除对应map中page对应的该位的比特值 */
        clear_bit(offset, map->page);
         /* 增加空闲pid数 */
        atomic_inc(&map->nr_free);
}
分配pid

static int alloc_pidmap( struct pid_namespace *pid_ns)
{
         int i, offset, max_scan, pid, last = pid_ns->last_pid;
         struct pidmap *map;

         /* last为上次分配的pid */
        pid = last + 1;
         /* 如果pid比最大值还大,那么就设置成RESERVED_PIDS 300,在Linux系统中会保留一部分进程号用作它用 */
         if (pid >= pid_max)
                pid = RESERVED_PIDS;
         /* 计算出该pid在它所在的map表中的偏移量 */
        offset = pid & BITS_PER_PAGE_MASK;
         /* 计算出该pid所在的map,pid/BITS_PER_PAGE就是它所在map对应的pidmap偏移量 */
        map = &pid_ns->pidmap[pid/BITS_PER_PAGE];
         /* 计算最大遍历次数,pid_max是一个全局变量,默认值PID_MAX_DEFAULT,根据系统是否设置CONFIG_BASE_SMALL,可以为0x1000或0x8000, 在x86体系上,(pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE 始终是1, 当pid是在map的第一个位置的时候,即offset=0的时候,只需循环
一次;当pid不是第一个位置,在中间或者结尾,即offset!=0的时候,max_scan=1,就需要循环两次,从last+1的位置开始,一直找到末尾,还>没找到对应的,那就从头开始,找到last处,总之需要走一遍map */

        max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset;
         for (i = 0; i <= max_scan; ++i) {
                 if (unlikely(!map->page)) {
                         /* 如果page为空,则从新分配一个,同时加锁再次判断是否为空,如果为空则直接设置,否则分配的就多余了
                             如果其他地方也在使用该page的时候,那么有可能在加锁之前,map->page由空变成了不空,
                        void *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
                        /*
                         * Free the page if someone raced with us
                         * installing it:
                         */

                        spin_lock_irq(&pidmap_lock);
                         if (map->page)
                                kfree(page);
                         else
                                map->page = page;
                        spin_unlock_irq(&pidmap_lock);
                         if (unlikely(!map->page))
                                 break;
                }
                 /* 如果map存在空闲位置,那么就设置该offset对应的比特位*/
                 if (likely(atomic_read(&map->nr_free))) {
                         do {
                                 if (!test_and_set_bit(offset, map->page)) {
                                         /* 减少空闲位置个数 */
                                        atomic_dec(&map->nr_free);
                                        pid_ns->last_pid = pid;
                                         /* 分配成功返回对应pid */
                                         return pid;
                                }
                                 /* 设置不成功,或许该位已经置位,那么继续寻找下一个比特位为0的位置,同时生成一个pid */
                                offset = find_next_offset(map, offset);
                                pid = mk_pid(pid_ns, map, offset);
                                 /*
                                 * 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 &&
                                        (i != max_scan || pid < last ||
                                         !((last+1) & BITS_PER_PAGE_MASK)));
                }
                 /* 如果map中已经没有空闲了,且判断还存在其他map的时候,继续在下一个map中分配
                     在x86体系上,判断始终不成立 */

                 if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
                        ++map;
                        offset = 0;
                } else {
                         /* 否则就从第一个位置从头开始找 */
                        map = &pid_ns->pidmap[0];
                        offset = RESERVED_PIDS;
                         /* 如果这个时候的位置已经是上次分配的了,那么就已经找过了,没必要再找一次了 */
                         if (unlikely(last == offset))
                                 break;
                }
                pid = mk_pid(pid_ns, map, offset);
        }
         return -1;
}