あらためて学ぶOSの役割 - 「OSの気持ち」を知り、コンピュータをよりよく理解しよう

パソコンを操作するうえで、欠かすことができないOS(オペレーティングシステム)ですが、あまりにも「あたりまえ」の存在ゆえ、その実像をイメージすることは多くはないでしょう。OSは「なにを」「どのように」処理しているのかを学ぶと、自身が使用するパソコンがもっとよく理解できるようなるかもしれません。内田公太さんが、OSの役割と働きの基本、そして「OSの気持ち」を理解するための方法を解説してくれました。

あらためて学ぶOSの役割 - 「OSの気持ち」を知り、コンピュータをよりよく理解しよう

こんにちは、内田公太(@uchan_nos)です。

普段皆さんはパソコンを使っていろいろな処理をしていると思います。ネットサーフィンに文書作成、音楽を聴いたり絵を描いたり。この記事をお読みの方はプログラミングもしている方が多いと思います。

C言語の入門書で学ぶ最初のプログラムはだいたい printf("Hello, world!\n"); というものです。たったこれだけで画面にHello, world!というメッセージが表示されます。オンボードのグラフィックだろうが高級なグラフィックボードだろうが、NVMe SSDだろうがSATA HDDだろうが、どんな構成のパソコンで実行しても同じようにメッセージが表示されます。あるいは画面を持たない組み込みシステムであっても、多くの場合このプログラムは問題なく動きます。よくあるのはシリアル通信(RS-232やUSBなど)で送信される仕組みです。

Hello, world!出力までのフロー

これはOS(オペレーティングシステム)がハードウェアの違いを吸収し、単純に扱えるシステムコールをアプリケーションに提供してくれているからです1。もし、各アプリケーションが自分でグラフィックボードやディスプレイを制御しなければならないとしたら大変ですね。

この記事ではパソコンの縁の下の力持ちであるOSの全体像を明らかにします。「OSの気持ちが分かる」を目指して書きましたので、読んでいただけたら幸いです。

身近なOS

OSはとても身近にあります。皆さんが使っているパソコンには必ずといって良いほどOSがインストールされています。今ならWindowsやmacOSがパソコン用OSとしては有名でしょう。OSのおかげで私たちはいろいろなアプリケーションを同時に、ときには連携させて使えます。

スマートフォンにもOSが組み込まれています。iOSやAndroidが有名で、ときどきWindowsが搭載されたスマートフォンを見かけます。パソコン用OSとスマートフォン用OSは中身や見た目が多少違うものの、OSの基本的な概念は共通しています。ユーザーに統一されたインターフェースを提供する、周辺機器をアプリケーションの代わりに制御する、複数のアプリケーションを動かす、といった概念です。例えば、OSが「テキスト入力」や「ホームに戻る」などの機能を提供しているおかげで、アプリケーション開発者はそれらを新たに実装する必要はなく、しかもユーザーは統一された(ちぐはぐではない)操作体験を得られます。

OSの役割

家電や自動車、家庭用ゲーム機、ロボットなどにもOSが入っています。 システム全体を管轄するOSとしてLinuxなどの汎用OSを使いつつ、末端の部品ではITRONなどの組み込みに特化したOSが使われたりします。OSが提供するマルチタスク機能のおかげで、ゲームキャラクターの移動処理をしつつ、裏で次のマップのデータをロードするといったことが実現できます。既存のOSを使わずにそれらを実現するようプログラミングすることも可能ですが、見方を変えると、それは簡易なOSを自分で作っているとも言えるでしょう。

AWSやGCP、Azureなどのクラウド環境にアプリケーションを配置してサービスを提供することが一般的になっていますが、そんなクラウド環境もOSの力をフル活用して構築されています。 例えば、CPUの個数やメモリ量を指定してVMを生成できる機能を考えてみます。クラウド環境の利用者は、それがどうやって実現されているのか気にせずに使えますが、しかし実際には物理マシンにOS2がインストールされ、その上で複数のVMが作成されます。物理マシンに搭載されたCPU、メモリ、ディスク、ネットワークなどのリソースを、OSが各VMに公平に分配することで、物理的な1台のマシンで複数のVMを提供できます。こうすることで、複数のユーザーが1台の物理マシンを共有でき、低価格な計算環境が構築されるのです。

