このページの本文へ

Windows Info 第73回

Windows Subsystem for Linuxの中身を詳しく見る

2016年10月09日 10時00分更新

文● 塩田紳二 編集● ASCII.jp

  • この記事をはてなブックマークに追加
  • 本文印刷

 Windows 10 バージョン1607(Windows Anniversery Update、RedStone1)には、Windows Subsystem for Linux(以下WSLと略す)が搭載されている。これは登録されるアイコンの名称などから、「bash on ubuntu on windows」などと呼ばれている。簡単にいうと、WSLとは、Windowsの中でUbuntu Linuxを動作させるもの。コマンドラインからUbuntu Linuxのシェルであるbashを起動すると、そこはもうLinuxの中だ。

Windows Subsystem for Linuxは
仮想マシン環境ではなく、サブシステムで動かす

 WSLはいわゆる「仮想マシン環境」ではない。どちらかというと「コンテナ」と呼ばれるものに近いが、仮想マシン支援機能はまったく使っていない。そもそもSubsystemとは、初期のWindows NTでOS/2やPosixのソフトウェアを動かすために導入された仕組みだ。

 Windows NTは、もともとOS/2のバージョンアップ版となるOS/2 3.0として開発が始まったが、IBMとマイクロソフトが方向性の違いから決別。マイクロソフトは32bit版WindowsとしてWindows NTを開発した。マイクロソフトは、IBM以外のPCメーカーに自社ブランドでOS/2をライセンスしていたため、互換性のためにOS/2のソフトウェアを動かす必要があった。また当時、米国政府に納入するコンピュータはPosixのアプリケーションが動作することが義務づけられていた関係でPosixの互換環境も必要になった。このため、Windows NTにはサブシステムという概念が導入されたのだ。

 初期のWindows NTは、カーネルに最低限の機能しか持たせない「マイクロカーネル」で開発が行われた。マイクロカーネルでは、大多数のAPIは、ユーザーモードで動作するソフトウェアモジュール(これがサブシステム)で実現する。このとき、複数のサブシステムを用意し、アプリケーションごとに切り替えて利用できるようにすることで、Windowsアプリケーション以外にOS/2やPosixのアプリケーションを実行可能にした。

 OS/2サブシステムはWindows XPで非搭載となり、Posixサブシステムは、Windows VistaからはSubsystem for UNIX-based Application(SUA)に切り替わり、Windows 8で非搭載となった。このためWindows10 TH1、TH2には、Windowsサブシステムしか動作していない。

 RS1のWSLは、Posixサブシステムの「リバイバル」だが、単純な復活ではなく、Ubuntu Linuxのカーネルに相当する機能をカーネルモード側でエミュレーションする。このためにRS1には、「LXSS.SYS」「LXCore.SYS」の2つのカーネルドライバが追加されている。このカーネルドライバは、Windowsのカーネル機能を利用しながら、Linux環境(WSLのプロセス)に対してカーネルのエミュレーションを行なう。このとき、利用されるのが、picoプロセスだ。picoプロセスは、簡単にいえば、特定のサブシステムに属さず、サブシステムに関連するモジュールなどもロードされていない「素」のプロセスだ。

 WSLでインストールされるbash.exeは、完全なWindowsアプリケーションだが、起動するとLinuxセッションマネージャーを起動する。セッションマネージャーは、システム側のソフトウェアなので、非公開のWindows Exective APIを使って、Windowsカーネルに対してPicoプロセスによるLinux環境の立ち上げを依頼する。ただし、この部分のメカニズムは、従来のPosixサブシステムの仕組みをある程度流用しているようだ。

 WSLを有効にすると、プロセスの環境を作るセッションマネージャのレジストリ設定に、サブシステムとしてPosixが追加される。ここにあるPSXSS.EXEは、PosixまたはSUAのセッションマネージャだと思われる。ただし、RS1には「%SystemRoot%\system32」(C:\Windows\system32)に同名のファイルはなく、形式的に定義が行われていると考えられる。

RS1でWSLを有効にすると、WindowsセッションマネージャにPosixサブシステムに相当するものが登録される。「Optional」「Posix」キーは、TH2やWSLを有効にしていないRS1には登録されていないキーだ

 もっともWSLが起動されるメカニズム自体は、POSIX/SUAとはまったく違うものだ。bash.exeが起動すると、Linuxセッションマネージャ(LXSSマネージャ)を起動する。LXSSマネージャは、Windows Exective API(すべてのサブシステムが使うカーネル側のAPIセット)を使って、Linuxプロセスの起動を依頼する。LXSSマネージャは、通常のWindowsサービスであり、他のWindowsサービス同様、管理ツールの「サービス」で見ることができる。

ローカルサービスとしてLxssManager(Linuxセッションマネージャー)が登録されている。ここにあるELFバイナリとは、Linuxの実行ファイル形式をさす

 カーネル側には、LXSS.SYS、LXCore.SYSカーネルドライバがあり、これがLinuxカーネルをエミュレーションしている。便宜的にここをLXSS/LXCore.SYSとする。これは、Windowsサブシステムでいえば、Win32K.SYSに相当するものだ。

 LXSS/LXCore.SYSは、Linuxカーネルとして必要な初期化などを行ったのち、vmlinux相当のモジュール(カーネルAPIを受け付けLXSS/LXCore.SYS側に転送する)をLinuxプロセスにリンクし、最初のユーザーモードプログラムとなるinitを起動する。initは、Linuxで最初に起動され、ユーザープロセス内の環境を整え、ログインシェルとなる/bin/bashなどを起動するプログラムだ。

 bash.exeが起動すると、LXSSマネージャにより、WSL側のプロセスが作られ、まずはinitプロセスが起動する。その後、このinitプロセスが/bin/bashを起動する。

