Linux におけるプロセス ID は、ユニークな process ID によって識別される。また、init を除く全てのプロセスは親プロセス ID (ppid) を持っており、これによって Linux 上のプロセスはツリーで表現できる。
プロセス ID を参照する際は、sys/types.h で定義されている pid_t を用いる。プログラム自身のプロセス ID は getpid()、親プロセス ID は getppid() で取得できる。
システム上で動作しているプロセスを表示するには ps コマンドを使う。ps コマンドは、デフォルトでは ps が実行されたターミナルによって制御されているプロセスを表示する。
$ ps [~] PID TTY TIME CMD 1313 ttys000 0:00.01 -zsh 1312 ttys001 0:00.57 -zsh 1388 ttys001 0:00.01 screen 1394 ttys002 0:00.00 screen -qUmc /Users/kiririmode/.screen.d/stem1 1401 ttys003 0:00.00 screen -qUmc /Users/kiririmode/.screen.d/stem2 1449 ttys004 0:00.00 screen -qUmc /Users/kiririmode/.screen.d/leaf 1452 ttys005 0:00.41 zsh -l
もっと詳細な情報を表示したいときは、以下のようにする。
$ ps -e -o pid,ppid,command | head -3 PID PPID COMMAND 1 0 /sbin/launchd 10 1 /usr/libexec/kextd
- e:システム上で動作している全プロセスの表示
- o:表示する項目の制御
プロセスをキルしたいときは kill コマンドを使う。kill コマンドでは、デフォルトでプロセスに SIGTERM を送る。これにより当該プロセスは、明示的に SIGTERM をマスクしていないかぎり、動作を停止する。
プロセスの生成
system
system システムコールは、あたかもその引数をシェルに与えたかのようにコマンドを実行する。実際、system は /bin/sh を立ち上げ、コマンドをそのシェルに渡す。/bin/sh が立ち上がらなかった場合は 127 を、それ以外のエラーでは -1 を返す。
どの version の /bin/sh が使われるか、また、その /bin/sh が実際にはどのシェルかはシステム、ディストリビューションに依存する。そのため、system システムコールの結果は、そのシステムによって変わり得る。
fork と exec
Linux の fork は、親プロセスのコピーを生成する。exec ファミリーは、あるプロセスを他のプログラムのインスタンスに変える。そのため、Linux において新しいプロセスを作る場合は、最初に fork を呼んで親プロセスのコピーを作り、その後 exec を呼ぶことによって、そのプロセスを他のプログラムのインスタンスに変えるという方法がとられる。
fork を呼ぶと、子プロセスが生成される。親プロセスは、fork を呼んだ箇所からも実行を続行し、子プロセスもその箇所から実行を開始する。
親プロセスと子プロセスの判断は、getpid() を呼び出すことで可能である。親プロセスは fork 呼び出し前後で pid は変わらないが、子プロセスは新しく pid が採番されている。また、fork は、親プロセスに対しては子プロセスの pid を返却し、子プロセスに対しては 0 を返却する。この戻り値を使えば、子プロセスと親プロセスの判別はより簡単になる。
exec が呼び出されると、プログラムの実行は停止され、異なるプログラムの実行が開始される。
exec ファミリーのシステムコールは以下のように分類される。
- execvp や execlp など、「p」を含むシステムコールは、引数として与えられたプログラムのパスを、現在の実行パスから検索する。一方、「p」を含まない exec ファミリーは、実行するプログラムのフルパスを指定しないといけない。
- execv や execvp など「v」を含むシステムコールは、NULL で終了する文字列へのポインタ配列を引数として与えることができる。一方、execl や execlp のように「l」を含む exec ファミリーは、varargs の形で引数を与える。
- execve など「e」を含む exec ファミリーは、環境変数を渡すことができる。