C言語

【C言語】getpid と getppid関数、正しく理解していますか?

関数仕様

書式

引数

なし

戻り値

正の値 自分のプロセスID(getpid)/ 親のプロセスID(getppid

メモ

getpid()getppid() は必ず成功し、エラーになることはありません。

 

機能

  • getpid() は、自分のプロセスIDを戻り値として返す
  • getppid() は、自分の親のプロセスIDを戻り値として返す
SANACHAN
SANACHAN
getpid() が返すプロセスIDは、プロセスごとに一意の値になるため、ファイル名の一部に埋め込んで一時ファイルとして利用することがあります。

 

注意すること

注意ポイント

glibcgetpid() を使う場合は、子プロセスで誤ったプロセスIDを取得する場合がある。

glibc バージョン 2.3.4 以降では、getpid() のラッパー関数は PID をキャッシュします。
そのため、fork()vfork()clone() などの glibc のラッパー関数を使用せずに子プロセスを生成した場合、
子プロセスにキャッシュがコピーされるため、誤った値を取得してしまう場合があります。

関連

fork() 関数については、「fork関数の使い方と注意点」にまとめています。

 

サンプルプログラム

 

[参考] getpid() は本当に失敗しないのか?

Linux カーネルのソースコードを元に、本当に失敗しないのか調べてみました。

 

sys_getpid()

まずは、カーネルがシステムコールを定義している関数です。
task_tgid_vnr() を呼び出す際の引数 current は、getpid() を呼び出したスレッドの管理構造体です。

CPUアーキテクチャによって異なりますが、通常はコンテキストスイッチする際に、
実行するスレッドの管理構造体へのアドレスが汎用レジスタに保存され、それを current で参照します。

 

task_tgid_vnr()

ラッパー関数が続きましたが、__task_pid_nr_ns() が本体のようです。
引数である nsNULL で呼び出されていますので、if 文内には入って task_active_pid_ns() を呼び出す。

 

task_active_pid_ns()

この経路では、pid が NULL になることはありませんので、何かしらのアドレスが ns にセットされます。

SANACHAN
SANACHAN
最後は、「nr = pid_nr_ns(rcu_dereference(*task_pid_ptr(task, type)), ns);」ですね。

 

task_pid_ptr()

引数の typePIDTYPE_TGID ですので、後者のロジックが実行されます。

 

rcu_dereference()

メモリの有効性をチェックしている、と理解しておきましょう。

 

pid_nr_ns()

ユーザーランドから呼び出した場合、if 文の中に入って自身のプロセスIDがセットされます。

 

長くなりましたが・・・

どこを見ても、システムコールのエラーを示す -1 が返る箇所が無いので、
getpid() が失敗しないというのは正しいようです

途中で NULL アクセスをした場合は、カーネル内で SIGSEGV が発生することになりますので、
カーネルパニックが発生してシステム自体が停止します。

 

こちらの記事もよく読まれています

  • この記事を書いた人
  • 最新記事
SANACHAN

SANACHAN

「生涯一エンジニア」を掲げ、大手グローバル企業でSE/PGとして8年勤め、キャリアアップ転職した現役のエンジニアです。世にあるメジャーな全プログラム言語(コボル除く)を自由に扱えます。一児の父。自分のため、家族のため、日々勉強してます。システムエンジニア、プログラミングに関する情報を蓄積している雑記帳です。

-C言語
-, , ,