プロセスIDの取得


Rev.1を表示中。最新版はこちら

プロセスIDはtsk->nsproxy->pid_ns下のPIDネームスペースの元で管理されていて、alloc_pid関数でPIDを割り当てます。ネームスペース下ではプロセスIDはユニークです。従ってtsk->nsproxy->pid_nsのネームスペース毎のビットマップから未使用のPIDを取得します。その関数がalloc_pidmap関数です。

PIDネームスペースは親子関係と、そしてトップPIDネームスペースからのネストレベルを有しています。親ネームスペースがns->parentで、ネストレベルがns->levelです。for (i = ns->level; i >= 0; i--)ループではネストレベル数、それぞれのPIDネームスペース下でPIDを取得しています。pid->numbers[i].nr/pid->numbers[i].nsがそれに相当します。すなわち、そのプロセスIDは異なるものの、親のネームスペースから、子のネームスペースのプロセスを識別することが可能ということです。

struct pid *pidは特定のプロセスそのものを表す構造体とも言えます。カーネルがプロセスIDからプロセス構造体を取得するのは、プロセスIDからstruct pidを取得します。これはプロセスIDとネームスペースのアドレスをキーとするハッシュテーブルpid_hashから簡単に取得できます。そこからそのstruct pid下にリスト管理しているリストを走査することでtask_structを取得します。そのための処理が以下の2つのループです。

for (type = 0; type < PIDTYPE_MAX; ++type)ループは、グループ/セッション/プロセスをtask_structをリストするヘッダー初期化します。PIDTYPE_PGID, PIDTYPE_SID, PIDTYPE_PID,です。

for (i = ns->level; i >= 0; i--)ループはpid_hashハッシュテーブルにupid->nr, upid->nsをキーとしてpid->numbers[i]を登録しています。

そしてalloc_pid関数で取得したpidのpid->numbers[0].nrをプロセスIDとしてtask_struct->pid/tgidに設定されます。psコマンドはtask_struct->tgidを取得します。従ってpsプロセスのネームスペース(シェルのネームスペース)に関係なく、いかなるネームスペースのプロセス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;

       pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
       if (!pid)
               goto out;

       tmp = ns;
       for (i = ns->level; i >= 0; i--) {
               nr = alloc_pidmap(tmp);
               if (nr < 0)
                       goto out_free;

               pid->numbers[i].nr = nr;
               pid->numbers[i].ns = tmp;
               tmp = tmp->parent;
       }

       get_pid_ns(ns);
       pid->level = ns->level;
       atomic_set(&pid->count, 1);
       for (type = 0; type < PIDTYPE_MAX; ++type)
               INIT_HLIST_HEAD(&pid->tasks[type]);

       spin_lock_irq(&pidmap_lock);
       for (i = ns->level; i >= 0; i--) {
               upid = &pid->numbers[i];
               hlist_add_head_rcu(&upid->pid_chain,
                               &pid_hash[pid_hashfn(upid->nr, upid->ns)]);
       }
       spin_unlock_irq(&pidmap_lock);

out:
       return pid;
 :
}
CLONE_NEWPIDが設定されていると、copy_namespacesから最終的にcreate_pid_namespace関数でプロセスIDのネームスペースが作成されます。copy_pid_ns関数でcreate_pid_namespace関数で、new_nsとして新規にPIDネームスペースを取得し、new_ns->parentに親のネームスペースを設定しています。get_pid_ns関数は引数のネームスペースがinit_pid_nsで無いことを確認し、そうでないならその参照カウンタns->krefをインクリメントし、引数のold_nsそのものを返しています。なおcreate_pid_namespace関数の引数は、新規のネームスペースのlevelとなります。+ 1としているように、階層的にネームスペースを作る毎に、そのレベルが深くなることを表しています。
struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns)
{
       struct pid_namespace *new_ns;
  :
       new_ns = create_pid_namespace(old_ns->level + 1);
       if (!IS_ERR(new_ns))
               new_ns->parent = get_pid_ns(old_ns);

out_put:
       put_pid_ns(old_ns);
out:
       return new_ns;
}
・備考
ネームスペースのlevelがネームスペースの階層レベルを表しています。しかもPID取得においてすべてのネームスペースからそれぞれのPIDを取得し、それをpid->number[]に設定していました。ところがstruct pidを見るとそのメンバーはnumbers[1]となっています。検証はしてませんが、よろしくないのでは(バグ?)・・・。
struct pid
{
       atomic_t count;
       unsigned int level;
       /* lists of tasks that use this pid */
       struct hlist_head tasks[PIDTYPE_MAX];
       struct rcu_head rcu;
       struct upid numbers[1];
};

最終更新 2011/05/15 05:25:23 - north
(2011/05/15 05:25:23 作成)


検索

アクセス数
3575165
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。