クラウド環境において使われるミドルウェア(Kubernetesなど)は、普通はOSとは呼びません。あくまでもOSは1台の物理マシン、あるいはVMにインストールされるものである、というのが普通の認識だと思います。しかし、複数のマシン間でリソースを管理し、リソースが空いてるマシンにアプリケーションを割り当てて実行するという機能を考えると、ミドルウェアも「クラウド環境におけるOS」と表現していいと思います。普通のOSは、1台のマシン内にあるCPUやメモリ、ストレージ、ネットワークなどのリソースを管理し、複数のアプリケーションがそれらを使えるように分配します。それと同じように、Kubernetesなどのミドルウェアは複数のマシンにあるそれらのリソースをアプリケーションに分配するのです。

OSが持つ3つの顔

筆者なりにOSを分析すると、大きく分けて以下の3つの顔を持つと言えるでしょう。

  1. 人間に対するインターフェースとしての顔
  2. アプリケーションに対するインターフェースとしての顔
  3. リソース分配者としての顔

まず、「人間に対するインターフェースとしての顔」とは、人間がパソコンを使うときの操作に関係するものです。WindowsやmacOSはGUI(Graphical User Interface)が基本となっていて、ウィンドウがぽこぽこ表示され、メインメニューがあり、右クリックでショートカットメニューが表示されます。基本的な操作はどのアプリケーションでもほとんど統一されており、例えばWindowsであればCtrl+Cでコピー、Ctrl+Vで貼り付けが可能です。

あるアプリでコピーした情報を他のアプリに貼り付ける、などとアプリをまたがる操作ができるのもOSがクリップボードと呼ばれる機能を提供するからです。ワープロソフトで文章をコピーしチャットソフトの入力欄に貼り付ける、という操作ができるのはクリップボードのおかげです。あるいは、アプリはファイルによっても連携させることができます。Webブラウザでページを保存すれば、それをテキストエディタで閲覧、編集できますが、こうしたファイルシステムはOSが提供する典型的な機能の1つです。

OSの仕事概念図

OSが提供する重要な機能として、コンピュータに接続された周辺機器の管理があります。Windowsならデバイスマネージャ、macOSならTODOといったユーティリティによって周辺機器の状態を確認したり、設定を変えたりできます。現代的な周辺機器はコンピュータに接続すると自動的に認識され、使用可能になるものが多いのでOSの存在をあまり感じませんが、実は裏ではOSが自動認識の処理をこなしています。OSは周辺機器が接続されると、その機器の種別を自動的に判定し、対応するドライバをインストールし、周辺機器を初期化します。

二つ目の「アプリケーションに対するインターフェースとしての顔」とは、アプリが動作するとき、あるいは開発者がアプリを作るときのOSの見え方です。アプリはOSの力を借りてさまざまな処理を行います。C言語プログラムprintf("Hello, world!\n");を実行すると画面に"Hello, world!"と表示されます。しかし、アプリが自ら画面に描画するわけではなく、OSに対して「Hello, world!という文字列を標準出力へ印字せよ」と依頼し、OSがその依頼通りに表示する、という役割分担になっています。

標準出力というのは文字列(バイト列)を出力するためのチャンネルで、OSがアプリのために準備してくれます3。アプリはバイト列、すなわちASCIIコードの列を文字の形に変換する方法、あるいは文字の形を画面に描画する方法を知らずとも、それらはすべてOSが面倒をみます。標準出力は画面への出力だけではありません。OSが提供するリダイレクトやパイプの機能を使うと、標準出力のバイト列をファイルや他のアプリの標準入力へと接続できます。出力元のアプリは、標準出力が画面(ターミナル)に接続されているのか、ファイルに接続されているのか、他のアプリに接続されているのかを気にせず、同じ方法でバイト列を出力するだけで良いのです。

文字出力までの流れ

標準出力に対する文字列表示に注目して説明しましたが、その他にもOSはアプリ作りを便利にする機能をたくさん提供します。基本的なところではキーボードやマウス、ネットワーク通信、時計など、周辺機器を手軽に扱う仕組みを提供します。また、一定時間待ったりイベントが発生するまで待ったりするのも通常はOSの機能を使います。マルチスレッドの仕組みそのものや、そこで使うミューテックスなどの同期処理の根幹となる機能もOSが提供します。このように、OSはアプリを作りやすくする機能をたくさん提供しているのです4

三つ目の「リソース分配者としての顔」とは、複数のアプリが平等に(あるいはユーザーが設定した優先度に応じて)計算リソースを使えるようにすることです。計算リソースの典型例はCPUです。1つのCPUコアは同時に1つのスレッドを動かすことしかできません。動作したいスレッドの数がCPUコア数を上回る場合、スレッドを切り替えつつ実行することで全てのスレッドにCPUという計算リソースを分配します。スレッドの切り替えには2種類の典型的な方法があります。そのうちの1つであるプリエンプティブマルチタスクを採用するOSは、一定間隔でスレッドを切り替えて実行します。この方法では、スレッドがCPUを使い続けて他のスレッドが実行不能になったり、システム全体がフリーズしてしまうことなく、各スレッドにCPUを割り振ることが可能です。

