セッションとプロセスグループ
プロセスグループ
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man7/credentials.7.html より引用:
各プロセスはセッション ID とプロセスグループ ID を持つ。 これらの ID はどちらも pid_t 型で表現される。 プロセスは、それぞれ getsid(2), getpgrp(2) を使って自分のセッション ID、プロセスグループ ID を取得できる。
fork(2) で生成された子プロセスは親プロセスのセッション ID とプロセスグループ ID を継承する。プロセスのセッション ID とプロセスグループ ID は execve(2) の前後で不変である。
セッションとプロセスグループの概念は、シェルのジョブ制御を行うために 考案されたものである。 プロセスグループ (時には「ジョブ」と呼ばれることもある) は、 同じプロセスグループ ID を共有するプロセスの集まりである。 シェルは、一つのコマンドもしくはパイプラインの実行に使われるプロセス群に 対して一つのプロセスグループを生成する (例えば、コマンド "ls | wc" を実行するために生成される二つのプロセスは 同じプロセスグループに置かれる)。 所属するプロセスグループは setpgid(2) を使って設定できる。 自身のプロセス ID がプロセスグループ ID と同じプロセスは、 そのグループの「プロセスグループ・リーダー」である。
プロセスグループの例)
適当なコマンドを実行。パイプも使ってみる。
別端末からプロセスの状況を確認。(ps の j オプションは BSD job control format.)
[user1@vm03 shtest]$ ./hoge.sh | less
→ hoge.sh, less, sleep 180 はいずれもPGID=4978 で同一プロセスグループ。プロセスグループ・リーダーはPIDがPGIDと等しいhoge.sh。
[user1@vm03 ~]$ ps j
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
4410 4411 4411 1966 pts/0 4978 S 501 0:00 -bash
4437 4438 4438 2029 pts/1 4982 S 501 0:00 -bash
4411 4978 4978 1966 pts/0 4978 S+ 501 0:00 /bin/sh ./hoge.sh
4411 4979 4978 1966 pts/0 4978 S+ 501 0:00 less
4978 4980 4978 1966 pts/0 4978 S+ 501 0:00 sleep 180
4438 4982 4982 2029 pts/1 4982 R+ 501 0:00 ps j
セッション
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man7/credentials.7.html より引用:
セッションは、同じセッション ID を共有するプロセスの集まりである。 ある一つのプロセスグループの全メンバーは同じセッション ID を持つ (つまり、一つのプロセスグループのメンバーは全て同じセッションに所属し、 これにより、セッションとプロセスグループで二階層のプロセス階層が形成できる)。 新たなセッションの生成はプロセスが setsid(2) を呼び出すことで行う。 setsid(2) は、 setsid(2) を呼び出したプロセスの PID と同じ値のセッション ID を持つ 新たなセッションを生成する。 セッションの生成者は「セッション・リーダー」と呼ばれる。
あるセッションの全プロセスは一つの 制御端末 を共有する。 セッションリーダーが最初に端末をオープンした際に制御端末は設定される (open(2) の呼び出しで O_NOCTTY フラグが指定された場合を除く)。 一つの端末は、最大でも一つのセッションの制御端末にしかなれない。
一つのセッションのジョブの中で、フォアグラウンドジョブになれるのは最大でも一つで、そのセッションの他のジョブはバックグラウンドジョブである。 フォアグラウンドジョブだけが端末からの読み込みを行える。 バックグラウンドのプロセスが端末から読み込みを行おうとした場合、 フォアグラウンドジョブを停止させるシグナルである SIGTTIN が所属するプロセスグループに対して送信される。 端末に TOSTOP フラグがセットされていた場合 (termios(3) 参照)、 フォアグラウンドジョブだけが端末への書き込みを行える。 バックグラウンドのプロセスが端末への書き込みを行おうとした場合、 フォアグラウンドジョブを停止させるシグナルである SIGTTOU が生成される。 シグナルを生成する端末キー (例えば 中断キー、通常は control-C) が押された場合、 そのシグナルはフォアグラウンドジョブのプロセスに送信される。
セッションの例)
適当なコマンドを3回実行。3回目は&をつけず、フォアグラウンドで実行。
別端末からプロセスの状況を確認
[user1@vm03 shtest]$ ./hoge.sh &
[1] 5012
[user1@vm03 shtest]$ ./hoge.sh &
[2] 5014
[user1@vm03 shtest]$ ./hoge.sh
[user1@vm03 ~]$ ps ajx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
:
1964 1966 1966 1966 pts/0 5019 Ss 0 0:00 -bash
:
1966 4410 4410 1966 pts/0 5019 S 0 0:00 su - user1
4410 4411 4411 1966 pts/0 5019 S 501 0:00 -bash
:
4411 5012 5012 1966 pts/0 5019 S 501 0:00 /bin/sh ./hoge.sh
5012 5013 5012 1966 pts/0 5019 S 501 0:00 sleep 180
4411 5014 5014 1966 pts/0 5019 S 501 0:00 /bin/sh ./hoge.sh
5014 5015 5014 1966 pts/0 5019 S 501 0:00 sleep 180
4411 5019 5019 1966 pts/0 5019 S+ 501 0:00 /bin/sh ./hoge.sh
5019 5020 5019 1966 pts/0 5019 S+ 501 0:00 sleep 180
:
- SID=1966となっている各プロセスは、同一セッション。
- SID=1966のセッションのセッション・リーダーはbash(PID:1966)。なお、上記psコマンドのSTATの"Ss"の小文字のsはセッション・リーダーであることを示す。
- SID=1966のセッションのフォアグラウンドジョブはPGID=5019のジョブ。なお、上記psコマンドのSTATの"S+"の"+"はフォアグラウンドジョブであることを示す。
- SID=1966のセッションの端末はpts/0である。pts/0は他のどのセッションの端末でもない。
端末 (terminal)
端末とはLinuxに対する標準入出力をLinuxと仲介するもの。
例えば、キーボードで入力した文字列を標準入力としてLinux/Unixに渡したり、標準出力をコンソール上に表示する。
psコマンドなどで表示されるttyやptsも端末のことを指している。
ptsは擬似端末と呼ばれ、telnetやsshなどでログインするとこの端末に接続される。
ttyは仮想コンソールと呼ばれ、Linuxに直接接続している場合に使われる端末である。通常、Linuxの場合、最初の6つの仮想コンソール (/dev/tty1〜/dev/tty6) があり、Alt + ファンクションキー(F1など)で切り替えることができる。
ttyコマンド
以下のように、ttyコマンドで、現在利用している端末デバイスを表示することができる。
[user1@vm03 shtest]$ tty
/dev/pts/0
[参考]
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man7/credentials.7.html
http://equj65.net/tech/linuxprocessgroup/
http://ja.wikipedia.org/wiki/Tty
Ctrl+C と killコマンド の違い
kill : 指定されたプロセスにのみシグナルを送信(プロセスの親子は関係ない)
Ctrl+C : フォアグラウンドのジョブの全プロセスに対してSIGINTを送信
[実験]
以下のようなスクリプトを実行させ、killした場合とCtrl+Cした場合とで挙動の違いを見る。
[user1@vm03 shtest]$ cat hoge.sh #!/bin/sh sleep 180
killコマンドの場合
hoge.sh を実行
[user1@vm03 shtest]$ ./hoge.sh
別端末からプロセスを確認
→hoge.sh のプロセスとsleep のプロセスが両方ある。PGIDは同じ。
[user1@vm03 ~]$ ps jx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
4410 4411 4411 1966 pts/0 4583 S 501 0:00 -bash
4437 4438 4438 2029 pts/1 4585 S 501 0:00 -bash
4411 4583 4583 1966 pts/0 4583 S+ 501 0:00 /bin/sh ./hoge.sh
4583 4584 4583 1966 pts/0 4583 S+ 501 0:00 sleep 180
4438 4585 4585 2029 pts/1 4585 R+ 501 0:00 ps jx
hoge.sh のプロセスをkillで殺す。
[user1@vm03 ~]$ kill 4583
もう一度プロセスを確認
→ sleep プロセスが残った。sleep プロセスの親プロセスのPID は1。つまり init プロセス。
[user1@vm03 ~]$ ps jx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
4410 4411 4411 1966 pts/0 4411 S+ 501 0:00 -bash
4437 4438 4438 2029 pts/1 4587 S 501 0:00 -bash
1 4584 4583 1966 pts/0 4411 S 501 0:00 sleep 180
4438 4587 4587 2029 pts/1 4587 R+ 501 0:00 ps jx
なお、killコマンドはシグナル番号が指定されなかった場合、デフォルトでSIGTERM (シグナル番号:15)を送る。
Ctrl+C の場合
hoge.sh を実行
[user1@vm03 shtest]$ ./hoge.sh
別端末からプロセスを確認
→hoge.sh のプロセスとsleep のプロセスが両方ある。PGIDは同じ。
[user1@vm03 ~]$ ps jx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
4410 4411 4411 1966 pts/0 4591 S 501 0:00 -bash
4437 4438 4438 2029 pts/1 4593 S 501 0:00 -bash
4411 4591 4591 1966 pts/0 4591 S+ 501 0:00 /bin/sh ./hoge.sh
4591 4592 4591 1966 pts/0 4591 S+ 501 0:00 sleep 180
4438 4593 4593 2029 pts/1 4593 R+ 501 0:00 ps jx
元の端末でCtrl+C でhoge.sh を中断する。
[user1@vm03 shtest]$ ./hoge.sh
^C
もう一度hoge.sh のプロセスを確認
→ hoge.sh も sleep プロセスもなくなっている。hoge.sh と同じPGID (PGID:4591) のプロセスに対してすべてSIGINT (シグナル番号:2)が送られたため。
[user1@vm03 ~]$ ps jx
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
4410 4411 4411 1966 pts/0 4411 S+ 501 0:00 -bash
4437 4438 4438 2029 pts/1 4595 S 501 0:00 -bash
4438 4595 4595 2029 pts/1 4595 R+ 501 0:00 ps jx
PGIDが同じプロセス群は「プロセスグループ」という。これは時には「ジョブ」とも呼ばれる。
どうして送られたシグナルがSIGINTであるとわかるか
→ intr = ^C; が、Ctrl+C でSIGINTを送信するということを意味する。
[user1@vm03 shtest]$ stty -a
speed 38400 baud; rows 35; columns 90; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol =; eol2 = ;
:
[まとめ]
kill : 指定されたプロセスにのみシグナルを送信(プロセスの親子は関係ない)
Ctrl+C : フォアグラウンドのジョブの全プロセスに対してSIGINTを送信
OS自作入門 29日目分、30日目分 (読了)
29日目分 圧縮と簡単なアプリケーション
OSのサイズを小さくするため、圧縮ファイルを解凍する機能をOSにつける話など。
他、インベーダーゲームのアプリなど。
30日目分 高度なアプリケーション
この章はOS本体とは直接関係ないので流し読み。
IPLのところだけ詳しく読んだ。BIOSでディスクを読み込む処理で、複数セクタ同時に読み込む機能を使ってディスク読み込みの高速化をしようという話。
全体の振り返り
途中間が空いたが、12/26〜1/12 の18日間で読了となった。30日に収まった。
結局私は本文に沿ってサンプルプログラムを動かしながらOS作りの過程を追っただけで、OSを本当に自作したことにはならなかった。
それでもOS作りの過程を追いながら、これまでOSでブラックボックスだった部分の中身が、少しだけ分かったような気になった。
とくに勉強になったのは、割り込み、タイマー、マルチタスク、APIのところか。
最初はOS作りというといかにも難しそうであったが、思ったよりは難しくなかった。
今後Linuxなど他のOSに触れる際も、「はりぼてOS」との違いを意識しながら見ることで、より深い理解が得られるようになるのではないかと思う。
OS自作入門 27日目分、28日目分
27日目分 LDTとライブラリ
キーワード:LDT(local descriptor table)、ライブラリ
ポイント:
- GDTが全部のタスクから共通に使えるセグメント設定であるのに対し、LDTはあるタスクでしか有効でないセグメント設定
- アプリ用のセグメントをLDTの中で設定すれば、他のタスクからセグメントを破壊されることはない
- ライブラリとは、将来他のプログラムにも使えそうな部品を集めてまとめたもの