class: title, smokescreen, shelf, no-footer # プロセス <div class=footnote> <small> </small> </div> --- class: img-right,compact # [体感しよう] AWS Academyへログインしてください <div class=footnote> <small> (脚注) 自分のEC2で試してもokですが、表示されるものが上の説明とは少し異なります </small> </div> ![](../../../service/aws/academy/images/vocareum-logined.png) - せっかくなので、AWS Academy (vocareum)を使っていきます。 まずはログインしてください。 - 右図のページになりましたか? - 次頁からは、 中央のターミナル(`謎の文字列:~$`のところ)にコマンドを入力・実行していきます - 用語**プロンプト(prompt)**: このユーザからの入力待ちをしている`謎の文字列:~$ `のこと。 --- class: compact # [体感しよう] psを試してみよう <div class=footnote> <small> (脚注1) psの結果に出てくる数字やプロンプトは各自ことなります。 PID TTY ...の行は常に同じですけど <br> (脚注2) 自分のEC2で試してもokですが、表示されるものが上の説明とは少し異なります </small> </div> - ターミナルで`ps`コマンドを実行してください <small> <b> - [注意]技術文書の「XXXコマンドを実行」は 「プロンプト(の右側に) XXXコマンドを入力後、Enterを押す」という意味ですが、 いちいちプロンプトやEnterの話は書きません(省略,暗黙の了解) </b> </small> ``` ddd_v1_w_n3e_1475134@runweb63730:~$ ps PID TTY TIME CMD 15246 pts/51 00:00:00 bash 27531 pts/51 00:00:00 ps ddd_v1_w_n3e_1475134@runweb63730:~$ ``` <small> - あなたが実行している**プロセス**(群)が、ここで表示された`bash`や`ps`です。 `ps`は、いま実行した`ps`コマンドそのものです。 `bash`は、 プロンプト`ddd_v1_w_n3e_1475134@runweb63730:~$ `を出して、 ユーザからのコマンド入力を待ち受けするプログラムのことです。 この待ち受けをするプログラム群は**シェル**と総称されます </small> --- class: img-right,compact # [体感しよう] 図にしてみる(1): ps <div class=footnote> <small> (脚注1) わかりやすさ優先で(不正確に)なっています。 たとえば、入出力もOS(kernel)がデバイスを制御して行うものなので、 もっとOSがあいだに挟まる図が正しいのですが、 真面目に書くと混乱するので省略しています <br> (脚注2) 図には次頁の内容まで書きこまれています。詳細は次頁を待て <br> (脚注3) より正確には、 Unixでは全プロセスに対し後述の「実行遷移」より細かい情報を表示します。 例: さまざまな待ち状態や死にかけなども表示されます (消滅時は一旦zombie状態になり死神(reaper)が回収<-本当) </small> </div> ![](images/ps-on-bash.png) <small> 1. シェル(今の場合bash)は待ち受け担当です 1. キーボードからの入力はシェルへ渡されます 1. シェルは渡されたコマンドを実行します(OSへ実行を依頼します) - psコマンドを実行すると、 その瞬間に実行されていたプロセスがすべて表示されます 1. OSはコマンドを実行し結果をシェルへ返します 1. シェルがモニタへ出力します </small> --- class: compact # [体感しよう] ps xを試してみよう <div class=footnote> <small> (脚注) ttydはvocareumオリジナルなのでEC2でps xを実行しても表示されません。EC2では代わりにsshdでしょう </small> </div> ``` ddd_v1_w_n3e_1475134@runweb63730:~$ ps x PID TTY STAT TIME COMMAND 5003 pts/51 R+ 0:00 ps x 15202 ? S 0:00 /usr/local/vocareum/tools/ttyd/ttyd.1.6.3.voc.ub16 --port 48177 --once /bin/bash -c /bin/bash --rcfile /mnt/vocwork5/dd 15246 pts/51 Ss 0:00 /bin/bash --rcfile /mnt/vocwork5/ddd_v1_w_n3e_1475134/asn1241523_1/asn1241524_1/work/.termrc -i ddd_v1_w_n3e_1475134@runweb63730:~$ ``` <small> - `ps x`コマンドを実行した結果、表示されるプロセスが一つ増えました `/usr/local/vocareum/tools/ttyd/ttyd.1.6.3.voc.ub16 ...以下略...`です - この出力では、2列目が`?`です。 これは端末と無関係に実行されているプロセスを意味します。 シェルへの入出力はなく、 ひっそりと裏側で仕事をしつづけるプロセスです。 シェルはユーザのお相手をする言わば表側(foreground)のプロセスですが、 その対極にある「`?`=端末と関係がない」プロセスはbackground processとも呼ばれます。 歴史的に、Unixでは、こういったプロセスを**デーモン(daemon)**と呼んでいます。 **WWWサーバ**などの**サーバのたぐい**は、みな**デーモン**です (演習はdaemonの設定がたくさん!) </small> --- class: img-right,compact # [体感しよう] 図にしてみる(2): ps x <div class=footnote> <small> (脚注1) わかりやすさ優先で(不正確に)なっています。 たとえば、入出力もOS(kernel)がデバイスを制御して行うものなので、 もっとOSがあいだに挟まる図が正しいのですが、 真面目に書くと混乱するので省略しています <br> (脚注2) ps auxwwが定番のコマンドです。 aオプションは全ユーザ分を表示、 uオプションは色々な情報、 wwオプションでコマンドの引数も省略せず最大限の情報を表示できます。 あと、たまにeオプションも重要 </small> </div> ![](images/ps-on-bash.png) <small> 1. シェル(今の場合bash)は待ち受け担当です 1. キーボードからの入力はシェルへ渡されます 1. シェルは渡されたコマンドを実行します(OSへ実行を依頼します) - psコマンドを実行した瞬間に実行されていたプロセスがすべて表示されます。 xオプションをつければデーモンも表示(脚注も参照) 1. OSはコマンドを実行し結果をシェルへ返します 1. シェルがユーザの画面(モニタ)へ出力します </small> --- class: compact # [体感しよう] ps x の表示の意味 <div class=footnote> <small> (脚注1) 中間試験では無視してokですが演習には必要; Unix用語なので基本情報には出ない,LPICには出ると思う <br> (脚注2) TTYはテレタイプという古代の端末に由来する用語; そもそも今のTTYは、みな擬似的な端末(pseudo terminal)です。 というわけでTTYの管理番号はpty/0とかpts/1という名称になります (p = psuedo)。 ?=端末なし </small> </div> <small> ``` ddd_v1_w_n3e_1475134@runweb63730:~$ ps x PID TTY STAT TIME COMMAND 5003 pts/51 R+ 0:00 ps x 15202 ? S 0:00 /usr/local/vocareum/tools/ttyd/ttyd.1.6.3.voc.ub16 --port 48177 --once /bin/bash -c /bin/bash --rcfile /mnt/vocwork5/dd 15246 pts/51 Ss 0:00 /bin/bash --rcfile /mnt/vocwork5/ddd_v1_w_n3e_1475134/asn1241523_1/asn1241524_1/work/.termrc -i ``` 各列の意味は次のとおりです - PID ..... Process ID; 文字どおり(OSがプロセスを管理するための)番号 - TTY ..... TeleTYpe;ユーザの実行環境(シェル)と結びついている端末(terminal)の番号 - STAT ... STATus (ステータス); 現在の状態(後述の「プロセスの状態遷移」より区分は細かい)です - TIME ... コマンドの実行時間 </small> --- class: compact # [体感しよう] まとめ <small>〜 psコマンドで分かったこと 〜</small> <div class=footnote> <small> 次頁からは、いったん用語に戻り、もう少し細かな解説に入ります </small> </div> - OSでは常に**複数のプログラムが動いている**(例: bash, ps, ttyd, sshd ...) - (大雑把に言えば)動いているプログラムを**プロセス**と呼ぶ - 疑問: CPUは一度に一つのことしか出来ないのでは? 同時に複数のプログラムを動かしているらしいけれど、一体どう動かしているのか? <br> -> **マルチプログラミング(マルチタスク)**(後述) - ユーザからの入力を待ち受けするプロセスを**シェル**と呼ぶ - サーバなどは**デーモン**プロセス。ユーザと直接の入出力はしない - 前頁では、詳細を説明しませんでしたが、 ps x の表示の3列目(STAT=ステータス)はプロセスの状態を表示しています。 いろいろな状態がありますよね? <br> -> プロセスの**状態遷移**の話へ続く(後述) --- class: img-right,compact # 【用語】仕事の処理単位 <div class=footnote> <small> (脚注) 汎用機文化では「ジョブを流す」とか言うし、 この手の用語の話は、 どちらかというと汎用機とか規格を決めたがる人たちの文化の雰囲気があります。 実際、Unixではjobとtaskとprocessをきちんと分けて使い分けてないですし... (例: processから起動したjobのcontrol) </small> </div> ![height120px](images/super_businessman.png) ![height320px](images/job_tasks.png) - コンピュータ->**ジョブ**->**タスク**と細分化 - **ジョブ**=ユーザがコンピュータに指示する単位、 **タスク**は**ジョブ**を分解したもので、コンピュータからみた仕事の単位 (そういう用語がある) - 以下、本稿ではOS上での仕事の単位を**プロセス**と呼びますが、 OS内部を解説する本稿の文脈ではタスクとプロセスは同義語です (Unixではプロセス、(Mach由来の)MacOSXやWindowsではタスクと呼んでいます) --- class: img-right,compact # 【用語】Unixにおけるプロセス <div class=footnote> <small> (脚注1) プロセスの詳細は覚えなくてOK。 TEXTやスタックなどについては本スライドの付録で解説しています (脚注2) ユーザプロセスを動かす環境を<B>ユーザランド(userland)</B>と呼びます。 <b>構築演習==ほぼユーザランドの操作</B> </small> </div> ![height240px](../basic/images/os_ring_model.png) ![height240px](../basic/images/kunsei_egg.png) ![height240px](images/easter_bunny.png) - プログラムが動く際には次のようなデータやメモリ領域、CPUの設定、管理情報が必要で、 これらの総体が**プロセス** <small> - **メモリ**上に置かれたコード(プログラムの命令の実体,**TEXT領域**) - **メモリ**上の変数や**スタック**領域 - **仮想記憶**システムの管理情報 - CPUの**レジスタ** - 開いているファイルの情報など </small> - プロセスには**特権**あり/なしの2種類 <small> - **カーネル (kernel)** ... 特権あり - ユーザ (user) ... 特権なし - 図(右)のような階層モデルで**内側が特権(中央がkernel、外がuser)**と考える </small> --- class: img-right,compact # プロセスの状態遷移とマルチプログラミング <div class=footnote> <small> (脚注1) <B>マルチタスク</B>も同意語 (脚注2) 実行状態プロセスが一つだけなのはコア数1の場合,複数コアの話は割愛 </small> </div> ![height240px](images/state_transition.png) ![height240px](images/multitask.png) - プロセスには3つの状態があります: **実行可能状態、実行状態、待ち状態**(右上図) - ある瞬間の**実行状態プロセスは一つだけ** - どのプロセスを実行状態にするかを決めるのが**スケジューラ**で、 たとえば1/100秒ごとに実行状態プロセスを切り替え、 人間の目にはプロセスが同時実行されている幻影をみせています。 この動作を**マルチプログラミング**と呼びます(右下図) <small> (アニメと同じ = 1秒間に24枚絵を動かせば人間には絵が動いてみえる) </small> --- class: img-right,compact # スケジューラとディスパッチャ ![height240px](images/state_transition.png) ![height240px](images/multitask.png) - 実行可能状態のプロセス候補の中から、 次に、 どのプロセスを実行状態にするかを決めるのが**スケジューラ**です - 選ぶ方法=**スケジューリングアルゴリズム**の代表例は <small> - ラウンドロビン方式 ... 順番に一定時間かわりばんこに実行 - **優先度方式** ... プロセスごとに優先度という概念があり、 再計算して適切なものを選ぶ。 「**対話的プロセスを優先**」などの細かい調整が出来るのでTSS向き </small> - 実行可能状態へ移行する処理をディスパッチ(dispatch)、 担当するプログラムを**ディスパッチャ**(dispather)と呼びます --- class: col-2,compact # マルチプログラミングのメリットとデメリット - メリットはOS全体での**利用効率向上** <small> - タイムシェアリングシステム(TSS)はコンピュータを**対話**的に使う方法です。 OSはキーボードやマウスからの入力を待ち、処理し、結果を出力 - あまりにも違う**デバイス間の速度の差**を相殺できます。 CPU、メモリ、HDD、キーボード入力やマウス操作には桁ちがいの処理速度の違いがあります。 例えば、キーボード入力を一文字待つあいだにCPUは数億回の足し算ができます - プロセスAが待ち状態のときにプロセスBを実行すればCPUが遊んでいる時間がなくなりますよね? 例:キーボード入力待ちやHDDへの入出力が始まれば、待つあいだに別のプロセスを実行 </small> <wbr> - デメリットは**コンテキスト切替**(後述)のオーバヘッド <small> - TSSでは、 このオーバヘッドがあってもメリットが大きいと判断されているわけです </small> --- class: img-right,compact # コンテキスト切り替え <div class=footnote> <small> (脚注1) コンテキスト切り替えは、英語でcontext switchです <br> (脚注2) 基本情報レベルでは<B>太字の用語だけでOK</B>です。 実際のコードがないと分からないでしょうけど、かなり大ごとになるので割愛します。 モヤモヤする人はUnix kernelのソースコードを読もう </small> </div> ![height240px](images/multitask.png) - プロセスの構成要素をコンテキスト(context)と呼んでいます。 プロセスを再現できる制御情報のすべて(前述のプロセスの総体と同義)のことです <small> - CPUレジスタの値,メモリ管理情報,カーネルのもつプロセス制御情報,ファイル他 </small> - **コンテキスト切り替え**とは <small> - プロセス1のコンテキストを保存 - プロセス3のコンテキストを読み出し再設定 - プロセス3を実行する(走らせる) </small> --- class: img-right,compact # プリエンプション(Preemption) <div class=footnote> <small> (脚注1) <b>割りこみ</B>(interrupt)は第4回に解説します <br> (脚注2) 基本情報レベルでは<B>太字の用語だけでOK</B>です。 実際のコードがないと分からないでしょうけど、かなり大ごとになるので割愛します。 モヤモヤする人はUnix kernelのソースコードを読もう </small> </div> ![height240px](images/multitask.png) - **プリエンプション**(Preemption) - Preemptとは強引に横取りすること - コンテキスト切り替えの実際 <small> 1. (割りこみがかかり)プロセス1がPreemptされ処理が中断 1. カーネルに制御が移り 1. プロセス1のコンテキストを退避(保存) 1. カーネルの**スケジューラ**が次に実行状態にするプロセス(3)を決定し 1. プロセス3のコンテキストを回復 1. カーネルからプロセス3に切り替わり、プロセス3の実行を開始 </small> --- class: col-2,compact # <small>【余談】きみはコンテキスト切り替えがイメージできるか?</small> <small> - 次の動作をイメージしながらkernelソースコードが読めるか?/納得できるか?次第で、 **OS動作の分かりづらさ**が変わってくると思います 1. 並列実行されているかもしれない 1. 突然、任意の場所で中断/再開がありうる ![height240px](images/preemption.png) <wbr> - いまどきのOSはFully Preemptiveに書かれていて、 [アセンブリ言語](../cpu/#disassembled-loop) の任意の場所(行単位)で中断がかかります - C言語で表現すると、 一行単位どころではなく一行の途中で突然中断し再開がいつか?も不明な振る舞いです (C言語をアセンブリ言語に翻訳すると一行が数倍に膨れ上がるのが普通で、 そのアセンブリ言語の任意の行で中断/再開します。 左のコード例でいえばforループの条件部`i < 10`ですら条件判定の途中で中断がありえます) </small> <div class=footnote> <small> (脚注) このページ以降、中間試験とは無関係です </small> </div> --- class: title, smokescreen, shelf, no-footer # プロセスのメモリレイアウト <div class=footnote> <small> (脚注) このあとは中間試験の範囲外。メモリ上のデータ配置の説明です。 アタックされるとき、どこが狙われるのか?などを理解するために必要な発展的内容になります </small> </div> --- class: img-right,compact # 【用語】プロセスの定義 <div class=footnote> <small> (脚注) ユーザプロセスを動かしている環境のことを<B>ユーザランド(userland)</B>と呼びます </small> </div> ![height240px](../basic/images/os_ring_model.png) ![height240px](../basic/images/kunsei_egg.png) ![height240px](images/memory_layout.png) ![height240px](images/easter_bunny.png) - プログラムが動く際には次のようなデータやメモリ領域、CPUの設定などが必要で、 これらの総体を**プロセス**と呼ぶ <small> - **メモリ**上に置かれたコード(プログラムの命令の実体,**TEXT領域**) - **メモリ**上の変数や**スタック**領域 - **仮想記憶**システムの管理情報 - CPUの**レジスタ** - 開いているファイルの情報など </small> - プロセスには**特権**あり/なしの2種類 <small> - **カーネル (kernel)** ... 特権あり - ユーザ (user) ... 特権なし - 図(右)のような階層モデルで**内側が特権(中央がkernel、外がuser)**と考える </small> --- class: img-right,compact # プロセスのメモリ空間レイアウトの例 <div class=footnote> <small> (脚注1) 応用情報のレベル (脚注2) <B>メモリレイアウトの詳細を気にしなくてOK(OSの有り難味)</B> </small> </div> ![height480px](images/memory_layout.png) - 右図のアドレスは下が小さく(0)->上が大 - 理論上の最大値は32ビットCPUが4GB(=32bit)、64ビットは16EB - レイアウト(上から下へ解説) <small> - 上から下へ**スタック**領域が伸びる <br> (関数呼び出しで利用) - 真ん中あたりは未使用 - データやローカル変数の領域 - アドレスの小さい側にTEXT領域 - みなさんのa.outの実体はここ - 0バイト付近には割り込みの定義 </small> - **どのプロセスでも同じレイアウト**です。 衝突しないの? -> これは物理ではなく**仮想メモリアドレス** (詳細は[仮想記憶](/slides/os/internal/memory/)) --- class: img-right,compact # プロセスのメモリ空間レイアウトと5大装置の動作例 ![height480px](images/memory_layout.png) <small> 1. kernelは、 **補助記憶装置**(HDDやSSDなどのストレージ)からデータを読み出し、 メモリ上の適切な場所へ配置、スタックなども初期化 1. CPUはメモリ上におかれた機械語を解釈しながら処理を進めます - 処理とは**制御**や**演算**のことですが、 キーボードやマウスからの**入力**を受け付けたり、 処理結果の**出力**も行います(-> [割り込み](../trap/)) 1. 処理を進めていき、ローカル変数のメモリが必要(例: malloc)になると、 ローカル変数用の領域(TEXT領域の上)に確保 1. 関数呼び出しの際の引数を置く場所はスタック領域です (関数呼び出しを重ねるほどスタックは下に伸びます) </small>