# プロセスグループ/セッションってなに? - シェルもどきをgoで自作する #16 ## おさらい これまで - [シェルってなに?コマンドラインインタプリタってなに? - シェルもどきをgoで自作する#1](https://hackmd.io/@jyami/HJzohRn2D) - [コマンドと引数の分解、環境変数PATHから探索、外部コマンドと内部コマンド - シェルもどきをgoで自作する #2](https://hackmd.io/@jyami/HyeSkkThP) - [字句解析その1 - シェルもどきをgoで自作する #3](https://hackmd.io/@jyami/Hk3bWSMQO) - [字句解析その2 - シェルもどきをgoで自作する #4](https://hackmd.io/@jyami/S1BkltxQu) - [リダイレクションってなに? - シェルもどきをgoで自作する #5](https://hackmd.io/@jyami/S113NQx8u) - [リダイレクションの種類 - シェルもどきをgoで自作する #6](https://hackmd.io/@jyami/rJ3XmClqd) - [リダイレクションの構文 - シェルもどきをgoで自作する #7](https://hackmd.io/@jyami/BJ04J2Upd) - [コマンドプロセスを作成する際のファイルディスクリプタの操作 - シェルもどきをgoで自作する #8](https://hackmd.io/@jyami/Hy7nSciMt) - [構文解析と抽象構文木 - シェルもどきをgoで自作する #9](https://hackmd.io/@jyami/ByrK1ajIK) - [パイプってなに? - シェルもどきをgoで自作する #10](https://hackmd.io/@jyami/SkXR3iltK) - [ワイルドカードってなに? - シェルもどきをgoで自作する #11](https://hackmd.io/@jyami/SJghKSl3F) - [環境変数ってなに? - シェルもどきをgoで自作する #12](https://hackmd.io/@jyami/H12wYg4L9) - [環境変数の設定と環境変数の展開 - シェルもどきをgoで自作する #13](https://hackmd.io/@jyami/Hy3EefRgj) - [シェル変数との違いからみた環境変数 - シェルもどきをgoで自作する #14](https://hackmd.io/@jyami/ByxFrm6Si) - [シェル変数を実装 - シェルもどきをgoで自作する #15](https://hackmd.io/@jyami/rJf5GFRhs) シェルもどき「[oreshell](https://github.com/jyami/oreshell)」を自作している。 前回はシェル変数を実装した。 今回からジョブ制御の実現を目指そう、と息巻いていたが、いろいろ調べるとジョブ制御の前に「プロセスグループ/セッション」のことを理解しておく必要があるらしい。 自分は理解できていないので、まずは「プロセスグループ/セッションってなに?」ってとこから。 ## プロセスグループ/セッションってなに? ジョブ制御との関係は? [Linux Programmer's Manual (7) CREDENTIALS](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/credentials.7.html)を読むと > 各プロセスはセッション ID とプロセスグループ ID を持つ。 (中略) > セッションとプロセスグループの概念は、シェルのジョブ制御を行うために 考案されたものである。 とある。 「プロセスグループ/セッション」はジョブ制御のために生まれたらしい。へえー。 [wikipedia](https://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%BB%E3%82%B9%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97)には > プロセスグループへのシグナル送信は、シェルプログラムが使用するジョブコントロールの基本となっている。 とある。シェルがジョブ制御をするときはプロセスグループに対してシグナルを送るらしい。 ## プロセスグループってなに? [Linux Programmer's Manual (7) CREDENTIALS](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/credentials.7.html)の続きを読む。 > プロセスグループ (時には「ジョブ」と呼ばれることもある) は、 同じプロセスグループ ID を共有するプロセスの集まりである。 シェルは、一つのコマンドもしくはパイプラインの実行に使われるプロセス群に 対して一つのプロセスグループを生成する (例えば、コマンド "ls | wc" を実行するために生成される二つのプロセスは 同じプロセスグループに置かれる)。 (中略) > 自身のプロセス ID がプロセスグループ ID と同じプロセスは、 そのグループの「プロセスグループリーダー」である。 いま、手元のlinux環境(wsl2 ubuntu2022)のbashから「ps -ejH」(osxなどのBSD系だと「ps axjf」か?)を実行すると ``` $ ps -ejH PID PGID SID TTY TIME CMD 1 0 0 ? 00:00:00 init(Ubuntu) 4 0 0 ? 00:00:01 init 25175 25175 25175 ? 00:00:00 SessionLeader 25176 25175 25175 ? 00:00:00 Relay(25177) 25177 25177 25177 pts/0 00:00:00 bash 19792 19792 25177 pts/0 00:00:00 ps ``` と表示した。 「PID」はプロセスID。 その隣の「PGID」がプロセスグループID。 ここで処理時間が長そうなパイプライン処理、例えば ``` $ grep -s -r hoge / | sort > /dev/null 2>&1 > /dev/null & ``` を実行し、もう一度「ps -ejH」を実行すると ``` $ ps -ejH PID PGID SID TTY TIME CMD 1 0 0 ? 00:00:00 init(Ubuntu) 4 0 0 ? 00:00:01 init 25175 25175 25175 ? 00:00:00 SessionLeader 25176 25175 25175 ? 00:00:00 Relay(25177) 25177 25177 25177 pts/0 00:00:00 bash 19812 19812 25177 pts/0 00:00:45 grep 19813 19812 25177 pts/0 00:00:00 sort 19816 19816 25177 pts/0 00:00:00 ps ``` と表示した。 「grep」の「PID」と「PGID」は「19812」、 「sort」の「PGID」は「19812」である。 先の説明の > シェルは、一つのコマンドもしくはパイプラインの実行に使われるプロセス群に 対して一つのプロセスグループを生成する > 自身のプロセス ID がプロセスグループ ID と同じプロセスは、 そのグループの「プロセスグループリーダー」である。 と照らし合わせると、 - 「grep」と「sort」は同じプロセスグループに属する。(パイプライン処理で「grep」「sort」を実行しているため) - 「bash」はプロセスグループリーダーである。 - 「grep」はプロセスグループリーダーである。 - 「ps」はプロセスグループリーダーである。 であることがわかる。 (「Relay」より上のプロセスのことはよくわからんので説明はパス。「SessionLeader」「Relay」はwslの仕掛けっぽい。) ## セッションってなに? 次はセッションの話。 [Linux Programmer's Manual (7) CREDENTIALS](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/credentials.7.html)の続きを読む。 > セッションは、同じセッション ID を共有するプロセスの集まりである。 ある一つのプロセスグループの全メンバーは同じセッション ID を持つ (つまり、一つのプロセスグループのメンバーは全て同じセッションに所属し、 これにより、セッションとプロセスグループで二階層のプロセス階層が形成できる)。新たなセッションの生成はプロセスが setsid(2) を呼び出すことで行う。 setsid(2) は、 setsid(2) を呼び出したプロセスの PID と同じ値のセッション ID を持つ 新たなセッションを生成する。セッションの生成者は「セッションリーダー」と呼ばれる。 セッションとはログインセッションのことだと思われる。 先ほどの「ps -ejH」の結果をもう一度見てみる。 ``` $ ps -ejH PID PGID SID TTY TIME CMD 1 0 0 ? 00:00:00 init(Ubuntu) 4 0 0 ? 00:00:01 init 25175 25175 25175 ? 00:00:00 SessionLeader 25176 25175 25175 ? 00:00:00 Relay(25177) 25177 25177 25177 pts/0 00:00:00 bash 19812 19812 25177 pts/0 00:00:45 grep 19813 19812 25177 pts/0 00:00:00 sort 19816 19816 25177 pts/0 00:00:00 ps ``` 「SID」がセッションID。 「bash」の「SID」が「25177」である。 その下の「grep」「sort」「ps」の「SID」も「25177」である。 > 新たなセッションの生成はプロセスが setsid(2) を呼び出すことで行う。 setsid(2) は、 setsid(2) を呼び出したプロセスの PID と同じ値のセッション ID を持つ 新たなセッションを生成する。セッションの生成者は「セッションリーダー」と呼ばれる。 とあるので、「bash」が「セッションリーダー」であることがわかる。(たぶんログインシェル) また、 > セッションは、同じセッション ID を共有するプロセスの集まりである。 とあるので、「bash」「grep」「sort」「ps」は同じセッションに属することがわかる。 ## プロセスとプロセスグループとセッション(と制御端末)の関係 [Linux Programmer's Manual (7) CREDENTIALS](https://linuxjm.osdn.jp/html/LDP_man-pages/man7/credentials.7.html)の続きをもう少し読む。 > あるセッションの全プロセスは一つの 制御端末 を共有する。 セッションリーダーが最初に端末をオープンした際に制御端末は設定される(中略)。 一つの端末は、最大でも一つのセッションの制御端末にしかなれない。 「ps -ejH」の結果の「TTY」が制御端末を表す。 「ps -ejH」の結果をもとに、制御端末とセッションとプロセスグループとプロセスの関係を以下に図で表す。 ![](https://hackmd.io/_uploads/r1Y-TwXD2.png) ## で、oreshellはプロセスグループに対応しているの? oreshellでパイプライン処理を実行するときに、パイプライン内の各プロセスにプロセスグループIDを与えていない。(当時はプロセスグループなんてものを知らなかったので) 次回は、oreshellのプロセスグループ対応の実装を行う。