世界を動かす技術を、日本語で。

fork()とexec()を超えて

2026年6月6日原文(lwn.net)

概要

  • Linuxカーネルにおける プロセス生成の現状と課題 を解説
  • Li Chen による「spawn templates」提案の内容とその評価
  • fork()/exec() パターンの非効率性と、その最適化アプローチ
  • posix_spawn() 導入の可能性と今後の方向性
  • 今後の Linuxプロセス生成API の進化の展望

Linuxのプロセス生成とspawn templates提案

  • Unixの伝統的なプロセス生成は fork() で親プロセスをコピーし、 exec() で新プログラムに切り替える方式

  • Linuxカーネルでは clone()execve() が該当システムコール

  • fork() はプロセス状態(メモリなど)をコピーするため、 高コストな操作

  • 多くの場合、 fork()の直後にexec() が呼ばれ、コピーしたメモリがすぐ破棄される非効率なパターン

  • vfork() などの最適化も限定的な効果

  • Li Chen の「spawn templates」パッチセットの概要

    • 同じ実行ファイルを何度も起動するケースでの最適化を狙い

    • 例:Gitコマンドを繰り返し呼び出すプログラム

    • spawn_template_create() システムコールでテンプレートを作成

      • 実行ファイルのパスやファイルディスクリプタを指定
      • カーネルが実行ファイルの情報をキャッシュ
      • テンプレートはファイルディスクリプタで管理
    • プロセス起動時の個別設定は spawn_template_spawn_args 構造体で指定

      • 引数リスト(argv)、環境変数(envp)、ファイルディスクリプタやシグナルの操作(actions)など
      • actionsは spawn_template_action 構造体で表現
        • 例:特定FDのクローズや複製、作業ディレクトリ変更など
    • spawn_template_spawn() システムコールで新プロセスを起動

      • 内部的にはfork()/exec()に近いが、テンプレートのキャッシュで高速化
      • ベンチマークでは 約2%の速度向上 を確認
      • 大規模なプロセス起動が頻繁なアプリケーションで効果を発揮

posix_spawn()と今後のプロセス生成API

  • Mateusz Guzik による詳細なレビュー

    • 問題の本質は fork()のコスト にあり、fork()自体を排除すべきと指摘
    • 「現在のプロセスをコピーするより、 クリーンな新プロセスの生成 が最適」と主張
  • Christian Brauner の提案

    • exec用のビルダーAPI のアイデアを肯定
    • 既存の pidfd 抽象化を活用すべきと提案
      • pidfd_open() で空のプロセスを生成するオプション
      • 新システムコール pidfd_config() で環境や実行イメージなどを設定
      • fsconfig() に類似した設定方式
    • 目標は ユーザ空間でのposix_spawn()実装 を可能にすること
      • fork()/exec()の隠蔽ではなく、ネイティブなAPIとして提供
  • Li Chen もBraunerの方向性に同意し、今後はそちらの設計で進める意向

  • 現時点では「spawn templates」はLinuxカーネルに採用されない見込み

  • 将来的に 本格的なposix_spawn()実装 がLinuxに導入される可能性

まとめ

  • 現行の fork()/exec()モデル は高コストで非効率な場合が多い
  • 「spawn templates」は部分的な最適化だが、根本的な解決には新APIの導入が必要
  • pidfd ベースの新しいプロセス生成APIと posix_spawn() 実装への期待
  • Linuxのプロセス生成は今後も進化が続く見通し

Hackerたちの意見

チェンのパッチが却下されたのは驚かないよ。あれはすごくニッチなユースケースで、サポートする価値がないからね。シェル開発者の視点から言うと、「開発者は、(現在の実装とは違って)fork()とexec()を隠さないネイティブ実装を歓迎するだろう」という締めの意見には同意だね。

彼らはそのコンセプトには興味があるみたいだけど、特定の実装には興味がないって感じだね。

ここでこの古いAPIについての議論がたくさんあるよ、たとえばここね。 https://news.ycombinator.com/item?id=31739794

最近、フォークしたプロセスでファイルディスクリプタをもっと閉じる必要があって、ちょっとしたバグに遭遇したんだ。「現在のプロセスのクローンが欲しい」ってのは、経験上「完全に新しいプロセスが欲しい」よりもずっと一般的じゃない気がする。後者を直接表現する方法がないのはおかしいし、クローンしてから後で修正するしかないのは変だよね。

「完全に新しいプロセス」ってどういう意味?

でも、一般的にはそのプロセスと通信したいから、ファイルディスクリプタとかの設定が必要だよね。親プロセスから情報を渡す必要があるし。

それはO_CLOEXECでカバーされてるんじゃない?

後者のことを直接表現する方法がないなんて、ちょっとおかしいよね。posix_spawnってそれのためにあるんじゃないの?

fork() + exec()モデルのエレガンスは、フォーク後にすべての通常のAPIを使ってあらゆる種類の設定ができるところだよ。今まで見た中で、これを組み合わせた呼び出しに置き換えようとした試みは、すべて根本的に劣っているように見えた。なぜなら、すべての設定オプションを呼び出しのパラメータとして追加しなきゃいけなくて、後で拡張できるようにしつつ、混乱しないようにする必要があるから。

僕は全く逆の意見だね。UNIX的なモデルの大きな間違いは、プロセス作成時にあまりにも多くの状態が保持されることだと思う。たとえば、特定のものをfd番号4にするAPIがあって、それを使ってプログラムを実行し、そのものをfd4で見つけることができる。これって変だよね。Windowsは、たくさんの欠点があるけど、fork+execを使わずにプロセスを作成する方法の選択肢がほとんどだった。優雅ではなかったけど、それが正しい決断だったと思う。

そうだね。fork()を排除する正しい方法は、プロセス状態を変更する通常のAPIが明示的なプロセスハンドルを取るようにすることだよ。そうすれば、同じAPIを使って空のプロセスをセットアップできるし、IPCやデバッグのために他の方法でも組み合わせられる。

これは主に、ほとんどのシステムコールがターゲットPIDを受け入れないという設計ミスを誤魔化してるだけだね。そうじゃなければ、単にサスペンドされたプロセスを作って、ターゲットPIDを明示的に受け取るシステムコールで設定してから開始すればいいんだ。

Hacker Newsで議論の続きを見る