Open4

Reposoup: 実行トレースのPOSIX移植

okuokuokuoku

ちょっと開発環境が多すぎて収集付かなくなってきたので、棚卸しと標準化を進めることにした。そもそもRISC-VとかXtensaって本来マイナープロセッサだと思うんだけど何でこの界隈では普及してんのか。。まぁこの種の多様性のお陰でお給料が発生しているんだから文句は言ってられないけど。。

トレースツールは以前Win32向けに作っている:

https://qiita.com/okuoku/items/2e85d4e22a0a5acb3ae1

POSIXは基本的にCMakeの CMAKE_C_COMPILER_LAUNCHER とかで済ませてしまっていたので、今回Win32用のトレーサをPOSIXに移植して構成法を統一することにした。

okuokuokuoku

実装方針

今回は posix_spawn とblocking I/O + pthreadの組合せでやってみる事にした。こうすることで、 元のWin32版 の構成に近づけることができる。

posix_spawn の活用

残念ながら Cygwinの posix_spawnfork(2) の実装と等価 なので、この点はCygwinではパフォーマンスに貢献できない。LinuxやBSD、UNIX系のOSでは専用の最適化がある。特に:

  • Linuxはglibc 2.24以降で clone(2) を使うようになった
  • NetBSDでは posix_spawn自体がsyscallになっている
  • Solarisでは現状での最終版である 11.4 で spawn(2) syscall が追加され て、 posix_spawn はそれを活用する

POSIX互換の組込みOSであるQNXも、最新バージョンで vfork をdeprecateして posix_spawn を推奨 している。(QNXは現在BlackBerryに買収されているが、その元々の用途であったBlackBerryは今日サービスを完全に終了する。)

okuokuokuoku

posix_spawn の使われ方

まぁ多分 ninja 程度の表現力があれば十分だろうということで、ninjaの実装を確認する。

https://github.com/ninja-build/ninja/blob/ce700488e01af33bc478bc986e261e306180b993/src/subprocess-posix.cc#L121

pipe(2) してあとは posix_spawn_file_actions_init して fd を繋いでいくくらいのようだ。

  • stdin -- これは /dev/null に接続されるが、 monoがstdinを要求していた のでユニバーサルに安全なのかはちょっと自信が無い。
  • stdoutstderr -- これらは用意した pipe に 両方とも dup2 で接続される。確かに、ninjaは挙動としては通常の出力とstderrを区別していないようだ。実行トレースでは両者を区別する必要があるので、別々のpipeに接続する必要がある。
  • posix_spawn_file_actions_addclose に 用意したpipe を渡す(stdout、stderrで無い方の端をcloseする)

また、 pipeの逆端は SetCloseOnExec しておく。... ninja互換ビルドシステムである Samurai は posix_spawn_file_actions_addclose で処理してるな。。まぁこちらでも同様の挙動になる。この違いは、 ninjaが posix_spawn を使うのを後から実装した ために発生したようだ。(元のコードは fork/exec で実装されていて、こちらの場合は close on execフラグの方が一般的な実装になる)