読者です 読者をやめる 読者になる 読者になる

タダノキロク

日々の考えたことの記録 主に無駄なこと

詳細Linuxカーネル プロセス管理周りのシステムコール 7/3

詳細Linuxカーネル プロセス管理周りのシステムコール 7/3

今日は、プロセス管理のシステムコールforkを見ることにする。

https://kernelreading.doorkeeper.jp/events/44499

プロセス管理は詳解Linuxだと3章辺りなるので、そこを中心に見てみる。

そもプロセスってなんだ?

詳解Linux曰く、

プロセスをプログラムの実行している状態であるとします。
(中略)
カーネルから見ると、プロセスの目的はシステム資源(CPU時間やメモリなど)を割り当てて実体として動かすこと。

プルグラムが何らかの実行単位で処理を実行している状態がプロセス。 この際に必要なリソースは

  • 命令コード向けメモリ(テキスト)
  • プロセス固有データ領域向けメモリ(スタック/ヒープ)
  • プロセッサ状態(コンテキスト):CPUに設定されている情報(SP/PCなど)

辺り。

これらのリソースを各プロセスは所有している。 これに対して、カーネルがプロセスに物理資源(CPU/物理メモリ)をスケジュール管理して割り当てる。

プロセスが生成される時は、基本的にこれらのリソースは親とほぼ同じものを所有している。
ただし、同じものの所有時には、命令コード(テキスト)は共有するが、 それ意外のリソース(スタック/ヒープ)は複製を作成してプログラムを実行する。

このようなプロセスの単位で複数の処理を同時に実行しようとしても、プロセス間での簡単なデータ共有ができない。子プロセスを作る度に、スタック/ヒープといったメモリの複製を作成する必要があり、プロセス作成によるオーバヘッドがある。

なので、データは共有するけど、処理を分けたいという要望があった。そのなかでマルチスレッドの考え方がうまれた。データ領域の一部を共有して複数の処理を同時に実行する。これのような実行形態をマルチスレッドのアプリケーションと呼ぶ。

この考えに対応するためにLinuxでは軽量プロセスを提供している。軽量プロセスでは、幾つかのリソースを共有する。これにより、スレッドのアプリケーションも動作している。

プロセスってどうやって作成するか

カーネルはプロセス生成のためにforkexecの2つのシステムコールを準備している。

  • forkは現在のプロセスをコピーして新たなリソースを作成する。
  • execは自プロセスを別の実行プログラムを読み込み実行する。

今回はタイトルにも在るように、forkシステムコールを読んでいく。
読んでいるkernelは4.2.0

システムコールの呼び出し

毎度ながらLinuxソース上のシステムコールSYSCALL_DEFINEのマクロが使われている。
forkももちろん同様で下記のようにソースは記述されている。

#ifdef __ARCH_WANT_SYS_FORK
SYSCALL_DEFINE0(fork)
{ 
#ifdef CONFIG_MMU
  return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
#else
  /* can not support in nommu mode */
  return -EINVAL;
#endif
}
#endif

これを見ると実体は_do_forkになっており、 clone_flag = SIGCHLDを指定している。
_do_forkはその他のclonevforkシステムコールからも呼び出されるが、処理はclone_flagにて変わるっぽい。

こっから先はざっと目を通したのみ。(全然進んでいない・・・) とりあえず、forkcloneで違いが在る部分、言い換えれば、clone_flagにて処理が変わっている部分に着目してみる。
_do_forkの処理は下記の通リ

  1. copy_processでプロセスディスクリプタカーネルデータ構造の初期化を実施。
  2. get_task_pidで未使用のPIDを探して、子プロセスに新しいPIDを割り当てる

ってところで時間切れ。 とりあえず、なんとなくでもプロセスとスレッドの関係がわかって良かった。