Operating System Lecture No.3
Menu
プロセスとカーネル
プロセスは、一つのコンピュータに、仕事のまとまりを作る。これは、あたかも、そのプロセスが一台のコンピュータを一人で使っているように見える。プロセスには以下の要素が付属している。- メモリ
 - CPU時間
 - コンテキスト
 
複数のプロセスが互いに、不法な方法で干渉しないように、ハードウェアとオペレーティングシステムが管理を行っている。
プロセスの作り方
ここでは、zsh からのプロセスの作り方を勉強しよう。
- コマンドの起動
 - 停止
 - 並列実行
 - バックグラウンドで実行
 - script の取り方
 
コンピュータとバス
ie.u-ryukyu.ac.jp system configuration CPU と外部の機器をつなぐ、バスとチップがある。
CPU から見れば、それはメモリにしか見えない。(I/O port を特別扱いするCPUもある)
Intel® Xeon® Processor Scalable Family Technical Overview
CPU
レジスタの集まりと、それを操作する命令Intel EMT64 64bit mode
register が16本、rip (program counter)を含めて対称的に扱えるようになっている。128bit XMMレジスタが16本。
x86 の命令に関しては、このサイトが便利
x86 Instruction Set Reference 
プロセス
Operating System上にはいろいろなプロセスがあり、それらを一つのCPUが順に実行していく。 コンピュータの基本的な要素は、計算を行なうCPUと結果を格納するメモリやディスクである。
実際には要求される動作には様々なものがあり、それらが一つ一つ、CPUやメモリを必要とする。これを仮想的なコンピュータにまとめたものがプロセスである。それらを、実際のコンピュータの持つ物理的なCPUやメモリに配分する作業を担当するのがOperating Systemである。
num-core
    #!/bin/bash
    if [[ "$OSTYPE" == "linux-gnu"* ]]; then
            # Linux
            ncores=$(nproc)
    elif [[ "$OSTYPE" == "darwin"* ]]; then
            # macOS
            ncores=$(sysctl -n hw.physicalcpu)
    else
            echo "Unknown OS"
            exit 1
    fi
    echo "Number of cores: $ncores"
カーネルとシステムコール
仮想CPUを切替えるためには特別な命令を呼び出す (特権命令)。トラップなどと呼ばれることもある。これらはユーザ側からはシステムコールと呼ばれる。
システムコールの集合がOSのAPI(Application Specific Interface)である。ユーザからはAPIそのものがOSと言って良い。
実際に、特権命令がどこにあるか調べてみよう。
システムコールの例題 これをクリックしないでdown loadして動かす。
gdb の使い方
デバッガの使い方をマスターしよう
    b   break (そこでストップする)
    run run   プログラムの実行を始める
    s   step   一行実行
    n   next   一行実行 (関数呼び出しはパスする)
    c   continue  実行を再開
    p i           変数iを表示
    w   where       関数の呼び出し履歴 (up, down も使おう)
    fi  finish      今実行している関数を終了するところまで実行
    x/20x           memory dump
アセンブラ関係
    stepi          1命令のステップ
    nexti          1命令の実行 (関数呼び出しはパスする)
    x/20i           逆アセンブル
    x/1i $pc        次に実行される命令の表示
    p $eax          レジスタの内容の表示
    info registers
    info threads
引数を指定する
    gdb --args ./command arg
gdb で system call を trace する
dynamlic link code を避けるには?
Intel64 用の.gdbinit PowerPC 用の.gdbinit Intel Mac 用の.gdbinit x86 の命令に関しては、このサイトが便利x86 Instruction Set Reference
lldb の使い方
    b   break (そこでストップする)
    run run   プログラムの実行を始める
    s   step   一行実行
    n   next   一行実行 (関数呼び出しはパスする)
    c   continue  実行を再開
    p i           変数iを表示
    memory read &test_data     meory dump
    regisegr read      register dump   (-a)
    bt              (frame info) 関数の呼び出し履歴 (up, down も使おう)
    fi  finish      今実行している関数を終了するところまで実行
アセンブラ関係
    stepi          1命令のステップ
    nexti          1命令の実行 (関数呼び出しはパスする)
    dissass         逆アセンブル
    p $eax          レジスタの内容の表示
    p (void*)$eax   レジスタの内容の表示 16進
    register read
    thread list
引数を指定する
    lldb  ./command -- arg
lldb で system call を trace する
dynamlic link code を避けるには?
問題3.1
Kernel 側の実装について調べる。Linux Kernel Source syscall から、sys_call_table を引いて、system call のルーチンに飛ぶ。
kernel space は、すべてのプロセスに共通。user space はプロセス毎に分かれている。
プロセスの状態
プロセスうち、いくつかの処理は、特別な扱いを受ける。
    * Interrupt                      CPUに信号が伝わった時点で行われる処理
    * DMA (direct memory access)     CPUを経由しないデータ転送
    * Kernel Process                 Operating System 自身が必要とする仕事
これ以外の処理は、平等に時間分割(Time sharing)されて実行される。
しかし、仕事のないプロセスにCPUを割り当てても意味がない。プロセスには決まった状態があり、そのうち、実行可能な状態のプロセスのみが実行される。
    * new                プロセスが生成された
    * ready              実行可能な状態
    * running            実際に実行されている
    * waiting            何かを待っている
    * terminated         終了中
これらの状態遷移を引き起こす操作には以下のようなものがある。
    * new                fork system call
    * running->waiting   wait system call / I/O call (read/write)
    * waiting->ready     外部からの入力, I/O 終了
    * ready->terminated  kill, exit
コマンド top を動かしてみて、プロセスの動きを観察しよう。
サブルーチンとプロセス生成の違い
この二つの違いは、メモリ空間の扱いが異なることである。サブルーチン呼び出しでは、メモリ空間は元と同じであるが、プロセス生成では、異なるものが呼び出される。サブルーチンには、wait に相当するものがないのは何故だろうか? 考えてみよう。
プロセスとユーザ
su コマンドは何をするものか?sudo コマンドは何をするものか?
setuid bit について理解しよう。
プロセス空間の切替え方は?
ファイル入出力
プロセスの入出力は、システムコール、特に、ファイルを経由して行われる。プロセスがアクセスしているファイルには、プロセスごとに番号がついている。これをファイル・ディスクリプタという。
ディスクリプタには、open system callによって、ファイルシステム上のファイルを結びつけることができる。ファイルだけなく、他のプロセスとの間を結ぶソケットや、その一方向版であるパイプを結びつけることもできる。
Unix では最初の3つのディスクリプタは、ユーザが持つログイン・シェルの入出力に接続されている。
この切り替えはcloseと dupによって行われる。
問題3.2
プロセスが使用しているシステムコールを調べる。fork と exec
fork は、同じメモリ空間上で、異なるコンテキスト(context)を生成する。exec は、同じコンテキストで別なプログラムを実行する。
 Perl で書いた簡単な shell 
相手のプロセスの待ち合わせ(join)は、Unixではwait というシステムコールを使っておこなわれる。
これらの図は、最近では UML を使って記述することが多い。特に、シーケンス図というのをここでは用いる。
例えば、
       % ( du -s /usr/local ; /bin/echo end ) &  
とした時には、以下のようなプロセスの状態遷移が起きる。
問題3.3
Perl による shell の実行で、どのようなプロセスの状態の時間的遷移をUMLの sequence diagram で、記述してみよう。サーバの sequence diagram UMLはなんで書いても良いが、draw.io / OmniGraffle などで書いても良い。(手書きも良いがコンピュータ上ではちょっと...)
Astah を使ってみよう。