51
UNIX の設計思想 井上直人 2015/01/21

Unix architecture

Embed Size (px)

Citation preview

UNIX の設計思想井上直人

2015/01/21

目次•目的

•対象者

•効果・効能

•歴史

• カーネル

•システムコール

•リソース

•プロセス

•ファイルディスクリプタ

•終了コード

•パイプ

• fork

• まとめ

•ここから先は

•参考文献

•その他

目的

UNIX の仕組みと哲学を学び コンピュータープログラミングを

楽しくハックする

対象者

• 低レイヤーで動くプログラムをよく知らない

• UNIX に興味はあるけど C言語 を覚えるのは大変

• コマンドは使えるけど、なぜそう使うのか分からない

効果・効能

• 明日から使える特効薬ではありません

• いつか役に立ちます・・・

• 過剰摂取は身を滅ぼします

歴史

• 1969年に AT&T のベル研究所で UNIX が誕生 • ゲームがしたかったから研究所の端に転がっていたPDP-7 にゲームプログラムを移植

• アセンブリで書かれていたものを C言語 で書きなおした

• UNIX と C言語 はともに成長していった

歴史• デニス・リッチー 2011年逝去 FreeBSD 9.0 や RedHat16 のリリースノートにメッセージが添えられている 「プログラミング言語C」の著者 !

• ケン・トンプソン 正規表現の普及に貢献 ラインエディター ed は正規表現の機能があった UTF-8 の開発 次世代 UNIX と謳われた幻の OS Plan9 での成果 Google で Go 言語の開発

!

• ブライアン・カーニハン Hello World を B言語 のチュートリアルで最初に用いた 「プログラミング言語C」の著者

カーネル

• CPU • メモリ • ハードディスク • BDドライブ • グラフィックボード • ネットワークカード • サウンドカード

OS の機能の 中心 となる部分 = カーネル

カーネル

低レイヤーの機能を抽象化し API として提供する !

システムコール を呼び出して仕事を依頼する

システムコール

コマンドをトレースしてどんなシステムコールが 呼ばれているのか調べてみよう

Mac$ sudo dtruss -a command

Linux$ sudo strace command

システムコール

$ man open # Mac のオープンコマンド$ man 2 open # システムコールの open()

システムコールを man で参照するには セクション 2 をみる

システムコール

セクション情報は以下の4つ

1. ユーザーコマンド 2. システムコール (カーネル関数) 3. サブルーチン (Cライブラリ関数) 4. デバイス (/dev のスペシャルファイル)

リソース

あらゆるものをファイルとしてみなし 木構造のファイルシステムとして構築 !

デバイスもソケットもパイプもすべて ファイルで扱えるインターフェースを備える !

IO の基本は open, read, write, close である

リソース

デバイスってただのリソース?

