現在のOSでは、複数のアプリを同時に動かしたり、ネットワーク越しに通信したり、複数CPUを使って高速に処理したりすることは当たり前になっています。
しかし、1980年代のUNIXは、もともとシンプルで扱いやすいOSとして設計された一方で、時代の変化によって多くの機能が後付けされ、内部構造が複雑になっていました。
今回紹介する論文 “Mach: A New Kernel Foundation For UNIX Development” は、Carnegie Mellon University、通称CMUで開発されたOSカーネル Mach について説明した論文です。
Machの目的は、単にUNIXに便利機能を追加することではありません。
むしろ、UNIXを将来のコンピュータ環境に対応させるために、OSの土台そのものを作り直すことでした。
- この記事でわかること
- Machとは何か
- なぜMachが必要だったのか
- Machの基本思想
- Machが提供する4つの基本概念
- 1. タスク
- 2. スレッド
- 3. ポート
- 4. メッセージ
- UNIXのプロセスの問題点
- Machの並列処理モデル
- 1. 1つのタスク内に複数スレッドを作る
- 2. 複数のタスクでメモリの一部を共有する
- 3. 複数のタスクがメッセージで通信する
- copy-on-writeとは何か
- メモリの継承方法
- 1. shared
- 2. copy
- 3. none
- ユーザー空間のページャ
- Machの仮想メモリ実装
- Machのプロセス間通信 IPC
- ポートは「安全な窓口」
- メッセージには大きなデータも送れる
- 大きなメッセージ転送の仕組み
- Matchmakerによるインターフェース定義
- ネットワーク越しの通信
- セキュリティ
- Machのシステム支援機能
- カーネルデバッガ
- 透明なリモートファイルシステム
- MachはUNIXをどう作り変えようとしたのか
- Mach-1の当時の実装状況
- 性能面での評価
- Machの何がすごかったのか
- 1. カーネルを小さくしようとした
- 2. 通信を中心にOSを設計した
- 3. マルチプロセッサを前提にした
- 4. 仮想メモリとIPCを統合した
- 5. 分散環境を意識していた
- 誰にでもわかるMachのイメージ
- 従来のUNIX
- Mach
- Machの限界や注意点
- まとめ
- 参考文献
この記事でわかること
この記事では、Machについて以下の内容をわかりやすく解説します。
- Machが作られた背景
- 従来のUNIXが抱えていた問題
- Machの基本設計
- タスク、スレッド、ポート、メッセージとは何か
- Machの仮想メモリ管理
- プロセス間通信、IPCの仕組み
- ネットワーク越しの通信とセキュリティ
- MachがUNIXをどう作り変えようとしたのか
- 当時の実装状況と意義
Machとは何か
Machは、CMUで開発されていた マルチプロセッサ対応のOSカーネル です。
論文では、Machは以下のような特徴を持つOSカーネルとして紹介されています。
- 4.3BSD UNIXとのバイナリ互換性
- 複数CPU、マルチプロセッサへの対応
- タスクとスレッドによる新しい実行モデル
- 高度な仮想メモリ管理
- ポートとメッセージによるプロセス間通信
- ネットワーク越しの透明な通信
- ユーザー空間でOS機能を拡張できる設計
簡単に言うと、Machは 古くなりつつあったUNIXの中核部分を、より柔軟で拡張しやすい構造に置き換えようとしたカーネル です。
なぜMachが必要だったのか
UNIXはシンプルだったが、複雑になりすぎた
初期のUNIXは、非常にシンプルな設計思想を持っていました。
UNIXでは、ファイル、パイプ、デバイスなどを「ファイルディスクリプタ」という形で扱い、read、write、seek のような少数の操作で処理できました。
これは非常に美しい設計でした。
しかし、時代が進むにつれて、UNIXには多くの機能が追加されていきます。
たとえば、論文では以下のような機能が挙げられています。
- パイプ
- System V streams
- BSD sockets
- pty
- セマフォ
- 共有メモリ
- 多数の ioctl 操作
これらは便利ではありますが、結果としてUNIXの内部はどんどん複雑になりました。
つまり、もともとは「少数の統一的な仕組み」で作られていたUNIXが、さまざまな用途に対応するために、バラバラの仕組みを大量に抱えるようになってしまったのです。
Machの基本思想
Machの考え方はかなり明確です。
それは、OSの機能をすべてカーネル内に詰め込むのではなく、小さな基本機能をカーネルが提供し、その上にさまざまなサービスを構築する という考え方です。
論文では、Machはオブジェクト指向的な考え方を取り入れていると説明されています。
ここでいうオブジェクト指向とは、難しく考える必要はありません。
たとえば、OSの中に「ファイル」「プロセス」「ウィンドウ」「通信相手」などの対象があるとします。
Machでは、それらを直接カーネル内の固定機能として扱うのではなく、ポートという通信口を通じて操作する対象 として扱います。
つまり、何かを操作したい場合は、その対象に対応するポートへメッセージを送ります。
この仕組みによって、対象が同じマシンの中にあっても、ネットワーク越しの別マシンにあっても、利用者側は同じように操作できます。
Machが提供する4つの基本概念
Machの中心には、以下の4つの抽象化があります。
1. タスク
タスクは、プログラムが動くための「入れ物」です。
タスクには以下のような資源が含まれます。
- 仮想アドレス空間
- ポートへのアクセス権
- システム資源への保護されたアクセス
従来のUNIXでいうプロセスに近いものですが、Machではプロセスをそのまま使うのではなく、より細かく分解しています。
UNIXのプロセスは、Machでは基本的に 1つのタスク + 1つのスレッド として表現されます。
2. スレッド
スレッドは、CPUで実際に実行される単位です。
タスクが「作業部屋」だとすると、スレッドはその部屋の中で実際に作業する「人」のようなものです。
1つのタスクの中に複数のスレッドを作ることができます。
これにより、1つのアプリケーションが複数の処理を並行して実行できるようになります。
特に、複数CPUを持つマルチプロセッサ環境では、複数のスレッドを同時に動かすことで性能を引き出せます。
3. ポート
ポートは、Machにおける通信チャネルです。
より直感的に言うと、ポートは メッセージを送るための受け口 です。
Machでは、タスクやスレッドなどのオブジェクトを操作するときにも、ポートを通じてメッセージを送ります。
この仕組みによって、OS内部の機能も、ユーザー空間のサービスも、ネットワーク越しのサービスも、同じような形で扱えます。
4. メッセージ
メッセージは、ポートを通じて送られるデータです。
Machのメッセージには、単なるバイト列だけでなく、型付きデータやポートへの権利を含めることができます。
つまり、メッセージを通じて「データ」だけでなく、「このポートに送信する権利」や「このサービスを利用する権利」も渡せます。
これは、セキュリティや権限管理の面でも重要です。
UNIXのプロセスの問題点
論文では、従来のUNIXのプロセス抽象化には限界があると指摘されています。
UNIXでは、クライアントごとに fork でプロセスを作るようなサーバープログラムがよく使われていました。
しかし、プロセスを作るには多くのコストがかかります。
たとえば、以下のような資源が必要になります。
- プロセス管理用の領域
- ファイルディスクリプタ
- ページテーブル
- 個別のアドレス空間
これでは、たくさんのクライアントを処理するサーバーでは無駄が大きくなります。
そこでMachでは、プロセスを タスク と スレッド に分けました。
タスクは資源を持つ重い単位、スレッドは実行のための軽い単位です。
これにより、1つのタスクの中に複数のスレッドを作り、同じメモリ空間を共有しながら効率よく処理できます。
Machの並列処理モデル
Machでは、アプリケーションは複数の方法で並列処理を実現できます。
これは、これまで説明したタスクとスレッドの分離を前提に、実際にどう組み合わせて使うかという応用パターンの紹介です。
1. 1つのタスク内に複数スレッドを作る
これは現在のマルチスレッドプログラミングに近い考え方です。
同じアドレス空間を共有するため、データの共有がしやすく、高速に動作できます。
2. 複数のタスクでメモリの一部を共有する
完全に同じ空間を共有するのではなく、必要なメモリ領域だけを共有できます。
安全性と効率のバランスを取りやすい方式です。
3. 複数のタスクがメッセージで通信する
メモリを共有せず、ポートとメッセージでやり取りする方式です。
これは、ネットワーク越しの分散システムにも向いています。
Machの仮想メモリ管理
Machの大きな特徴の1つが、柔軟な仮想メモリ管理です。
論文では、Machの仮想メモリは以下の操作をサポートすると説明されています。
- 仮想メモリ領域の割り当て
- 仮想メモリ領域の解放
- メモリ保護の設定
- 子タスクへの継承方法の指定
ここで重要なのが、Machが copy-on-write を活用している点です。
copy-on-writeとは何か
copy-on-writeは、日本語にすると「書き込み時コピー」です。
たとえば、親タスクから子タスクを作るとき、普通に考えるとメモリ全体をコピーする必要があります。
しかし、それは非常に重い処理です。
そこでcopy-on-writeでは、最初は実際にコピーしません。
親と子が同じメモリ内容を共有しておき、どちらかがそのメモリを書き換えようとした瞬間に、そのページだけをコピーします。
これにより、fork のような処理をかなり高速化できます。
Machでは、UNIXの fork もこの仕組みを使って効率よく実現されています。
メモリの継承方法
Machでは、親タスクから子タスクへメモリをどう引き継ぐかを、ページ単位で指定できます。
主な指定方法は以下の3つです。
1. shared
親と子で同じメモリを共有します。
どちらかが書き換えれば、もう一方にも影響します。
2. copy
copy-on-writeでコピーします。
最初は共有し、書き込みが発生したときに必要な部分だけコピーします。
3. none
子タスクには引き継ぎません。
その領域は子タスク側では未割り当てになります。
このように、Machではメモリの扱いを非常に細かく制御できます。
ユーザー空間のページャ
Machの仮想メモリ設計で特に重要なのが、ページフォルトやページアウトの処理を、カーネルだけでなく 非カーネルのタスク に任せられる点です。
通常、メモリに必要なページが存在しない場合、OSカーネルがディスクなどから読み込みます。
しかしMachでは、特定のメモリ領域に対して「この領域のページングはこのタスクが担当する」と指定できます。
たとえば、メモリマップトファイルを実装する場合、ページャとしてファイルシステムを指定できます。
すると、ページフォルトが起きたとき、カーネルはファイルシステムに対して必要なデータを要求します。
これは、カーネルを巨大化させず、ユーザー空間でOS機能を拡張できる重要な仕組みです。
Machの仮想メモリ実装
Machの仮想メモリ実装では、機械依存部分と機械非依存部分が分離されています。
これは非常に重要です。
なぜなら、CPUやハードウェアによってメモリ管理の仕組みは大きく異なるからです。
たとえば、VAXとRT/PCではページテーブルの仕組みが違います。
Machでは、機械に依存しない部分が仮想メモリの論理的な情報を管理し、機械依存部分はページの有効化、無効化、保護設定などの低レベル操作に集中します。
この設計により、Machは複数のハードウェアへ移植しやすくなっています。
論文の8ページにある図では、タスクのアドレスマップ、共有マップ、バックストアの関係や、機械依存部分と機械非依存部分の分離が示されています。
Machのプロセス間通信 IPC
Machのもう1つの中心機能が、プロセス間通信、つまりIPCです。
従来の4.3BSD UNIXでは、プロセス間通信には以下のような複数の仕組みが使われていました。
- パイプ
- pty
- シグナル
- ソケット
しかし、これらは統一された仕組みではありません。
特にネットワーク通信で使われるソケットは、IPアドレスなどの機械に依存した名前を使うため、場所に依存しやすく、保護機構も十分ではありませんでした。
Machでは、IPCを ポート と メッセージ で統一的に扱います。
ポートは「安全な窓口」
Machのポートは、カーネルによって保護されたメッセージキューです。
ポートには複数の送信者が存在できますが、受信者は基本的に1つです。
重要なのは、ポートへアクセスするには ポート権限 が必要なことです。
つまり、誰でも勝手にポートへメッセージを送れるわけではありません。
メッセージの中にポート権限を含めることで、他のタスクに権限を渡すこともできます。
これにより、MachのIPCは単なる通信手段ではなく、権限管理の仕組みとしても機能します。
メッセージには大きなデータも送れる
Machのメッセージは、固定長のヘッダーと可変長の型付きデータから構成されます。
メッセージには、ポート権限やポインタも含めることができます。
さらに、Machでは非常に大きなデータもメッセージとして送ることができます。
論文では、タスクのアドレス空間全体に相当するサイズまで送れると説明されています。
ただし、巨大なデータを毎回コピーしていたら非常に遅くなります。
そこでMachでは、ここでもcopy-on-writeを使います。
大きなメッセージ転送の仕組み
論文の図5では、大きなメッセージを送るときのメモリマッピングの流れが説明されています。
たとえば、タスクAが24MBの大きなデータをタスクBに送るとします。
普通に考えると、24MBを丸ごとコピーする必要があります。
しかしMachでは、送信時にそのメモリ領域をcopy-on-writeとして扱います。
つまり、実際のデータをすぐにコピーするのではなく、メモリマップを操作して、必要になるまでコピーを遅らせます。
これにより、大きなデータを効率よくプロセス間でやり取りできます。
この考え方は、Machの大きな強みです。
Matchmakerによるインターフェース定義
Machでは、プロセス間のインターフェースを定義するために Matchmaker というインターフェース定義言語が使われています。
Matchmakerは、C、CommonLisp、Pascalなどの言語向けに、リモートプロシージャコール風のスタブを生成します。
リモートプロシージャコール(RPC)風とは、離れた場所にある処理を、あたかも手元の関数を呼び出すのと同じ感覚で使えるようにする仕組みのことです。
これにより、開発者は低レベルなメッセージ送受信を直接書かなくても、関数呼び出しに近い形でプロセス間通信を扱えます。
また、メッセージ内の型情報を利用して、異なるCPUアーキテクチャ間でのデータ変換や整列調整も行えるようになっています。
ネットワーク越しの通信
Machカーネル自体は、ネットワーク通信を直接提供するわけではありません。
代わりに、ユーザー空間の ネットワークサーバー が、Mach IPCをネットワーク越しに拡張します。
この考え方が非常に重要です。
カーネルにネットワーク機能をすべて入れるのではなく、ユーザー空間のサーバーが「リモートのポート」をローカルにあるかのように見せます。
タスクから見ると、送信先のポートが同じマシン上にあるのか、ネットワーク越しにあるのかを意識する必要がありません。
これは、現在の分散システムやマイクロサービス的な発想にも通じる部分があります。
セキュリティ
Machのポートは、能力ベース、つまり capability-based な保護機構を持っています。
簡単に言えば、「そのポートを使う権利を持っているかどうか」でアクセスを制御します。
ネットワーク越しでもこの保護を維持するために、ネットワークサーバーは暗号化を利用してセキュリティを拡張できると論文では説明されています。
つまりMachは、単に通信を便利にするだけでなく、分散環境でも安全に権限を扱うことを目指していました。
Machのシステム支援機能
Machは基本機能だけでなく、開発や運用を支援する機能も持っていました。
カーネルデバッガ
Machには、adbに基づくカーネルデバッガ kdb が組み込まれています。
adbとは、UNIXで古くから使われてきた汎用のデバッガで、メモリやレジスタの中身を直接確認しながらプログラムの動作を調べるためのツールです。
従来のUNIXカーネル開発では、デバッグが非常に大変でした。
多くの場合、printfを埋め込んで調査するような方法が使われていました。
Machのカーネルデバッガでは、以下のような機能が使えます。
- ブレークポイント
- シングルステップ実行
- スタックトレース
- シンボルテーブル変換
- ローカル変数やレジスタを含む詳細なスタックトレース
- 命令数のカウント
これは、カーネルのデバッグや性能調整に非常に役立ったと論文では述べられています。
透明なリモートファイルシステム
Machには、透明なリモートファイルシステムも用意されています。
これは、ユーザーがリモートのファイルシステムを、あたかもローカルにあるかのように扱える仕組みです。
通常のUNIX操作、たとえば以下のような操作がリモートでも使えます。
- read
- write
- open
- close
- リモートディレクトリの利用
- リモートファイルの実行
リモートファイルシステムへのリンクは、特別なファイル型によって表現されます。
mountポイントではなく特別なリンクを使うことで、多数のリモートファイルシステムへ柔軟に接続できるようにしています。
MachはUNIXをどう作り変えようとしたのか
論文の重要な主張は、MachがUNIXの単なる拡張ではなく、UNIXを再構築するための新しい土台 だという点です。
当時のBerkeley UNIXカーネルは、機能追加によってどんどん大きくなっていました。
その結果、UNIXの長所であったシンプルさや変更しやすさが失われつつありました。
Machの方針は、UNIXの機能をできるだけカーネル外へ出し、ユーザー空間のタスクとして実装することです。
カーネルには以下のような基本機能だけを残します。
- 仮想メモリ管理
- プロセス間通信
- 低レベルデバイスドライバ
- マルチプロセッサスケジューリング
- UNIXトラップのリダイレクト
一方で、UNIXのファイルシステムやプロセス管理などは、将来的にはユーザー空間のサービスとして実装することを目指していました。
論文15ページの図6では、Machカーネルの上にUNIX互換機能やネットワーク機能がユーザー空間のサービスとして乗る構成が示されています。
Mach-1の当時の実装状況
論文執筆時点、つまり1986年4月時点では、Machはまだ開発中でした。
ただし、すでに多くの機能は動作しており、CMUの研究プロジェクトで実際に利用されていました。
論文によると、当時Machは以下の環境で動作していました。
- VAX 11/750
- VAX 11/780
- VAX 11/785
- VAX 8600
- MicroVAX I
- MicroVAX II
- 4プロセッサ構成のVAX 11/784
- IBM RT/PC
また、SUN 3、Encore MultiMax、VAX 8300への移植作業も始まっていたとされています。
ただし、スレッド機構については、1986年夏までの実装が予定されている段階でした。
性能面での評価
論文では、Machはまだ十分な性能比較が行われていないとされています。
しかし、初期の簡単な測定では、仮想メモリ性能について良い結果が出ていました。
たとえば、MicroVAX IIで新しく割り当てたメモリにアクセスするコストは、1024バイトあたり0.7ミリ秒未満で、4.3BSDの約1.2ミリ秒より速かったと説明されています。
また、UNIXでは高コストになりがちな fork も、Machの新しい仮想メモリ機構によって大幅に高速化されると述べられています。
Machの何がすごかったのか
Machのすごさは、単に「新しいOSを作った」という点ではありません。
より重要なのは、OSの設計を次の方向へ進めようとしたことです。
1. カーネルを小さくしようとした
Machは、すべてをカーネルに入れるのではなく、基本機能だけをカーネルに置き、他の機能をユーザー空間のサーバーとして実装しようとしました。
これは、後のマイクロカーネル思想につながる考え方です。
2. 通信を中心にOSを設計した
Machでは、ポートとメッセージが中心的な役割を持ちます。
タスクやスレッドの操作、サービスの利用、ネットワーク越しの通信などを、統一的なメッセージ通信で扱います。
3. マルチプロセッサを前提にした
当時のUNIXは、現在ほどマルチCPU環境を前提にしていませんでした。
Machは、複数CPUを使う環境を想定し、タスクとスレッドを分離しました。
これは、現在のOSでは当たり前になっている考え方です。
4. 仮想メモリとIPCを統合した
Machでは、大きなメッセージ転送にcopy-on-writeを使うなど、仮想メモリとIPCが密接に統合されています。
この設計により、大量データのやり取りを効率化できます。
5. 分散環境を意識していた
Machは、1台のコンピュータだけでなく、ネットワークで接続された複数のマシンを含む環境を想定していました。
ポートによる抽象化により、ローカルとリモートの違いを隠すことを目指していました。
誰にでもわかるMachのイメージ
Machを日常生活にたとえると、次のように考えるとわかりやすいです。
ここまでの詳しい仕組みの話を、このたとえで一気に整理してみましょう。
従来のUNIX
従来のUNIXは、1つの大きな役所のようなものです。
最初はシンプルな窓口だけで十分でした。
しかし、時代が進むにつれて、住民票、税金、保険、郵便、交通、福祉など、どんどん機能が増えていきました。
その結果、役所の中が複雑になり、部署ごとに手続きがバラバラになってしまいました。
Mach
Machは、役所の建物そのものを整理し直す考え方です。
中心には、最低限の共通窓口だけを置きます。
それぞれのサービスは、独立した部署として外側に置きます。
利用者は、どの部署が同じ建物の中にあるのか、別の場所にあるのかを気にせず、共通の窓口を通じて依頼できます。
この共通窓口が、Machでいうポートとメッセージです。
Machの限界や注意点
Machは非常に先進的な設計でしたが、すべてが完璧だったわけではありません。
論文時点では、まだ開発中であり、詳細な性能比較も十分ではありませんでした。
また、マイクロカーネル的な設計では、ユーザー空間のサーバーとカーネル間の通信が増えるため、設計や実装によってはオーバーヘッドが問題になる可能性があります。
つまり、Machの設計思想は非常に強力ですが、実際に高速で使いやすいOSにするには、IPC性能やサーバー設計が極めて重要になります。
まとめ
Machは、UNIXを将来のコンピュータ環境に対応させるために作られた、新しいOSカーネルです。
従来のUNIXが抱えていた問題は、機能追加による複雑化、マルチプロセッサ対応の難しさ、統一性のない通信機構、分散環境への対応不足でした。
Machはこれに対して、以下のような設計を採用しました。
- タスクとスレッドの分離
- ポートとメッセージによる統一的なIPC
- copy-on-writeを活用した効率的な仮想メモリ
- ユーザー空間ページャ
- ネットワーク透過な通信
- capability-basedな保護
- UNIX機能をユーザー空間へ移す構想
Machの本質は、UNIXを単に拡張することではありません。
OSの基本構造を見直し、マルチプロセッサ、分散システム、拡張可能なOSサービスに対応するための新しい土台を作ることでした。
この論文は、現在のOS設計や分散システム、マイクロカーネル、メッセージパッシング、マルチスレッド処理を理解するうえでも重要な内容を含んでいます。
参考文献
Mike Accetta, Robert Baron, William Bolosky, David Golub, Richard Rashid, Avadis Tevanian, Michael Young, “Mach: A New Kernel Foundation For UNIX Development”, Carnegie Mellon University.
https://cseweb.ucsd.edu/classes/wi11/cse221/papers/accetta86.pdf?utm_source=chatgpt.com