あるいはIOも重要なリソースです。ストレージの読み書きの性能には限界があるため、複数のアプリが大量にファイルを読み書きするようなケースでIOの分配が必要です。1つのアプリの処理が一区切りするまで待つ方法では、そのアプリの実行が終了するまで他のアプリが止まってしまいます。アプリを平等に動作させるには、各アプリのIO量を適切に制御し、限りあるIO性能を分配しなければなりません。これもOSの仕事の1つです。

ここまでOSの3つの顔を紹介してきました。ざっくり言えば、OSはコンピュータを使いやすくするための基盤を提供するものと捉えられるでしょう。コンピュータの操作性を向上させ、アプリ開発をやりやすくし、マルチタスクをサポートするのです。これらOSの働きによって、より多くの人がコンピュータを使えるようになり、アプリがどんどん開発されるようになり、こなせる仕事の種類が増えることに繋がります。OSはコンピュータシステム発展の立役者だと言えるでしょう。

OSのない世界

多くの読者の皆さんはパソコンにOSが入っていない世界を想像できないかもしれません。身近にそんなパソコンはありませんからね。ですが、実は簡単に手に入るものでOSがない世界を体験できるものがあります。マイコンボードです。

マイコンボードのイメージ画像

マイコンボードとは、小さな(マイクロ)コンピュータが搭載された基板のことです。上の写真はArduino Dueというマイコンボードです。電子工作などに用いられ、LEDを点滅させたり(Lチカ)、モーターを回転させたり、センサーを読み取ったりするのに使います。最近よく耳にする製品としては、ArduinoやM5Stackなどがあります。これらにはOSが搭載されておらず、「OSなき世界」を想像するのにちょうどよい題材です。同様の文脈でRaspberry Piという製品も聞いたことがあるかもしれません。こちらはLinuxをベースとしたOSをインストールして使うのが標準的な使い方で、どちらかというと普通のパソコンに近い製品です。

さて、OSが搭載されていないArduinoやM5Stackなどのマイコンボードにおけるアプリ開発を考えます。このどちらも製品もArduino IDEというソフト(開発環境)でアプリ開発を行えます。Arduino IDEを起動すると最初からソースコードを記述する画面が大きく表示され、メインメニューからプログラムをコンパイルしたり、マイコンボードへ書き込む操作などが選べるようになっています。

開発環境を起動すると最初からソースコードを書けるようになっている、という事実は、ArduinoやM5Stack上に同時に存在するアプリは1つである、ということの裏返しになっています。マイコンボードの電源を入れると、書き込まれている唯一のアプリが動作します。別のアプリを書き込むと前のアプリは消失します。複数のアプリが同時並行に実行される世界観とは大きく異なります。同時に1つのアプリ(タスク)だけを実行できるOSもありますので、アプリが1つだということがOSがない絶対の証拠にはなりませんが。

OSがない環境でのアプリ開発のもう1つの特徴としては、各種ハードウェアの制御をすべてアプリ自身がやらなければならない、というのもあります。ArduinoやM5Stackには、スイッチや各種センサー、液晶ディスプレイなど、さまざまな周辺機器を接続できますが、これらのハードウェアを制御するにはドライバ(専用のプログラム)が必要であり、用意するのはアプリ開発者の責任です。有名なハードウェアであればドライバがライブラリとして配布、あるいは初めからArduino IDEのような開発環境に含まれていて、自分で開発する必要はないこともありますが、その場合もアプリの一部として組み込む必要はあります。OSに組み込まれたドライバを通してハードウェアを利用するモデルとは大きく異なります。

OSがある世界、OSがない世界のイメージ図

OSがない環境では、人間、あるいはコンピュータの外側とやり取りするのもアプリの責任となります。スイッチや各種センサー、液晶ディスプレイなどを通して外界とやり取りするのはアプリそのものです。アプリ自身がセンサーの信号変化を監視し、変化に応じた処理をする必要があり、センサーや基板の仕様に従って適切に制御しなければなりません。液晶ディスプレイに文字や絵を表示する仕方も、液晶ディスプレイの種類によって異なるため、接続された液晶ディスプレイの仕様をアプリが把握しておく必要があります。一方、OSがある世界では、それらのハードウェアと直接やり取りするのはOSに組み込まれたドライバであり、アプリ自身ではありません。アプリはハードウェアの細かい違いを意識する必要はなく、OSが用意している抽象化されたインターフェースを介してハードウェアを利用できます。

