たのしい工学

プログラミングを学んで、モノをつくりたいひと、効率的に仕事をしたい人のための硬派なブログになりました

【コンピュータサイエンスの独学】OS カーネル

   

カーネル

カーネルは、OSの中枢となるソフトウェアです。 システム全体のリソースを管理し、ハードウェア・ソフトウェア間のやりとりを管理します。カーネルが行っている動作は主に下記2つです。

・アプリケーションからの要求(システムコール)に応える
・ハードウェアからの応答をアプリケーションに伝える

上図のようにカーネルはアプリケーションとハードウェアの中間に位置し、アプリケーション、およびハードウェアからの要求があれば、何らかの動作を行います。 カーネルを中間の位置に置くことによるメリットは大きいです。 もしカーネルがなければアプリケーションがハードウェアを直接制御することになります。 世の中には無数のハードウェアが市場に出回っていますので、これは非常に非現実的です。 例えば、ワープロソフトで作成したドキュメントをプリンタで印刷したい場合、プリンタメーカーはたくさんありますし、機種も様々に存在しているので、ワープロソフトがそれら全てのプリンタに対応させるのは、とんでもなく大変です。 しかし、カーネルが間に入ることで、カーネルがプリンタ機種による差を吸収してくれるので、ワープロソフトは接続されているプリンタの機種を気にする必要がなくなります。 そして何より、カーネルは「システムの保護」という観点で大いに活躍してくれています。 アプリケーションにはバグはつきものです。 バグが与える影響範囲がそのアプリケーション内で収まれば良いのですが、ほかのアプリケーションにも影響を与えたり、最悪システム全体が落ちてしまうという事態も十分に考えれられます。 カーネルは、アプリケーションのバグ、あるいは悪意のある動作からシステムを守り、全体の安全性を向上に大いに貢献してくれているというわけです。

小さく保つ発想(Unix的な思想)

カーネルはOSの中枢です。
そのため、稼働中のシステムに対して、カーネルを途中で入れ替えるということは基本的にやりません。
カーネルを入れ替えるということは、それまで動いていたシステムとはまったく違うものとなるということであり、それまで動いていた環境が入れ替え後もそのまま動くとは限らないからです。

ただ、コンピュータの進化は凄まじく、ハードウェアの数や種類はものすごく多くなってますし、コンピュータの処理能力も年々上がっていきます。
そのような流れに伴い、カーネルに要求される機能は増え、それらの機能に対応していくため、カーネルのサイズはどんどん大きくなっていきます。

この事態は好ましいことではありません。
というのも、前述しましたが、カーネルは途中で入れ替えることはできないからです。

そこで、カーネルにはOSが担う各種機能のうち、必要最小限のみを実装し、残りを部品化し分離することで、全体の設計が簡素化でき、結果的に性能も向上できるという考え方が広まっていきます。

そのような考え方で設計されたカーネルを「マイクロカーネル」と呼び、WindowsやLinuxなど、現在も使われているほとんどのOSはマイクロカーネルであると言えるようになっています。

そして、カーネルから外した部分(部品)は「カーネルモジュール」という形で提供します。
そのような形を取ることで、カーネルモジュールは時代に伴い増えていきますが、カーネルは変えずにカーネルモジュールだけ動的に追加するということが可能となります。

システムコール

ソフトウェアはハードウェアを操作することで、その役割を果たします。
例えば、キーボードから入力を受け付けたり、ディスプレイにデータを出力したり、ソフトウェアはハードウェアがあってはじめて成り立つわけです。

しかしアプリケーションはハードウェアを直接操作することはできません。
ハードウェアと直接やりとりできるのはカーネルだけです。
つまり、ソフトウェアはハードウェアを操作したいとき、カーネルに処理を依頼して、間接的に操作することになります。

では、カーネルに処理を依頼するにはどうしたら良いのでしょうか。

その方法が「システムコール」です。

システムコールの「システム」はここでは「カーネル」と捉え、「カーネルをコール」すると考えるとわかりやすいです。

たとえばシステムコールには下記のような種類が用意されています。

・open
・close
・read
・write
・ioctl
・fork
・exec
・stat
・unlink  etc

上記したのは一部であり、他にもたくさんあります。
ソフトウェアはこのようなシステムコールを介して、ハードウェアを操作することになります。

デバイスドライバ

デバイスとは、比較的大きな単位を持った機器、装置のことです。
例えば、CPUやメモリ、グラフィックボードやディスプレイ、マウスやキーボード、プリンタなどのことです。
ハードウェアと同意と考えても問題ないでしょう。

カーネルはそれらデバイス全てを管理しています。

しかし、例えば「プリンタ」と言っても、市場には様々なメーカー、機種が出回っています。
メーカーや機種が異なれば、機能や操作方法も異なります。
カラー印刷できるプリンタもあれば、両面印刷できるプリンタもあります。

それはつまり、プリンタの機種が異なれば、その数だけ、カーネル側でもコードが必要となるわけです。
しかし、プリンタの機種が異なっても、同じプリンタですから、共通する機能があります。
そのような共通部分をそれぞれのプリンタごとに用意してたら無駄です。
そのため、共通化できる部分はカーネルが受け持ち、それ以外の部分は独立させ、交換可能にしておくのが都合が良いです。

その独立した部分がデバイスドライバです。

デバイスドライバの定義はカーネルに包括されます。
つまり、デバイスドライバもカーネルの一部となります。

よくなにかしらのハードウェアを購入した場合に、デバイスドライバのインストールが必要になることがあると思います。それはそのデバイス特有のものであり、従来のカーネルでは共通化できていない部分です。デバイスドライバ(≒カーネル)をインストールすることで、カーネルの機能を拡張し、そのハードウェアを抽象化することで、PC等からの入力信号、システムコールにより、そのハードウェアを扱うことができるようになります。

ライブラリ

ソフトウェアを開発する際、システムコール以外にライブラリ関数を活用することになります。
ライブラリ関数とは、ライブラリ(library)に収められている関数であり、「/lib」配下などにファイルとして格納されています。

C言語の入門書に必ず出てくる、printf関数やscanf関数などがライブラリ関数です。

メインプログラムはライブラリとリンクすることで、、その関数を呼び出すことができるようになります。

ライブラリ関数は、その内部でシステムコールを行っているのもあれば、ライブラリ関数だけで完結しているものもあります。
例えば、文字列もしくは数値を指定の書式に変換して画面(標準出力)に出力するprintf関数は、その内部でwriteというシステムコールを使っています。

逆に、strlen関数は文字列の長さを返すライブラリ関数ですが、その内部ではシステムコールを使っていません。

特定の機能を持ったプログラムを、他のプログラムから利用できるようにライブラリにまとめることで、プログラミングの効率が向上します。

API

API(Application Programming Interface)とは、アプリケーションから利用できる、OSやプログラミング言語で用意されたライブラリなどの機能の入り口(インターフェイス)のことです。

例えば、C言語のライブラリのAPIは関数やマクロであり、カーネルのAPIはシステムコールとなります。

当然、APIは自作することもできます。
自作のモジュールが他のモジュールに関数を提供するケースを考えた場合、他のモジュールに公開する関数がAPIとなります。

 - コンピュータサイエンス