Linux进程PID分配
struct pid在内核内部用于标识一个“进程”,表示一个独立的任务(task)、进程组、会话,为了快速索引可以用hash表来组织。下面我们基于Linux4.20看下进程的pid是如何分配的,首先看下进程pid相关的数据结构:进程数据结构中的namespace成员:struct task_struct{… …/* Namespaces:*/struct nsprox...
·
struct pid在内核内部用于标识一个“进程”,表示一个独立的任务(task)、进程组、会话,为了快速索引可以用hash表来组织。
下面我们基于Linux4.20看下进程的pid是如何分配的,首先看下进程pid相关的数据结构:
进程数据结构中的namespace成员:
struct task_struct
{
… …
/* Namespaces: */
struct nsproxy *nsproxy;
… …
pid_t pid;
… …
}
进程PID的创建流程,在copy_process函数中:
//进程pid的创建:如果不是进程0的pid就需要创建一个pid
static __latent_entropy struct task_struct *copy_process(
unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *child_tidptr,
struct pid *pid,
int trace,
unsigned long tls,
int node)
{
……
// 如果入参clone_flag中配置CLONE_NEWNS, CLONE_NEWUTS, CLONE_NEWIPC,
// CLONE_NEWPID, CLONE_NEWNET, CLONE_NEWCGROUP 就为当前进程创建一个
// 新的nsproxy
retval = copy_namespaces(clone_flags, p);
if (retval)
goto bad_fork_cleanup_mm;
… …
// 如果配置CLONE_NEWPID,会调用create_pid_namespace从pid_ns_cachep中分配
// 一个pid_namespace, 并将调用进程的pid_namespace设置父节,ns->level设置为父
// 节点的level+1,并初始化其它成员
if (pid != &init_struct_pid) {
pid = alloc_pid(p->nsproxy->pid_ns_for_children);
if (IS_ERR(pid)) {
retval = PTR_ERR(pid);
goto bad_fork_cleanup_thread;
}
}
……
/* ok, now we should be set up.. */
p->pid = pid_nr(pid);
……
}
大体流程已经清楚,下面看下pid分配的具体流程,下面看下进程ID的具体分配函数:
struct pid *alloc_pid(struct pid_namespace *ns)
{
struct pid *pid;
enum pid_type type;
int i, nr;
struct pid_namespace *tmp;
struct upid *upid;
int retval = -ENOMEM;
pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
if (!pid)
return ERR_PTR(retval);
tmp = ns;
// 进程0的level为1,每个设置CLONE_NEWPID的进程,都会比其父进程的level增1
pid->level = ns->level;
// 从level层开始到0层,依次在每一个level申请一个nr,并记录在对应的numbers[i]中
for (i = ns->level; i >= 0; i--) {
int pid_min = 1;
idr_preload(GFP_KERNEL);
spin_lock_irq(&pidmap_lock);
/*
* init really needs pid 1, but after reaching the maximum
* wrap back to RESERVED_PIDS
*/
if (idr_get_cursor(&tmp->idr) > RESERVED_PIDS)
pid_min = RESERVED_PIDS;
/*
* Store a null pointer so find_pid_ns does not find
* a partially initialized PID (see below).
*/
// 从pid_min和pid_max中分配一个未使用的id
nr = idr_alloc_cyclic(&tmp->idr, NULL, pid_min,
pid_max, GFP_ATOMIC);
spin_unlock_irq(&pidmap_lock);
idr_preload_end();
if (nr < 0) {
retval = (nr == -ENOSPC) ? -EAGAIN : nr;
goto out_free;
}
pid->numbers[i].nr = nr;
pid->numbers[i].ns = tmp;
tmp = tmp->parent;
}
if (unlikely(is_child_reaper(pid))) {
if (pid_ns_prepare_proc(ns))
goto out_free;
}
get_pid_ns(ns);
atomic_set(&pid->count, 1);
for (type = 0; type < PIDTYPE_MAX; ++type)
INIT_HLIST_HEAD(&pid->tasks[type]);
upid = pid->numbers + ns->level;
spin_lock_irq(&pidmap_lock);
if (!(ns->pid_allocated & PIDNS_ADDING))
goto out_unlock;
for ( ; upid >= pid->numbers; --upid) {
/* Make the PID visible to find_pid_ns. */
idr_replace(&upid->ns->idr, pid, upid->nr);
upid->ns->pid_allocated++;
}
spin_unlock_irq(&pidmap_lock);
return pid;
out_unlock:
spin_unlock_irq(&pidmap_lock);
put_pid_ns(ns);
out_free:
spin_lock_irq(&pidmap_lock);
while (++i <= ns->level) {
upid = pid->numbers + i;
idr_remove(&upid->ns->idr, upid->nr);
}
/* On failure to allocate the first pid, reset the state */
if (ns->pid_allocated == PIDNS_ADDING)
idr_set_cursor(&ns->idr, 0);
spin_unlock_irq(&pidmap_lock);
kmem_cache_free(ns->pid_cachep, pid);
return ERR_PTR(retval);
}
更多推荐
已为社区贡献1条内容
所有评论(0)