ここは私の個人的なメモのページです。公開しているつもりも、隠しているつもりも
ありませんので、「たまたま通りかかった机の上にこんな紙が落ちていた」という
感覚で見ていって下さい。(書きかけです)
間違いを見付けたとか、感想や提案等あれば、
ito@mlb.co.jp までお願いします。
Linux の 特徴
はじめに。
私は、6年間程 Sun のワークステーションを使ってソフト開発の仕事をしておりました。
その後、2年程前になりますが Linux に出会いました。
最初は勝手がわからず、とまどっていましたが、最近ようやくLinuxの魅力が
わかって来た気がします。
最初の頃は、どこにでもある普通のPCで unixが使える、しかも X Winodw まで動く
という事だけが私にとっての魅力でしたが、Linuxをよく知れば知るほど、
それだけじゃない、Linux 自身にはいろいろなアイデアが程良いバランスで
実現されていて、それ自身でも十分興味に値するOSであり、またその可能性や将来は
とてつもなく大きなもであり、楽しいものだと気づいたのです。
Linux 自身もそれを取り巻く環境(ライブラリや各種のコマンド郡、そらには使う人
や、政治的な問題まで含めて)もまだまだこれから良くしていかなければならない
発展途上のものです。しかし、そういう時代に生まれて、その発展に少しでも貢献
できる機会を与えられた事に感謝するとともに、すでに実用になるレベルまでLinuxを
発展させてきた、世界中の人々の努力に感謝致します。
ここでは、Linux 固有な事を中心に、Unix を良く知っている技術者向けに
Linux の魅力を紹介したいと思います。
Linux Kernel の特徴
- 普通の特徴
- フロッピー1枚のシステムを作成できる程の小ささ。
- Intel386マシンで8Mのメモリがあれば動作する。(X Window Sytem を含めた場合16M)
- マルチプロセッサーにも対応
- 色々な種類の、ファイルシステム、バイナリフォーマット、ドライバをサポートして
おり、簡単に、これらの種類を追加していける柔軟さ。
- POSIX 1003.1 準拠でさらに、SystemV や BSD4.3のほとんどの機能を取り込んでいる
- DEC Alpha や、SUN Sparc, PowerPC, Motolora 680X0 などで上で動作。
- DEC Alpha や、Ultra Sparc では64bit化されている。
- 余っているメモリは動的にディスクキャッシュに流用してくれる
- フリー(GNU Public Licence)であり、誰にでも簡単にビルド出来る
- リアルタイムスケジューリング
Unix の全てのプロセスに対する公平な態度は、リアルタイムな処理をしようとした
時に、しばしUnix の限界を感じさせました。
Unixでは、ハードウエアの助けなくしては、短い時間間隔の制御を必要とするプログラム
を書く事はまず不可能です。
しかし、Linux は1歩進んでいます。Linux ではリアルタイムのスケージューリングを
するクラスとして、SCHED_FIFOと、SCHED_RRの2つが追加され、
従来のスケージューリングの仕方(SCHED_OTHER)と合わせて、
合計3つのスケジューリングクラスがあり、
sched_setscheduler( pid, class, param ) システムコールで特定のプロセスの
スケジューリングクラスを変更出来ます。
pid: プロセスID( 0の場合は自分自身 )
class:SCHED_FIFO、SCHED_RR、SCHED_OTHERのどれか、
param:各スケジューリングクラス内でのプライオリティ。nice 値に対応します。
リアルタイムスケジューリングクラスへの変更は、スーパーユーザでしか行えません。
リアルタイムのスケージューリングクラスのプロセスは、SCHED_OTHERより優先されます
ので、ユーザプロセスの数等に関係なく、スーパーユーザの管理の元で一部のプロセスに
対して、CPUの割り当てを保証する事が出来るようになります。
Linux のデフォルトでは、少なくとも、400ms に一回は必ずCPUを割当てる事が出来ます。
(注意:ハードウエアの割り込みを待っている場合は、割り込みがかかった時点で、すぐに
スケジューリングされなおされます。ここでいう、400msというのは、ハードウエアの割り込み
とかに、まったく依存しないリアルタイムクラスのプロセスの場合で、かつ、別のプロセスが
高いプライオリティで、まったくカーネルの助けを借りずに延々とCPUを消費している場合です。
普通ではこのような状況は考えにくいです。)
SCHED_FIFO は、指定されたプライオリティーの順番に処理されますので、
より高いプライオリティーのプロセスが、IO待ち等でスリープするまで、
低いプライオリティーのプロセスにCPUが割り当てられることはありません。
SCHED_RRは、ラウンドロビン方式のスケジューリングを行います。同じプライオリティーの
リルタイムクラスのプロセスが複数ある場合に意味を持ち、再スケジューリングの度に、
必ず次のプロセスに制御が移ります。
実験
- スケジューリング
Linux のスケジューリングはちょっと面白い事をしています。
従来のUnix では、1/10 秒毎に必ずスケジューリングをしなおしていたのですが、
Linux では、プロセスのプライオリティーに合わせて、次のスケジューリングまでの
時間が動的に変わります。
これは、nice 値に合わせて、割り当てるタイムスライスの量を変えているのです。
1タイムスライスは 1 tick に相当し、intel では 1/100 秒、Alpha では、1/1024秒
です。
従来のUnix がこの再スケジューリングの計算に費す時間はかなりの割合を占めるの
ですが、その計算結果は円滑なスケージューリングに用いられるだけで、ユーザが
やりたいと思っている仕事とは無関係であり、無駄な時間であるとも言えます。
Linux での実装は、なかなか理にかなったものといえ、好感をもちます。
しかし、従来の Unix との互換性の為に(Posix 互換の為?)、内部ではnice 値を
タイムスライスの割り当て数として扱うっているのにもかかわらず、外との
インターフェースは、-20 から 20 までの nice 値 として扱われる様に、
毎回正規化していますので、ちょっとわかりにくくなってしまっているのが
残念です。
実験
- rtc(Real Time Clock) デバイス
内蔵のCMOSクロックをユーザー空間から使うためのデバイスです。
このデバイスと、リルタイムクラスのスケジューリングを併用すれば、
たいていの制御用のプログラムは作れそうですね。
ただし、クロックの割り込みがあった時に、次のtick の時に再スケジューリング
して下さいというフラグを立てるだけなので、(kernel/sched.c の add_to_runqueue
で、need_resched=1 にする)実際には、次のカーネルのtickの割り込みの際に
再スケジューリングされるので、intel では、1/100秒以下の応答を必要とする
ものは作れません。(CPUを掴んだままの時は出来ますけど。もしくは、CMOSクロック
の割り込み間隔をもっと早くしてあげれば出来ますね。)
- clone システムコール
このシステムコールは、スレッドをサポートするために作られました。
fork は cloneを使って実装されています。clone を使えば、もっと細かく
色々な事を指定できます。
しかし、libc はスレッドをサポートしていませんし、glibc でサポートされる予定には
なっていますが、まだ作業は進行中で、利用できるようになるのはまだ先の事になります。
(スレッドをサポートするには、現在スタティックな領域を使っている物を排他制御したり、
スレッド毎に別の領域を使うように変更する必要があります。
例えば、errorno はスレッド毎に別の領域を使う必要がありますし、標準入出力のライブラリは、
バッファを利用する際に排他制御をする必要があるでしょう。)
pid_t clone(unsigned long flags, void *sp)
flagsに使える値は次の値の or です。
- シグナル
サブブロセス終了時に親に送るシグナルです。
0〜255までのsignalの値が使えます。
- CLONE_VM
バーチャルメモリ空間を共有する場合に指定します。
(kernel/fork.c の copy_mm)
- CLONE_FS
fs_struct (プロセスのルートディレクトリとカレントディレクトリ、umaskを保持)
を共有する場合に指定します。
fs_info 構造体の定義は include/linux/sched.h (kernel/fork.c の copy_fs)
- CLONE_FILES
開いているファイルディスクリプタをシェアする場合に指定します。
(kernel/fork.c の copy_files)
- CLONE_SIGHAND
シグナルハンドラをシェアする場合に指定します。
(kernel/fork.c の copy_sighand)
- CLONE_PID
親プロセスと同じプロセスIDを使用する場合に指定します。
kill pid で、RH5.1ベースのシステムでは、同じPIDのプロセスが全部死にましたが、
RH4.2ベースのシステムでは、1つしか死にませんでした。
ここの仕様の違いは、kill の仕様の違いと思われます。(まだ未確認ですが。カーネルは最初に
見付かったプロセスにのみシグナルを送っているように見えます。)
同じPIDにしてしまうと、スレッドを殺す時にsignal は使えないようです。
同じPIDにするメリットは何なんでしょうね?
sp は子共が使うスタック領域へのポインタで、0だと、親と同じ所を使います。
clone の実装に合わせて、wait3 や wait4 システムコールの options に __WCLONE が追加
されているのですが、(kernel/exit.c の sys_wait4)
if ((子プロセス->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) 無視
else 通知
となっています。
現時点では、/proc/(fs/proc/array.c) や、kill(kernel/exit.c)は同じPIDの
プロセスが複数ある事を全く考慮していません。
まだ私の力では、動きがいまいち把握出来ていません。勉強中です。
実験
- setfsuid システムコール
従来からある、uid(実ユーザID), gid(実グループID), euid(実効ユーザID), egid(実効グループID),
以外に、fsuid, fsgidが追加され、ファイルシステムをアクセスする際のIDが保持されます。
setfsuidを呼ばなければ、euid, egid が設定されています。NFSDが利用します
まだ勉強中
- Loadable Kernel Module
動的にデバイスドライバを入れたり外したり出来ます。
- デバイスの初期化を好きな時にできる
isapnp のデバイスは、デバイスに対してIRQやIOアドレスを決めてからでないと利用できないので、
BIOSが設定してくれない場合には、デバイスドライバをカーネル組み込みにしてしまうと
利用できなくなってしまいまが、モジュールにしておけば、isapnpコマンドを使って好きな
IOに割り振ってから、モジュールを入れる事が出来ます。
また、たまにしか使わないもの。例えば、SCSIにMOだけがつながっている場合に、
MOの電源を切ったまま起動して、MOを使いたくなった時に、電源を入れて、SCSIのドライバを
入れてやれば、MOが認識されます。必要がなくなった時点で、ドライバを外して、電源を切る事も
できます。(最近は、デバイス毎に再認識させれるようになったためこの必要はすでにありません)
- いらないドライバを省く事でカーネルの利用メモリが少なくなる
- オプションが渡しやすい。
irqやio以外にも色々なオプションがありますが、カーネル組み込みの場合は、カーネルの引数で
オプションを渡すしかありませんが、モジュールにしておけば、色々なオプションを、
モジュールを読み込ませる時に指定できますので、再起動の必要がありません。
- 複数のドライバを選択して利用できる
同じチップを使ったカードでも、メーカーによってデバイスドライバが違う場合があります。
こういう場合に、カーネルの再構築をしなくとも、実験的にいろいろなドライバを試す事が出来ます。
また、バージョンの違うドライバを試す際にも便利でしょう。
間違ったドライバを使ったり、モジュールのロード、アンロードを繰り返すと、
カーネルごとおかしくなる場合もありますから、そんなに便利とはいえませんが、
すくなくとも、カーネルを作り直す必要がないので、デバイスドライバの開発や
デバッグをする場合にはドライバだけ作り直せば良いので便利です。
- モジュールを自動読み込みする為の機構を流用。
デバイスドライバが必要になった時に、自動的にカーネルに組み込める様な仕掛けが用意されています。
これをするのが、kerneld というデーモンなのですが、モジュールを組み込む前後で、別の事をさせる
事も出来ます。この機構を使って、自動的にインターネットにダイアルアップさせたりする事も可能です。
時間ができたら、使い方も書くつもりです。
- ioperm, iopl
こんなのunix じゃないって言われそうなシステムコールで、ユーザプロセスが直接IOを叩くための
ものです。Xサーバ等が利用しています。
(早く、デバイスドライバと、アプリケーションに分離して欲しいですね。)
ハードを直接制御したい場合に、デバイスドライバを書かなくとも、IOにアクセス出来ます。
ユーザ空間ですから、他の割り込みを止めるような事は出来ませんが、テスト的にプログラミング
する上ではとても便利です。
- signal
Linux はBSDよりもSysVに似てはいますが、どちらでもないが正解です。
signal の扱いなどが、BSDとSysVでは違いますから、プログラミングの上では気を付けなければ
いけないのですが、Linux では、signal に関しては、インクルードするヘッダを変える事で
どちらの振舞もさせる事が出来ます。
- loop デバイス
ファイルをデバイスに見せかけてしまうデバイスで、とっても便利です。
IOの際にオフセットを付ける事と、暗号化させる機能も持っています。
losetup というコマンドを使って、loopデバイスと、ファイルの対応を付ける事が出来ます。
CD を焼く前に、内容を確認したい場合などに、実際にCDに焼くイメージのファイルをマウントしたり、
ディスクの中身をddで取りだしたファイルを実際にマウントして、中身だけを取り出したり、書き換えたり
も出来ます。
デバイスファイル自身をloopにつなげる事も出来ますから、暗号化されたディスクも作れます。
- md デバイス
複数のデバイスを1つのデバイスに見せかける為のデバイスです。(ソフトウエア raid )
IDE, SCSIの混在も出来ます。
- sg デバイス
- その他のデバイス
ISDN, WDT
- proc ファイルシステム
- ext2 ファイルシステム
lsattr, chattr
- ディレクトリキャッシュ
Linux には、inode キャッシュや、バッファーキャッシュ以外にも、
ディレクトリのキャッシュというちょっと珍しい物があります。
ディレクトリからファイルを探すには、一つずつエントリを比較するので、
よく使われるファイルをキャッシッングする事で、高速化をはかります。
ext2、isofs、vfatのみが利用しています。
また、15文字以下のファイル名にしか効きませんので、
名前を考える時には注意しておくと良いでしょう。(fs/dcache.c)
- boot
LILO、LOADLIN、initrd
- Vertual Console
な、なんとX まで。
shift+PageUp
- IP-Masquarade,Bridging,VertualHost,IPv6,tunneling
- setserial, setfdprm,hdparm,tunelp
- pam
- swap スペース
- カーネルのビルド
- カーネルのソース
Linux Operating System の特徴
- 多彩なアプリケーション
init すら、自分の好きなのを選べる。
- GNU Tools
cpio、dump あやうし。
cp -a や、tar で デバイスファイルがとれちゃうは、
tar zcf remotohost:/dev/nst0 で、圧縮も、
別のホストのバックアップデバイスにも直接書けちゃう、
便利ならいいという、なんでもありの世界。
cp, dd, tar, ls,
- セキュリティーよりも便利さ優先にかなり寄ってます
- rpm