OSの気持ちを理解する

OSはソフトウェアですので「気持ち」というのも変ですが、OSの視点からその役割や仕組みを観察することでコンピュータをより良く理解できるはずだ、という筆者の思いから「OSの気持ち」と書いてみました。事務仕事や開発作業はOSの恩恵を多分に受けているにも関わらず、OSが何をやっているのかはなかなか見えてきません。逆に言えばOSの仕組みが全然分からなくてもコンピュータを使って仕事ができてしまいます。それでもOSの気持ちを理解しようとする人々がいるのはなぜでしょうか。

OSの気持ちを理解しようとする動機はさまざまと思いますが、筆者が思いつくのは次のようなことです。

  • OSを改造する
  • OSの機能を活用したソフトウェアを作る
  • OSの機能に関連するバグを解決する
  • システムのボトルネックを調査する
  • 知的好奇心を満たす

OSを改造するというと信じられないかもしれませんが、実際にそういう世界があります。例えば、サーバ用のOSとして普及しているLinuxはソースコードが公開されており、自分で改造ができます。バグがあれば直したり、欲しい機能を追加したりということが実際に行われています。このように、改造したOSを期待通りに動かすにはOSの気持ちが分かっている必要があります。少なくとも、改造しようとする部分とその周辺の仕組みを知らなければならないでしょう。

OSの機能を活用するというのは、アプリ開発であればシステムコールを活用すること、カーネルモジュール開発であればカーネル内関数を活用すること、というような意味です。read()write()などの非常に基本的なシステムコールでさえ、アプリによってはブロッキング動作の有無やバッファの大きさ、呼び出しのアトミック性などが問題になり得ます。あるいは、ファイルにデータを書いたとしても、単にキャッシュされているだけでディスクに書かれていないかもしれません。データをディスクに永続化することが大切なアプリでは、適切にフラッシュ操作を実行する必要があるでしょう。ドライバ開発等の、よりOSの中心部に入り込むソフトウェアを作る場合、OSの気持ちを理解する重要性はもっと大きくなります。

知的好奇心を満たす、というのも立派な動機だと筆者は思います。ロマンってやつです。OSの気持ちが分からなくても普段の仕事には影響がほとんどないかもしれません。ですが、OSという複雑怪奇なソフトウェアの気持ちが理解できたら、なんだか楽しそうじゃないでしょうか?筆者は中学生の頃からそのロマンを追い求め続けてきました。

OSの気持ちを理解するにはどのような方法があるでしょうか。いろいろ考えられると思いますが、ここでは代表的と思われる4つの方法を紹介します。

OSの機能を実験的に確かめる

OSを用いて様々な実験を行うことで挙動を理解しようという作戦です。スレッドの時分割処理が実際にどうなっているのかを知りたければ、複数のスレッドを生成し、それぞれのスレッドがどのくらいの時間ずつ実行され、切り替わるのかを観察する、という実験が考えられます。この手法の良いところは、実際に動作するOSのリアルな挙動を観察できることです。机上の空論ではない、現実の感触です。手を動かして実験するので、言葉で理論を説明されても実感がわかない……という方でもチャレンジしやすいのではないかと思います。

この方針でLinuxを理解しようとする書籍に『試して理解 Linuxのしくみ』(武内覚、2018)があります。各種の実験を通してLinuxの気持ちを理解していくことができます。エンジニアHubにもこの著者の記事があります。いま知っておきたいLinux─WebアプリがOSのプロセスとしてどのように見えるか? を運用に生かす

OSのソースコードを読む

ソースコードには設計が埋め込まれています。OSのソースコードを読めば、分かりやすいかどうかはさておき、全体像から細部に至るまでOSの設計を学べます。この目的に使えるOSは、OSSとして公開されているOSであるLinuxやFreeBSDなどです。この手法の良いところは、OSの設計を知ることで、どんな場合にどんな挙動をするか、ということが網羅的に分かることです。実験によって調べる方法は入力するデータやマシン構成などによって挙動が変わるため、この環境で実験してこの結果を得た、という狭い範囲の情報しか得られません。設計が分かれば、どんな状況でどうなるかが広く類推できるのです。

