WSL (Bash on Windows) で Windows のプログラムが実行可能になったので遊んでみた

本当は、先週ぐらいに

Announcing Windows 10 Insider Preview Build 14951 for Mobile and PC | Windows Experience Blog

があって、この Build 14951 で、Windows側のプログラム呼べるようになったよんって書いてあったんだけど、待てど暮らせど、アップデートが落ちてこず。結局、

blogs.windows.com

これが落ちてくるまで待つことになりました。

パイプが動く

さて、この仕組みで、実行できるだけなら普通なんだけど、ちゃんとパイプが動く。
なので、Windows 側の dir の結果を Ubuntu 側で grep したりできる。

f:id:espresso3389:20161027193928p:plain

まぁ、Windows の dir は内部コマンドなので、 cmd.exe を経由しないといけませんが、そうすればいいだけです。
素敵です。逆向きも当然。

GUIアプリを起動してみる

notepad.exe を起動するとどうなるでしょうか?

f:id:espresso3389:20161027192049p:plain

おや、 cmd.exe と違って、ターミナルに制御が戻ってきません(プロンプトが出てない)。
つまり、標準出力・入力系は繋がりっぱなしですね。これ。

そして、この状態で、Ctrl-C を押すと、ターミナルに制御が戻ってきます(プロンプトが表示される)。
ただし、 notepad.exe は死にません。起動しっぱなしです。

どういうこと?っていう感じで、もう一度、 notepad.exe を起動して、 ps でプロセスを見てみると、

f:id:espresso3389:20161027193853p:plain

Windows のプロセスは、 /init 経由で呼ばれてるんですね。
で、Ctrl-C で、 SIGINT を送り付けたら、 /init だけが死ぬと。
init が死ぬって結構、致命的に聞こえますが、まぁ、この init はそういうやつじゃないと。

で、 notepad.exe は死にませぬ。
なので、自分で起動したプログラムの面倒を自分で見切れないという意味では辛いかもしれません。

で、なんで Windows のプログラムが動くの?

スペシャルバージョンのカーネルが動いてます!・・・っていうわけじゃないです。
そもそも、この辺のバイナリは、普通の Ubuntu のものと同一ですしね。

何が起きているかというと、実は、スゲー昔に書いたことあるんですが、

espresso3389.hatenablog.com

の中に、追記で、 binfmt_misc って奴の話があります。これは、Owin の話ですね。
要は、Linux カーネルには、実行ファイルの先頭のバイト列を見て、そのファイルを解釈するプログラムを起動する仕組みがあるんですね。シェルスクリプトの #!/bin/sh とかの拡張だと思えばわかりやすい。
mono とか、 Wine はこの仕組みを利用して、 Linux 上で、 exe が直接動くような感じを実現しています。

細かいことはさておき、この仕組みで、 /init に引数として、 /mnt/c/Windows/System32/notepad.exe が渡されて起動するんですね。なので、実際のプログラムの実行処理は /init に任されてると。WSL の /init は完全に Windows の息のかかったプロセスなので、あとは・・・。

この辺のことは、下の記事に詳しすぎるぐらいに書いてあるので、英語で長文読むのが嫌じゃない人は、是非、読みましょう。

blogs.msdn.microsoft.com