簡単なコマンドですら何度も使用する「システムコール」とは「カーネルに仕事を依頼する方法」を指す。OSではプログラムを安全に実行するために、プロセッサの提供する機能を使用して「特権モードで動作するカーネル」と、「非特権モードで動作するそれ以外のプログラム」というように「カーネル」と「それ以外のプログラム」をそれぞれ実行する世界を分けている。
カーネルはハードウェアの提供する機能をすべて利用できるが、それ以外のプログラムは、ハードウェアの機能の中でも利用できないものがある。この「非特権モードで動作しているプログラム」が「特権モードで動作しているカーネル」に「仕事を依頼する」方法が「システムコール」だ。
起動直後の状態でも、OSでは複数のプログラムが動作している。これらのプログラムを安全に動作させるには、プログラムがほかのプログラムに影響を与えることができないようにする必要がある。あるプログラムが勝手におかしな動きをして、それがほかのプログラムに影響を与えるようでは困る。
こうしたことが起こらないよう、ほかのプログラムに影響を与える処理はカーネルのみが実行できるようにし、そのほかのプログラムからは操作できないようにする。非特権モードで動作するプログラムに可能な処理は、本来そのハードウェアで実行できる処理よりも制限されている。こうした制限を設けることで、あるプログラムが勝手にほかのプログラムに影響を与えないようにしている。
では、その「非特権モードで動作するプログラム」が「制限されている機能」を使わなければならなくなったときにどうするか。唯一それを実行できる「カーネル」に処理を「依頼」するわけだ。カーネルは依頼された処理を、処理しても問題ないものであるかなどの判断を下し、必要があれば処理を実施する。これが「システムコール」と呼ばれるものの動きだ。OSが提供するシステムコールはさまざまだ。例えばFreeBSDならおよそ530種類のシステムコールがある。
OSそのものの開発や、組み込み機器向けソフトウェアの開発など、システムコールを頻繁に呼び出す場面はある。しかし、一般的なソフトウェアのの開発現場でシステムコールを直接利用するようなプログラムを作ることはほとんどない。まったくないと言ってもいい現場も多い。その理由としては、システムコールそのものが扱いにくいことが多いというここと、基本的にはシステムコールを呼ばない方がプログラムの処理性能を高められるからだ。
少々乱暴な言い方になるが、システムコールはなるべく呼ばない方が、プログラムの性能を高められることが多い。必ずしもそうではないこともあり、ケースバイケースなのだが、基本的には呼ばない方が良い。システムコールを使うということは、カーネルに処理を依頼した後に、一度そのソフトウェアの動作を止め、カーネルが準備をし、処理をして、結果をソフトウェアに戻すことになる。このようにカーネルに処理を移すためにいくつもの手順が必要になり、その分処理が遅くなるのだ。
ライブラリはシステムコールを呼ぶことで性能が劣化しないように、システムコールを呼び出す回数が少なくなるように、データをキャッシュしたり、処理手順を入れ替えるなどの工夫をしてある。こういった工夫を、自分のプログラムですべて記述するのは骨が折れる。そこで、ほとんどの場合は、ライブラリをそのまま使うことになる。また標準化されたライブラリを使うと、ソフトウェアの移植性が高まるという効果も期待できる。このように、ライブラリを利用せずに自前でシステムコールを使うことには、あまり利点がないのだ。
それにライブラリは、よく使う処理を簡単に記述できるように工夫してあることが多い。仮にそのライブラリが使いにくいものだとしても、さらに上位のライブラリやミドルウェアを探すと、その用途で便利に使えるように工夫してあるものが見つかる。わざわざシステムコールを直接使う必要はないわけだ。
ここからが今回の本題であり、この連載の目的、本質になる。なぜ「システムコールを使う方法」を追っていくのか、学ぶのかということだ。それはシステムコールを使うことで利益を得られる場面があるからだ。
まず、処理性能の面で利益が得られるシステムコールがある。システムコールの実装の中には、コンソールのコマンドと比較して機能がまったく変わらないものもあるが、反対に、Cのソースコードで使わなければ意味がないものもある。
ソースコードで使わなければ意味がないとされるシステムコールの中には、同じような機能を提供するほかのシステムコールと比較して、けた違いに高い性能を発揮したり、スケールしたりするものがある。見方を変えると、カーネルが提供する最新機能を使うには、システムコールを直接実行しなければならない。そのためにシステムコールを学ぶのは価値がある。
そして、既存のソフトウェアの特定の処理を高速化する必要に迫られ、その分析や解析、そして代替ソフトウェアの開発のためにシステムコールの知識が必要になることもある。性能上のボトルネックになっている部分を発見し、その部分をどのような処理に置き換えれば高速化が期待できるのかと突き詰めていけば、システムコールのレベルになってくる。ここでシステムコールに対する知識があるのとないのとでは、できることがまったく違ってくる。ボトルネックを発見して別のソフトウェアや処理に置き換えるというのはよくあることだ。やはり、システムコールは知っておくに越したことはない。
そしてこれは何をするにしてもとても大切なことだが、システムコールを調べることは単純に「面白い」。普段は意識することがないシステムコールや、カーネルの中身を知ることは、知的にエキサイティングな体験だ。今まで「ブラックボックス」だった部分の仕組みが明らかになると、頭の中にソフトウェアの動きをもっと物理的にはっきりと、イメージできるようになる。今まで分からなかったこと、知らなかったことが明らかになるというのは、それだけで止められない中毒性がある。
カーネルレベルでの動きが想像できるようになると、プログラミングであったり、さらにはコマンドを実行したりシェルスクリプトを組んだり、管理や運用といったレベルにおいても「効率の良い方法」を選択しやすくなる。「実際カーネルではこのように動くだろうから、Aという処理方法よりも、Bという処理方法の方が良い」「20論理コアで動かすなら、こちらの処理の方がスケールする」といった設計や実装の段階でのスキルが向上する。上層のAPIやライブラリだけを意識して使っているだけでは得られないスキルを身に付けることができる。
次回はシステムコールを試していくための環境のセットアップ方法を紹介する。主要なOSであれば、どれも似たようなことができるので何でも良いのだが、連載していく上で共通のプラットフォームがあった方が話を進めやすい。仮想化アプリケーションを活用して環境を用意してしまおう。
ファイルの編集にはどのエディタを使っても良いが、現在、Vimの連載が進行中だ。Vimを使うことを前提にして作業をしていきたい。Vimを使ったことがないのであれば、良い機会なのでこれをきっかけに使ってみてはいかがだろうか。Vim連載でプログラミングに向くプラグインのセットアップや操作方法なども紹介していく予定だ。
BSDコンサルティング株式会社取締役/オングス代表取締役
後藤 大地
@ITへの寄稿、MYCOMジャーナルにおけるニュース執筆のほか、アプリケーション開発やシステム構築、『改訂第二版 FreeBSDビギナーズバイブル』『D言語パーフェクトガイド』『UNIX本格マスター 基礎編〜Linux&FreeBSDを使いこなすための第一歩〜』など著書多数。
Copyright © ITmedia, Inc. All Rights Reserved.