まえがき
- std::processはポータブルな実装だがにここではunix着目する
プロセス起動
- 新しいプロセスを立ち上げてプログラムを実行する
- サブプロセスと言ったりもする
プロセス
- プログラムを実行している主体
- いろいろ状態をもってる
- メモリ空間
- ファイルディスクリプタ
- 環境変数
 
prcess::Command
- プロセス起動を行うためのAPI
- 実装はポータブル(Posix/Windows)
- UNIXでいうfork-execを行う
 
- シェルを経由する専用APIは用意しない
- newやargの引数に sh -cを渡せばできる
 
- newやargの引数に 
イメージ
- 以下の例ではシェルを経由して実行
- 
outputで出力を受け取るまで暗黙にwait
 
- 
let output = Command::new("sh")
                     .arg("-c")
                     .arg("echo hello")
                     .output()
                     .expect("failed to execute process");
デザイン
- 
Command::new時点ではプロセスを生成しない- 
spawnなどを呼ぶまでの間にやりたいことを設定- 引数の追加(arg/args)
- リダイレクト(stdin/stdout/stderr)
- 環境変数の追加/クリア(env_clear)
- カレントディレクトリ(current_dir)
 
- 引数の追加(
 
- 
デザイン
- waitするかどうかはAPIによって変わる
- spawnはwaitしないので親が明示的に行う
- outputやstatusは当然行う
 
spawn
- ジェネリックなプロセス起動API
- 
std::process::Childを返す- 子プロセスのPIDをもつ
- waitをメソッドにもつ
 
spawnの内部実装
- 条件が合えば posix_spawnを使う
- そうでない場合 forkとexecを使う
posix_spawn
- fork-execまで一気にやってくれるAPI
- 現時点でいくつかのプラットフォームで使える(ただしそれぞれいくつか制約条件はある)
- Linux/Glibc2.24+, MacOS , FreeBSD
 
posix_spawnを使う意図
- メモリを複製しない実装が使われることが多い
- Linuxなら clone(CLONE_VM/E_VFORK)
- Linux: clone(CLONE_VM|CLONE_VFORK)
- MacOS/FreeBSDなら vfork
 
- Linuxなら 
- fork-exec間に差し込めない処理もある
- 
current_dirなど使ったらforkを使う
 
- 
before_exec
- UNIXなシステムのみ存在
- Windowsではそもそも不可能
 
- fork-exec間で行いたい処理をフック可能
- 他ではPythonの preexec_fnなどがある
 
- 他ではPythonの 
- リダイレクトや環境変数以外にもやりたいことはある
- リソース管理 (例: core dump)
- fdのclose処理を書きたいかも
 
before_execは問題ないのか
- 任意の処理が記述できてしまう
- fork-exec間はasync-signal-safeな関数のみ使うべき
- 危険性はドキュメントで注意喚起している
- Pythonも同様
 
 
FDの挙動
- 他の言語のように3番以降のFDをcloseするAPIを提供していない
- Rustのstd自体はCLOEXEC前提
- execのときにcloseするフラグ
 
- Cのライブラリ関数は保証がない
- リークしちゃうかも
 
 
- Rustのstd自体はCLOEXEC前提
過去の議論
- 
https://github.com/rust-lang/rust/pull/27609
- 標準ライブラリの範囲では不要という判断
- どうしても必要なら before_execでできる
- 将来的には変わるかも
 
spawnのまとめ
- プロセス起動のプリミティブなAPI
- fork+属性設定+exec
- posix_spawnを使えるときは使う
 
- 
before_execで振る舞いを自由に記述できる- 注意は必要