bash.exeがLXSSマネージャーサービスを起動すると、LXSSマネージャは、カーネルモード側のモジュールを使い、WSLを動作させる。カーネルモード側のLXSS.SYS/LXCore.SYSがLinuxカーネルの役目を果たし、Linuxで初期化を行うinitプロセスを起動する。その結果/bin/bashが起動する

 Windowsで起動中のプロセスを表示できるProcess Explorerで見てみると、initやbashといったWSL側のプロセスは、Linuxセッションマネージャの子プロセスになっているようだ。

Process Explorerでbash.exeを起動した状態を見ると、下でbash.exeが起動していて、LXSSマネージャサービス(一番上にあるPID12716のサービス)が起動していて、その下にinit、bashプロセスが見える。bash.exe内でさらに/bin/bashを起動すると、2つめのbashが起動する

 このように、LinuxのプログラムもWindowsのプロセスと同じように扱われている。つまり、プロセスやスレッドのスケジューリングやメモリ割り当てなどは、すべてWindowsカーネルが管理している。

 WSL側のLinuxプログラムからのカーネル起動呼び出しは、おそらく、SYSENTER/SYSCALLなどの特権命令のトラップで処理されていると考えられる。Linuxでは、カーネルの機能呼び出しは、これらの特権命令、あるいはint80hコールが使われる。これらは、特権命令となるため、通常のプロセスでは、命令実行時に割り込みが発生し、Windowsカーネルに制御が移る。カーネルモードで、LXSS/LXCore.SYSでこれらの特権命令を解析し、適切なWindowsカーネル呼び出しとして処理を行なう。

 また、/bin/bashなどの標準入出力は、LXSSマネージャ経由で接続されたbash.exeのWindowsコンソールに表示される。Windowsコンソールは、実際にはconhost.exeというプログラムで、通常は、cmd.exeのサブプロセスとして起動される。bash.exeでも同様にサブプロセスとして起動され、bash.exeからの出力をコンソールウィンドウに表示し、キーボード入力をbash.exeへと渡す。

 実際のところbash.exeは、WSLとの中継を行うように動作するわけだ。なお、bash.exeのプロパティを見ると説明は「Microsoft Bash ランチャー」になっている。

bash.exeの説明は「Microsoft Bashラウンチャー」であり、あくまでもWSLを起動して/bin/bashを起動するためのプログラムとなっている

 bash.exeが終了すると、Linuxセッションマネージャは残るがinitやbashなどWSL側のプロセスは終了してしまう。このため、WSLでは、Webサーバーなどを動かすのには向いていないとされている。

 WSLプロセス内で動作するソフトウェアは、Ubuntu Linux用に配布されているバイナリコード(ELF形式)そのもので、WSL用に別途コンパイルして生成したバイナリプログラムではない。つまり、WSLで起動されるプロセスは、そこで動作しているプログラムからみれば、すべてUbuntu Linuxのプロセス環境とまったく同じなのである。だから、バイナリプログラムは、Ubuntu Linuxとまったく同じようにLinuxのAPIを呼び出す。

 このとき、カーネルが行なう処理に対しては、Windowsカーネルモード内で動作しているLXSS/LXCoreが受け取り、必要に応じてWindowsカーネルの機能を使って実現する。

 ファイル関係のカーネルAPIなどは、Windows用のAPIに変換して処理される。このため、WSL内のLinuxプロセス/スレッドからは、Linuxと同じようにカーネルが処理しているように見えるが、実際には、NTFSなどのWindowsのファイルシステムのAPIを介して処理されている(Linuxが持つNTFSアクセスの機能を使っているわけではない)。

 WSLは、このために2つのファイルシステムを持っている。1つは、Linux側に基本的なファイルシステム(rootfs)を見せるためのVolFSだ。WSLでは、各ユーザーのAppdataフォルダ以下にLinux用のファイルシステムを持つ。具体的には、

%userprofile%\appdata\local\lxss\

の下にある「rootfs」以下が、WSLのルートディレクトリになる。ただし、ユーザーのホームディレクトリ、rootユーザーのホームディレクトリは、同じくlxssフォルダ以下のhomeとrootになっている。これは、Linuxのインストール自体と各ユーザーが保持しているファイルを分離するためだ。実際のLinuxでも、これらは別パーティションになっていることが多い。

 なお、WSLにLinux環境をインストール/アンインストールするコマンド「lxrun.exe」で、アンインストールを行うとき、「/full」オプションを付けなければ、ユーザーやrootのホームディレクトリは削除されない。

 また、これからわかるようにWSLは、ユーザーごとにLinux環境のファイルシステムを持つことになり、同一マシンに登録されたユーザー間でも、まったく違うファイルシステムにアクセスすることになる。

 さて、次回は、WSLの内部からLinux環境を見てみることにしよう。

カテゴリートップへ

この連載の記事

注目ニュース

ASCII倶楽部

プレミアムPC試用レポート

ピックアップ

ASCII.jp RSS2.0 配信中

ASCII.jpメール デジタルMac/iPodマガジン