の続き。
今日は第3章のプロセス管理を読んだ。
カーネルによるプロセス生成と削除の機能についてだが、仮想記憶の理解がないと詳しい理解が得られないということで、仮想記憶がない単純な場合をもとに話が進んだ。仮想記憶については5章で述べられるようだ。
プロセスに関しては、以前に「なるほどUnixプロセス」を読んでいたため、理解が早かった。
ただ、プログラムがどのようにメモリ上にマップされるかまでは把握してなかったので、
解説の図を見たり、readelfコマンド、/proc/[pid]/maps
ファイルを実際に確認したので、
ざっくりこんなもんかと知れたのは良かった。
ノート
第3章 プロセス管理
- Linuxにおいて、プロセス生成は2つの目的がある
- 同じプログラムの処理を複数のプロセスに分けて処理する
- fork()
- 全く別のプログラムを生成する
- execve()
- 同じプログラムの処理を複数のプロセスに分けて処理する
- fork() 関数
- 発行したプロセスをもとに、新たにプロセスを1つ生成する
- 親プロセス - 子プロセス
- 流れ
- 子プロセス用のメモリ領域を作成して、親プロセスのメモリをコピーする
- 親プロセスと子プロセスは違うコードを時刻するように分岐する
- form()関数の戻り値が、親プロセスと子プロセスの間で異なることを利用する
- 発行したプロセスをもとに、新たにプロセスを1つ生成する
- execve() 関数
- 流れ
- 実行ファイルを読み出して、プロセスのメモリマップに必要な情報を読み出す
- コードを含むデータ領域のファイル上オフセット、サイズ、およびメモリマップ開始アドレス
- コード以外の変数などデータ領域ついての上記と同じ情報
- 最初に実行する命令のメモリアドレス(エントリポイント)
- 現在のプロセスのメモリを新しいプロセスのデータで上書きする
- 新しいプロセスの最初の命令から実行開始する
- 流れ
- https://qiita.com/zacky1972/items/ef4486e8a6d95edb68fd
- CPUは レジスタ (register, processor register) と呼ばれる小規模な記憶装置を持っている
- レジスターはメモリと比べて記憶容量が小さいが,その代わりとても高速に読み書きすることができる
- Linuxの実行ファイルは Executable Linkable Format(ELF)というフォーマットを使用する
- readelfコマンドで確認できる
- 開始アドレスを得る場合は「-h」オプション
- コードとデータのファイル内オフセット、サイズ、開始アドレスを得る場合は「-S」オプション
- 「.text」なのがコード領域の情報、「.data」なのがデータ領域の情報
- readelfコマンドで確認できる
- プログラム実行時に作成されたプロセスのメモリマップは、
/proc/[pid]/maps
というファイルで得られる
cat /proc/29537/maps 55e16a5e9000-55e16a5f0000 r-xp 00000000 fc:02 1048708 /bin/sleep 55e16a7f0000-55e16a7f1000 r--p 00007000 fc:02 1048708 /bin/sleep 55e16a7f1000-55e16a7f2000 rw-p 00008000 fc:02 1048708 /bin/sleep 55e16ac85000-55e16aca6000 rw-p 00000000 00:00 0 [heap] 7f9cccce9000-7f9ccce5c000 r--p 00000000 fc:02 131771 /usr/lib/locale/C.UTF-8/LC_COLLATE 7f9ccce5c000-7f9ccd043000 r-xp 00000000 fc:02 1185282 /lib/x86_64-linux-gnu/libc-2.27.so 7f9ccd043000-7f9ccd243000 ---p 001e7000 fc:02 1185282 /lib/x86_64-linux-gnu/libc-2.27.so 7f9ccd243000-7f9ccd247000 r--p 001e7000 fc:02 1185282 /lib/x86_64-linux-gnu/libc-2.27.so 7f9ccd247000-7f9ccd249000 rw-p 001eb000 fc:02 1185282 /lib/x86_64-linux-gnu/libc-2.27.so 7f9ccd249000-7f9ccd24d000 rw-p 00000000 00:00 0 7f9ccd24d000-7f9ccd274000 r-xp 00000000 fc:02 1185270 /lib/x86_64-linux-gnu/ld-2.27.so 7f9ccd295000-7f9ccd2c6000 r--p 00000000 fc:02 131773 /usr/lib/locale/C.UTF-8/LC_CTYPE 7f9ccd2c6000-7f9ccd2c7000 r--p 00000000 fc:02 131778 /usr/lib/locale/C.UTF-8/LC_NUMERIC 7f9ccd2c7000-7f9ccd2c8000 r--p 00000000 fc:02 131781 /usr/lib/locale/C.UTF-8/LC_TIME 7f9ccd2c8000-7f9ccd2c9000 r--p 00000000 fc:02 131776 /usr/lib/locale/C.UTF-8/LC_MONETARY 7f9ccd2c9000-7f9ccd2ca000 r--p 00000000 fc:02 131782 /usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES 7f9ccd2ca000-7f9ccd2cb000 r--p 00000000 fc:02 131779 /usr/lib/locale/C.UTF-8/LC_PAPER 7f9ccd2cb000-7f9ccd2cc000 r--p 00000000 fc:02 131777 /usr/lib/locale/C.UTF-8/LC_NAME 7f9ccd2cc000-7f9ccd2cd000 r--p 00000000 fc:02 131770 /usr/lib/locale/C.UTF-8/LC_ADDRESS 7f9ccd2cd000-7f9ccd2ce000 r--p 00000000 fc:02 131780 /usr/lib/locale/C.UTF-8/LC_TELEPHONE 7f9ccd2ce000-7f9ccd2cf000 r--p 00000000 fc:02 131775 /usr/lib/locale/C.UTF-8/LC_MEASUREMENT 7f9ccd2cf000-7f9ccd46a000 r--p 00000000 fc:02 145331 /usr/lib/locale/locale-archive 7f9ccd46a000-7f9ccd46c000 rw-p 00000000 00:00 0 7f9ccd46c000-7f9ccd473000 r--s 00000000 fc:02 137960 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache 7f9ccd473000-7f9ccd474000 r--p 00000000 fc:02 131774 /usr/lib/locale/C.UTF-8/LC_IDENTIFICATION 7f9ccd474000-7f9ccd475000 r--p 00027000 fc:02 1185270 /lib/x86_64-linux-gnu/ld-2.27.so 7f9ccd475000-7f9ccd476000 rw-p 00028000 fc:02 1185270 /lib/x86_64-linux-gnu/ld-2.27.so 7f9ccd476000-7f9ccd477000 rw-p 00000000 00:00 0 7ffd81948000-7ffd81969000 rw-p 00000000 00:00 0 [stack] 7ffd819ad000-7ffd819b0000 r--p 00000000 00:00 0 [vvar] 7ffd819b0000-7ffd819b2000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
- プログラム終了には「_exit()」関数(内部的にはexit_group()システムコール)を呼ぶ
- プロセスに割り当てていたメモリをすべて回収する