この方針でOSを理解しようとする書籍に『はじめてのOSコードリーディング』(青柳隆宏、2013)や『詳解 Linuxカーネル 第3版』(Daniel P. Bovet, Marco Cesati, 2007)があります。前者の書籍はUNIX V6のソースコードを解説したものですが、UNIX V6はかなりシンプルな作りのOSでして、学習の題材として良いと思います。ただ、PDP-11というマシン向けのOSですので、x86やArmに慣れている人でもちょっと理解が大変です。

OSの理論を学ぶ

現実のOSを動作させてみたりソースコードを読む以外に、OSの各機能を理論的に解説した教科書を読むのも有力な手段でしょう。大学の教科書としていろいろなOS関連の本が出ています。絶版になってしまいましたが、『オペレーティングシステム 設計と実装 第3版』は有名な書籍です。MINIXという教育用のOSを題材にしているので、各解説が具体的で説得力のあるものになっています。

また、大学の授業としてはMITのオペレーティングシステムエンジニアリングが有名です。この授業はxv6という小さな教育用OSを活用し、理論と実践の両面からOSを学べるようになっています。xv6は規模が小さいので、全体像を理解したり改造したりするのが比較的容易になっています。英語ですが授業資料や宿題が公開されており、MITに入学しなくても学習リソースが手に入りやすいです。

OSを作ってみる

OSの気持ちを理解するには、OSを作ってみればいいじゃない、ということです。OSを実際に作ってみると、非常に高い解像度でもってOSの仕組みを学べます。理論だけ知っているのと実装が頭に思い浮かぶのとでは大きな差があります。スレッドを切り替えるときにOSが何をやっているのか、ページングが仮想アドレスを物理アドレスに変換するというのは具体的には何がどうなることなのか、などが、実体験として理解できるでしょう。自分で実際に動くものを作ってみると、理論では扱わない末端の部分まで作り込む必要が出てくるので、細部にわたり経験値が貯まります。雰囲気だけでない理解を得たい場合にお勧めの手法です。

既存のOSに改造を施すことによっても部分的に「作ってみる」ことは達成でき、相応の理解が得られるでしょう。ただ、OSの全体像をまんべんなく詳しく知りたい場合には、OSの起動部分から全て作ってみるのが効果的だと筆者は考えています。

この目的の書籍に『12ステップで作る組込みOS自作入門』(坂井弘亮、2019)や『ゼロからのOS自作入門』(内田公太、2021)があります。前者の書籍はH8マイコンという、OSを搭載せずに使うことも多いマイコン向けのOSを作るのがテーマです。H8マイコンはパソコン用CPUと比べると大変シンプルな構造ですので、OSもシンプルになり、理解しやすいかと思います。後者の書籍は、この記事の筆者uchanが書いたもので、現代のx86パソコンで起動できるOSを作る方法を説明しています。OSを起動させるための「ブートローダ」というソフトウェアから全て自分で作る過程を経験できるため、OSが全体としてどんなことをやっているのかを、ソースコードレベルで知ることができます。

uchan-nos 7 @uchan_nos, 8 uchan-nos

9
小学生の頃にPICマイコンのアセンブリ言語に出会い、プログラマの道に進む。中学2年のときにC言語と出会い、プログラムを幾つか製作。その頃フリーソフトというものにはまってvectorを彷徨っていたところ、国産OSの「OSASK」を発見してしまう。そのつながりで高校時代は『30日でできる!OS自作入門』(川合秀実、2006年)の校正を手伝うことになる。

東京工業大学の計算工学専攻を卒業、サイボウズのインフラ系ソフトウェア開発部署を経て、現在はサイボウズ・ラボでOSや言語処理系をメインとした研究開発に従事。好きな言語はC++とPython。近著に『ゼロからのOS自作入門』(マイナビ出版)がある。

編集:はてな編集部


  1. 厳密な話をすると、printf が動く環境がOSとは呼べないような単なるライブラリによって提供されていることもあります。特に小さな組み込みマイコンではその傾向があります。

  2. この用途で使う「OS」はハイパーバイザと呼ばれます。OSとハイパーバイザに利用される技術の多くは共通していますので、OSの一種として説明してみました。

  3. 詳しい方は、それはシェルの仕事でありOS(カーネル)の仕事ではない!と思うかもしれません。筆者はOSのことをシェルやユーザー空間のツール類を含む広い概念として捉えており、その前提で記事を書いています。

  4. アプリ作りを便利にする機能というよりは、OSによって導入されてしまった制限を緩和するための機能も多くあります。OSがなければコンピュータ中の機能を自由に使えるのに、というようなケースです。

若手ハイキャリアのスカウト転職