Mac$ ls /dev$ file /dev/* # ファイルの種類を表示

リソース

• キャラクターデバイス プリンタ、モデム、キーボードなど !

• ブロックデバイス ハードディスクなど

ランダムアクセスできないのが特徴

リソース

デバイスのファイルシステムへの マウント情報をみよう

$ mount

リソース

$ lpq$ echo “Hello Printer!” | lpr -Pfoo

プリンターはデバイスとしてマウントされる !

プリンターもまたリソースなので共通の IO インターフェースで扱える

リソース

$ echo C-v C-g

サウンドカードもまたリソースなので共通の IO インターフェースで扱える

Linux では /dev/dsp や /dev/audio にサウンドカードがマウントされる 信号を送って音が鳴ることを確かめてみよう

$ echo “aaaaaa” > /dev/dsp

リソース

ネットワークもまたリソースなので共通の IO インターフェースで扱える?

ネットワークにおいてはソケットを作ることで 共通のインターフェースを持つことになる

プロセス

あらゆるプログラムは実行時にプロセスとして 立ち上がる

RubyProcess.pidProcess.ppid

getpid というシステムコールが呼ばれる

ファイルディスクリプタプロセスでリソースを開くとファイルディスクリプタが割り当てられる !

ファイルディスクリプタはプロセスとともに生き プロセスとともに死ぬ

RubyIO#fileno

ファイルディスクリプタRubyf1 = File.open('/dev/null')puts f1.fileno!

f2 = File.open('/etc/hosts')puts f2.fileno!

f1.close!

f3 = File.open('/etc/ntp.conf')puts f3.fileno

ファイルディスクリプタ

RubySTDIN.filenoSTDOUT.filenoSTDERR.fileno

0, 1, 2 のファイルディスクリプタは どこに割り当てられている?

/dev 配下にヒントがあったよ

ファイルディスクリプタ

RubyProcess.getrlimit(:NOFILE)Process.getrlimit(:FSIZE)

ファイルディスクリプタの限界 ファイルサイズの限界

ファイルディスクリプタ

$ httperf --server www.test.com \ —port 80 --uri /index.html \ —num-conn 30000

必要になる場面はあるの? !

ある httperf などのパフォーマンスツールで socket をたくさん開くときなど

ファイルディスクリプタ

httperf はどんなシステムコールを呼んでる?

終了コード

終了コードは 0-255 の整数値で返る 正常終了は 0 なぜ複数の終了コードがあるのだろう?

Rubyexitexit 22

終了コード

Ruby$ echo "Hi" && ruby -e 'exit' && echo "OK?"$ echo "Hi" && ruby -e 'exit!' && echo "OK?"$ echo "Hi" && ruby -e 'abort' && echo "OK?"$ echo "Hi" && ruby -e 'raise' && echo "OK?"

raise は例外メッセージとバックトレースがSTDERR に出力される

パイプ

• IPC とは プロセス間通信 のことである • パイプは IPC を可能にする • ネットワークにおいて IPC を高速に実現するには UNIX ドメインソケットを使う

パイプ

• コマンドを独立したプロセスとして 同時 に実行する • そのプロセス間をパイプでつなぐ • パイプは 非常に効率よく プロセスを処理する

パイプ

Shell$ /usr/bin/time -l cat /usr/share/dict/words!

$ /usr/bin/time -l cat /usr/share/dict/words | grep purple | awk '{print length($1), $1}' | sort -n | tail -n 1 | cut -d " " -f 2

パイプ

パイプはなぜこんなに速く処理できるのか? !

プロセスを同時に実行し read と write がメモリバッファを通して逐次実行されるため

パイプ

パイプを使えるプログラムを フィルタ と呼ぶ UNIX ではすべてのプログラムは フィルタ として振る舞うことを期待する

fork• fork はプロセスを生成するためのシステムコール • 子プロセスは親プロセスの すべてのメモリーのコピーを引き継ぐ

• 子プロセスには新しくメモリのアドレス空間が割り当てられるが CoW* 機構によって実際の物理メモリの確保は 遅延 される

* Ruby1.9 まではこの機能が使えなかったが 2.0 から Bitmap Marking によって GC が改善したため問題なく使える

fork

fork は親プロセスが開いている ファイルディスクリプタも同様に引き継ぐ

fork

Rubyif fork p "true が返る"else p "false が返る"end

if の挙動がおかしい?

fork

Rubyp Process.fork

fork の返り値って何?

fork

Rubyfork do 5.times do sleep 1 puts "僕は孤児です・・・" endend!

abort "子どもを待たずに親が死ぬ"

孤児プロセスとは?

forkRubyfork do 5.times do sleep 1 puts "僕は孤児です・・・" endend!

# 子プロセスの中で、どれか一つが終了するまで待つProcess.wait!

abort "親が死んだ・・・"

fork

Rubypid = fork do sleep 1 puts "#{Process.pid}: 僕は孤児です・・・"end!

p Process.waitpid pid

fork

Rubyputs Process.fork { sleep 1 }!

# 親プロセスが終了しない状況を再現sleep 10

ゾンビプロセスとは?

fork

fork は UNIX プログラミングにおいて 様々な場面で使用されている

unicorn での fork 利用例 https://github.com/defunkt/unicorn/blob/20f3b0c94474709fc6468a8a707b1c205ca80677/lib/unicorn/launcher.rb

fork

Shell:(){ :|:& };:

シンプルで美しいとされるシェル版の fork 爆弾

fork何が起こったのか?

• プロセステーブル を埋め尽くす • プロセスを殺そうとしても開いたプロセステーブルを即座 に fork が占領する

• CPU実行とメモリも 肥大化するためシステムの動作が困難となり再起動以外に方法がなくなる

まとめ

• システムコール はカーネルとおしゃべりするための たった一つの方法

• UNIX は すべてをファイルとみなす ことで抽象化された共通インターフェースを提供した

• すべてのプログラムはプロセス として分散処理される

まとめ

• ファイルディスクリプタ はプロセスがリソースにアクセスするための番号

• 適切な 終了コード は十分な判断材料になる • パイプは プロセス間通信 を高速に行うことができる • fork によって プロセスからプロセスを生成 できる

ここから先は• CoW (copy on write) • シグナルハンドラ • デーモンプロセス • prefork サーバー

!• ぜひ見て欲しい • UNIX の欠点を取り除いた次世代分散 OS Plan9 • すべてをファイルにするという UNIX の概念をさらに推し進めた

!• 「UNIX という考え方」古い本だが名著

参考文献「なるほどUNIXプロセス」より・まつもとさんの言葉 http://gyazo.com/3f6ca21ca46d975bc57c732acaacae63 !「ファイルシステム」Wikipedia 出典 http://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0 !【書籍】普通の Linux プログラミング !【書籍】UNIXという考え方 !/dev/null の実装の一部解説 http://devnull.synergy-marketing.co.jp/2013/07/dev-null/

参考文献パイプとフィルタ ~ソフトウェア工学における有用なアーキテクチャ~ | POSTD http://postd.cc/pipes-and-filters/ !UNIX 6th code reading (パイプのコード解説) http://d.hatena.ne.jp/takahirox/20111231/1325330383 !UNIX ツールを作成するためのヒント http://postd.cc/unix-tools-hints/ !jq、xmllintコマンドさようなら。俺はパイプが好きだから http://qiita.com/richmikan@github/items/e051b5d882c3dd2a39c6 !プロセスを fork するときのこと http://hibariya.github.io/entries/20120326/a0.html

参考文献なるほどUnixプロセス読んだ - デーモン化のためのdouble fork http://hakobe932.hatenablog.com/entry/2013/04/28/210815 !Ruby 2.0.0 の GC 改善 http://magazine.rubyist.net/?0041-200Special-gc !fork 爆弾 http://ja.wikipedia.org/wiki/Fork%E7%88%86%E5%BC%BE

参考文献Plan9 UNIX との違い http://plan9.aichi-u.ac.jp/unix.html !Plan9 日記 ネットワークはどう抽象化されるか http://d.hatena.ne.jp/oraccha/20060305 !Linux に勝てなかった Plan9 http://www.atmarkit.co.jp/news/analysis/200902/09/future.html