Windows NT系はUNIX系と比較して設計上のどういう点が先進的だったのか?
元Google・現Microsoftのソフトウェアエンジニアであるジュリオ・メリノ氏が、現代のWindows 11の基盤アーキテクチャとなっているWindows NT系と、FreeBSDやLinuxなどに代表されるUNIX系を比較した考察をまとめています。
Windows NT vs. Unix: A design comparison - by Julio Merino
https://blogsystem5.substack.com/p/windows-nt-vs-unix-design
・開発の経緯
MicrosoftはDOS系となるMS-DOSを1981年8月に、Windows 1.0を1985年11月にリリースしました。そして、DOS系の後継としてOS/2をIBMと共同開発していましたが、プロジェクトが難航したため、OS/2とは別となるMicrosoft独自の「Windows NT系」の開発を1989年にスタートし、1993年7月にWindows NT 3.1としてリリースしました。
UNIX系の歴史はWindows NT系よりも古く、1969年にMulticsに触発されて開発が始まりました。UNIX系の主な目的は「プログラマーにとって便利なプラットフォームを提供すること」で、UNIX系は単純さに重点を置くことでMulticsに勝っったとメリノ氏は評価しています。しかし、ポータビリティやマルチタスキングについてはUNIX系の当初の設計目標にはなく、これらの機能は後年にフォークや再発明の中で後付けされたとのこと。
・カーネル
UNIX系は一部の例外を除いて、主にモノリシックカーネルとして実装されています。このカーネルはOSが提供する機能を利用するためのシステムコールのセットを公開し、ユーザー空間のアプリケーションはこのシステムコールインターフェースを通じて直接カーネルと対話します。
一方、Windows NT系のカーネルは、モノリシックカーネルとマイクロカーネルの特徴を組み合わせたハイブリッド設計を採用しています。この設計の中心となるのが「エグゼクティブ」と呼ばれる特権コンポーネントです。
Windows NT系の特徴的な点は、ユーザー空間のアプリケーションが直接カーネルと対話しせず、特定の保護されたサブシステムと対話します。これらのサブシステムには、Win32、POSIX、OS/2などがあり、それぞれが特別なユーザー空間プロセスとして実装されています。サブシステムの役割は、アプリケーションが使用するAPIをエグゼクティブのシステムコールに「変換」することです。
Windows NT系の主要な設計目標の1つは、DOSとDOS系Windows、OS/2、POSIXのアプリケーションとの互換性を確保することでした。メリノ氏によると、Windows NT系で互換性が追求されたのは、IBMと共同開発していたOS/2向けのアプリケーションをサポートする必要があったことが背景にあるそうです。
そして、NTカーネルの重要な構成要素の一つが「ハードウェア抽象化レイヤー(HAL)」です。HALは、マシンのハードウェアにアクセスするための抽象的なプリミティブを提供します。このレイヤーの存在により、Windows NT系はi386、Alpha、PowerPCなど複数のアーキテクチャで動作可能になりました。
また、NTカーネルはマルチプロセッシングシステムをサポートし、プリエンプティブな設計を採用しています。これにより、カーネルスレッドでも実行中に一時中断して他のカーネルスレッドを実行するプリエンプトが可能になりました。この設計は、高性能なシステムを実現する上で重要な役割を果たしています。
これらの特徴により、Windows NT系のカーネルは設計当初から柔軟性と拡張性を持つ構造を採用しており、多くのUNIX系システムが後から段階的に機能を追加していったのとは対照的なアプローチだったとメリノ氏は評価しています。
by Marc Buehler
・ユーザー空間
まず、システムと応用プログラムの設定に関して、NTはレジストリという中央集権的なデータベースを導入しました。これにより、設定の統一性と管理の容易さを実現しました。一方、UNIX系は多数の異なる設定ファイルと形式を使用しており、一貫性に欠ける面があります。
Microsoftが世界市場を意識していたため、Windows NT系は当初からロケールのサポートを組み込んでいました。一方、UNIX系ではUTF-8サポートや多言語サポートが後から追加されたとのこと。プログラミング言語に関しては、NTはMicrosoft独自のC言語拡張を使用して実装されており、構造化例外処理(SEH)などの機能が追加されています。一方、UNIX系システムではこのような独自拡張は一般的ではありません。メリノ氏は、Windows NT系はユーザー空間設計において統一性・国際化・言語拡張などでUNIX系とは異なるアプローチを取っていたことを示していると論じました。
・オブジェクト指向
Windows NT系はオブジェクト指向のカーネルを採用しており、システム内のさまざまな要素が共通の表現を持つように設計されていました。UNIX系でもプロセスは構造体で定義され、ファイルシステムの実装は仮想ノード(Vノード)を扱いますが、Windows NT系ほど徹底したオブジェクト指向の設計ではないとのこと。
Windows NT系のオブジェクト指向設計の主な利点は、システム全体での一貫性と効率性にあります。まず、中央集権的なアクセス制御が可能になります。すべてのオブジェクトはオブジェクトマネージャーによって一元的に作成されるため、権限チェックなどのセキュリティポリシーを単一の場所で定義し、システム全体に一貫して適用できます。これにより、セキュリティ管理が簡素化され、潜在的な脆弱性を減らすことができます。
次に、共通のアイデンティティシステムがあります。プロセス、ファイルハンドル、パイプなど、システム内のあらゆるリソースが単一のオブジェクトツリーで表現されます。これにより、すべてのリソースに対して統一された名前空間が提供され、リソース管理が容易になります。また、異なる種類のオブジェクト間での操作も一貫した方法で行うことができます。
さらに、統一されたイベント処理システムがあります。すべてのオブジェクトタイプがシグナル状態を持つため、プロセスの終了やI/O操作の完了など異なる種類のイベントを、ユーザー空間のプログラムが同じ方法で待機し、処理することができます。これにより、イベント駆動型のプログラミングが容易になり、システムのリソースを効率的に利用できます。
そして、オブジェクト指向設計によって複雑なシステムリソースが一貫した方法で管理され、開発者にとってより理解しやすく、使いやすいインターフェースを提供することが可能になります。また、新しい種類のリソースやサービスをシステムに追加する際も、既存のフレームワークに容易に統合できるため、システムの拡張性も向上します。
しかし、このオブジェクト指向の設計にも課題がありました。オブジェクトはWindows NT系固有の構造であるため、Windows NT系がサポートしようとしていたすべてのAPIに一般化するのは難しい面があります。例えば、POSIXサブシステムでは、NTのオブジェクトとPOSIXのエンティティの間で論理的な変換を行う必要があります。一方でWin32サブシステムは、仲介なしでオブジェクトをクライアントに渡すだけです。
・プロセス
UNIX系では、プロセスはツリー構造で表現され、各プロセスは親を持ち、0個以上の子プロセスを持つことができます。一方、Windows NT系ではプロセス間にそのような関係性はなく、作成元から任意のタイプのオブジェクトを「継承」することはできますが、作成後は独立した存在となります。
Windows NT系は当初からスレッドをサポートしていました。これは、SMPマシンでの高性能コンピューティングに必要不可欠だと認識されていたためです。対照的に、UNIX系システムの多くはスレッドを後から追加しており、既存の設計に適合させる必要がありました。
Windows NT系にはUNIX系のシグナルはありませんが、代わりにアラートがあります。これらはカーネルモードとユーザーモードの両方で存在し、POSIXサブシステムはカーネルモードアラートを使用してシグナルをエミュレートします。また、NTはピコプロセスという概念を導入し、最小限のWindows構造を持つプロセスを実現しました。これはWSL 1でLinux互換プロセスを実装するために使用されています。
・仮想メモリ
Windows NT系とUNIX系は共に、プロセス間の保護と物理メモリ以上の仮想アドレス空間を提供するために、メモリ管理ユニット(MMU)とページングを利用しています。
NTの特筆すべき点は、カーネル自体もディスクにページアウトできることです。もちろん、カーネル全体がページアウト可能なわけではありません。そうすると、カーネルページフォルトの解決にファイルシステムドライバのコードが必要になりますが、そのコード自体がページアウトされている可能性があるという問題が発生するからです。しかし、カーネルの大部分はページアウト可能で、当時はメモリの節約につながりました。
さらに、Windows NT系は当初からファイルシステムと仮想メモリのためのメモリキャッシュが統合されている「ユニファイドメモリアーキテクチャ」を採用していました。対照的に、古いUNIX系、ファイルシステムと仮想メモリに別々のメモリキャッシュがありました。
共有メモリの管理と表現に関しても、Windows NT系とUNIX系には違いがあります。Windows NT系では、共有メモリセクションはオブジェクトであり、他のオブジェクトと同じアクセス検証チェックの対象となります。また、他のオブジェクトと同じ方法でアドレス指定が可能です。これに対し、UNIX系では共有メモリは後から追加された機能で、他のエンティティとは異なる名前空間と異なるAPIを持ち、通常のパーミッションも適用されません。
・I/Oサブシステム
Windows NT系は当初から複数のファイルシステムをサポートするように設計されていました。これは、UNIX系が単一のファイルシステムから始まり、後に仮想ファイルシステム(VFS)抽象化を導入してマルチファイルシステムサポートを実現したのとは対照的です。Windows NT系では、ファイルシステムはオブジェクトツリーの中のオブジェクトとして表現され、各オブジェクトがパスの残りの部分を解析する責任を持ちます。
Windows NT系のファイルシステムであるNTFSは当時としては非常に高度で、64ビットアドレッシング、ジャーナリングファイルシステム、Unicodeファイル名などをサポートしています。
また、NTのI/Oサブシステムの当初からの設計には、現在のRAIDに相当するディスクストリッピングやミラーリング、デバイスのホットプラグなどの機能が組み込まれていたことも特筆すべき点だとメリノ氏は述べています。
リノ氏は「NTのI/Oサブシステムを特に先進的にしている要因は、そのインターフェースが本質的に非同期であること」と指摘しています。。対照的に、多くのUNIX系システムでは非同期I/Oのサポートが後から追加され、その性能も必ずしも優れているとは言えません。
さらにNTのI/Oサブシステムは、名前付きパイプの実装においてもUNIX系とは異なるアプローチを取っています。UNIX系において名前付きパイプはローカルな構造ですが、NTでは名前付きパイプをネットワーク上で動作させることができます。これにより、異なるコンピュータ上のアプリケーション間でネットワークの詳細を気にすることなく通信が可能になります。
・ネットワーク
インターネットが現在ほど普及していなかった時代、DOSやWindows 3.0は限られたネットワーク機能しかサポートしていませんでした。一方、UNIX系はインターネットの基盤として、すべての基本的なインターネットプロトコルがUNIX系上で書かれ、実装されていました。そのため、Windows NT系ではインターネットプロトコルと既存の環境で使用されていた従来のLANプロトコルの両方がサポートされました。
特筆すべき点として、Windows NT系はネットワークドメインの概念を導入しました。UNIX系では、ネットワーク管理者は通常、手作業でマシン間のユーザーアカウントを同期させていました。しかし、NTのネットワークドメインはディレクトリと認証機能を統合し、企業ネットワークでより簡単に設定することを可能にしました。
また、UNIX系は長い間単純な読み取り/書き込み/実行の権限セットしか提供していなかったのに対し、Windows NT系は高度なアクセス制御リスト(ACL)を最初から提供していました。LinuxやBSDもACLをサポートしていますが、いずれも後から追加されたものであり、Windows NT系ほど一貫性のある実装ではありません。
ネットワークファイルシステムに関しては、UNIX系ではNetwork File System(NFS)が、NTではServer Message Block(SMB)が使用されていました。さらに、Windows NT系はネットワークドライバインターフェース仕様(NDIS)を提供し、ネットワークカードドライバーを簡単にサポートできるようにしました。これは、Linuxなどのシステムがメーカー提供のドライバをサポートするのに苦労していたのとは対照的だとメリノ氏は述べています。
・結論
メリノ氏は、現在では当たり前となっているシステム設計の多くの特徴がWindows NT系には最初から備わっており、発売当時のWindows NT系は確かに画期的だったと評価しています。しかし、Windows NT系は堅固な設計原則が設定されていたにもかかわらず、UIの肥大化によってその素晴らしさが失われたと述べ、今となってはLinuxやFreeBSDなど現代のUNIX系システムと比較して著しく進んでいるとは言えないと指摘しました。