Bash On WindowsとWin32の間で共有メモリしたらどうなるのか問題
クライアント版のWindows10にはWSL(Windows Subsystem For Linux)と呼ばれるLinuxカーネルエミュレータが搭載されており、これを使用したBash On WindowsとしてLinuxのバイナリ互換環境を提供している。
世間にはいろいろとこのWSLを使ってアプリケーション環境を作ろうという試みもある:
- https://github.com/kpocza/LoWe
- ptrace()によるsyscall読み替え
- https://github.com/ionescu007/lxss
- Windowsとの交信に使用されるioctlをリバースエンジニアリングで解析、/devへのデバイス追加等
- pdf(Blackhat 2016): https://github.com/ionescu007/lxss/raw/master/The%20Linux%20kernel%20hidden%20inside%20windows%2010.pdf
まぁこの辺はそのうちどうにかなるとして、現段階(= Anniversary Update)のWSLでWin32アプリとの共有メモリを実現するにはどうすれば良いのかを考える。
... で、いろいろ考えたんだけどNTFSなRAMDISKを作り、そのファイルを双方でmmap(2)するが一番簡単なんじゃないかという結論になった。(一般にRAMDISKはFAT32の方が微妙に高速なことが多いが、WSLにWindowsのファイルを見せるにはDrvFs経由で見せる必要があり、このDrvFSが今のところNTFSとReFSにしか対応していない - https://blogs.msdn.microsoft.com/wsl/2016/06/15/wsl-file-system-support/ )
NTFSなRAMDISKはImDisk Toolkit( http://www.majorgeeks.com/files/details/imdisk_toolkit.html )等で簡単に生成できる。
適当に検証プログラムを書きCygwinとWSLのclangでビルドして(__builtin_cyclecount()がClangのintrinsicなので)、とりあえず期待通りメモリ内容が共有できていることが確認できた。
memsetからmsyncされるまでの間にprintf()を挟んでみると対向プロセスがmemsetしていく過程が観察できるため、普通のファイルI/Oでエミュレーションされているわけでは無さそうだ。
Retry @ 1121:2 Retry @ 1121:18432 Retry @ 1121:41472 Retry @ 1121:86528 Retry @ 1121:177152 Retry @ 1121:344576 Retry @ 1121:691200 Retry @ 1121:1517568 Retry @ 1121:3561472
- Cygwin => WSLの順で起動
- WSL => Cygwinの順で起動
微妙にパフォーマンスが違っているのが気になるな。。1.4GB/secくらい出るならそれなりに実用的に使えそうだ。もっとも、LoWeのようにソケットを使って通信するのが普通の方法で、どうせ大体のシチュエーションでは実際にデータを使うためにはコピーが必要なのであまり意味は無いような気がする。どっちにせよプロセス間の同期のためにソケットを使うことになる(そうしないとプロセス間共有semaphore等が実現できない)ので一緒にデータをpiggy-backした方が高速だと思う。
ちなみに、テストコードではmsync()をしているが、msync()を省略してもちゃんと動作する。何故? (デカくてキャッシュに収まらないから。)
現状のInsider previewでは(何故かPosix shared memoryでなく)SysV shared memoryがサポートされているが、これをWin32からアクセスする方法は見当たらなかった。というかipcmkコマンドで複数の共有メモリを作ってもipcsコマンドで1つしか見えない等挙動が不審な気がする。先のPDFにあるように、WSL自体はWin32 <=> WSLプロセスの共有メモリ等も持っているらしく、常識的な方法での共有メモリがサポートされるのもそう遠くは無いように見える。