[インデックス 12080] ファイルの概要
このコミットは、Go言語のos
パッケージにおけるプロセス待機メカニズムの重要な変更を導入しています。具体的には、os.Process.Wait
メソッドからオプション引数を削除し、独立したos.Wait
関数を廃止しています。これは、これらの機能がプラットフォーム間の移植性の問題を引き起こし、またオプションが実用上ほとんど使用されていなかったという背景に基づいています。
コミット
commit b5a3bd5ff6f735f39a312a43d3f0a647f4d76590
Author: Rob Pike <r@golang.org>
Date: Mon Feb 20 15:36:08 2012 +1100
os: drop the Wait function and the options to Process.Wait
They are portability problems and the options are almost always zero in practice anyway.
R=golang-dev, dsymonds, r, bradfitz
CC=golang-dev
https://golang.org/cl/5688046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b5a3bd5ff6f735f39a312a43d3f0a647f4d76590
元コミット内容
os: drop the Wait function and the options to Process.Wait
They are portability problems and the options are almost always zero in practice anyway.
変更の背景
この変更の主な背景には、Go言語の設計哲学である「シンプルさ」と「移植性」があります。
-
移植性の問題:
os.Process.Wait
メソッドが以前持っていたオプション引数(例:WNOHANG
,WSTOPPED
,WUNTRACED
など)は、基盤となるオペレーティングシステム(OS)のwait
システムコール(Unix系ではwait4
など)の挙動を直接反映していました。しかし、これらのオプションはOSによってサポート状況やセマンティクスが異なり、Goのクロスプラットフォームな性質と相容れない移植性の問題を引き起こしていました。Goは、異なるOS上でも一貫した挙動を提供する抽象化レイヤーを目指しており、OS固有のオプションが露出していることはその目標に反していました。 -
実用上の利用頻度: コミットメッセージにもあるように、これらのオプションは「実用上ほとんどゼロ」でした。つまり、ほとんどのGoプログラムでは、プロセスが終了するまで単純に待機するだけで十分であり、複雑な待機オプションを必要とするケースは稀でした。使用頻度の低い複雑なAPIは、コードの複雑性を増し、学習コストを高めるため、Goのシンプルさを追求する上で削除の対象となりました。
-
os.Wait
関数の冗長性: 独立したos.Wait(pid int, options int)
関数は、os.FindProcess
でプロセスを見つけてからos.Process.Wait
を呼び出すのと同等の機能を提供していました。このような冗長なAPIは、混乱を招き、コードベースを肥大化させるため、よりシンプルで一貫性のあるos.Process.Wait
メソッドに一本化されました。
これらの理由から、Go開発チームはAPIを簡素化し、より堅牢で移植性の高いプロセス待機メカニズムを提供するために、この変更を決定しました。
前提知識の解説
このコミットを理解するためには、以下の概念を把握しておく必要があります。
-
Go言語の
os
パッケージ:os
パッケージは、オペレーティングシステム機能へのプラットフォームに依存しないインターフェースを提供します。ファイル操作、プロセス管理、環境変数へのアクセスなどが含まれます。os.Process
: 実行中のプロセスを表す構造体です。プロセスのPID(プロセスID)などの情報を含みます。os.Process.Wait()
:os.Process
型のメソッドで、関連付けられたプロセスが終了するまで待機し、そのプロセスの状態に関する情報(*os.ProcessState
)を返します。
-
syscall
パッケージとwait
システムコール:syscall
パッケージは、Goプログラムから低レベルのOSプリミティブ(システムコール)に直接アクセスするためのインターフェースを提供します。syscall.Wait4()
: Unix系OSにおけるシステムコールの一つで、子プロセスの状態変化(終了、停止など)を待機するために使用されます。このシステムコールは、待機するプロセスのPID、ステータス情報を格納するポインタ、そして挙動を制御するためのオプション引数を受け取ります。wait
システムコールのオプション:WNOHANG
: このオプションが指定されると、子プロセスの状態変化がすぐに利用可能でない場合でも、呼び出し元のプロセスはブロックされずにすぐに戻ります。子プロセスが終了していない場合、wait4
は0を返します。これは、親プロセスが子プロセスの終了をポーリングしながら他の処理を継続したい場合に有用です。WSTOPPED
: このオプションが指定されると、シグナルによって停止した子プロセスのステータス情報も返されます。これは、子プロセスが終了したわけではなく、一時的に実行を停止している状態を検出するために使われます。WUNTRACED
: このオプションはWSTOPPED
と似ていますが、特にジョブコントロールに関連して、親プロセスが子プロセスの停止(例:SIGTSTP
シグナルによる停止)を通知されるようにします。
-
gofix
ツール:gofix
は、Go言語の初期に存在したコマンドラインツールで、Go言語や標準ライブラリのAPI変更に伴って、古いAPIを使用しているコードを自動的に新しいAPIに書き換えるために使用されました。Go言語は後方互換性を重視していますが、大規模なAPI変更があった際には、gofix
のようなツールが開発者の移行作業を支援しました。このコミットでは、os.Wait(0)
のような特定のパターンを自動的にos.Wait()
に書き換えるためのgofix
ルールが追加されています。
技術的詳細
このコミットの技術的な核心は、os.Process.Wait
メソッドのシグネチャ変更と、それに伴う内部実装の簡素化、そして既存コードの移行支援です。
-
os.Process.Wait
メソッドのシグネチャ変更:- 変更前:
func (p *Process) Wait(options int) (w *Waitmsg, err error)
- 変更後:
func (p *Process) Wait() (w *Waitmsg, err error)
- これにより、
options
引数が完全に削除されました。これは、Goのos
パッケージが提供するプロセス待機機能が、OS固有の複雑なオプションから解放され、よりシンプルで一貫した挙動に統一されたことを意味します。
- 変更前:
-
独立した
os.Wait
関数の削除:func Wait(pid int, options int) (w *Waitmsg, err error)
という形式の関数が、src/pkg/os/exec_plan9.go
とsrc/pkg/os/exec_posix.go
から完全に削除されました。これにより、プロセス待機はos.Process
インスタンスのメソッドとしてのみ提供されることになり、APIの統一性が向上しました。
-
プラットフォーム固有の実装の簡素化:
src/pkg/os/exec_plan9.go
、src/pkg/os/exec_posix.go
、src/pkg/os/exec_unix.go
などのプラットフォーム固有のファイルで、os.Process.Wait
の実装からoptions
引数に関連するロジックが削除されました。特にUnix系OS向けのsrc/pkg/os/exec_unix.go
では、WNOHANG
,WSTOPPED
,WUNTRACED
,WRUSAGE
といった定数定義が削除され、syscall.Wait4
の呼び出しもoptions
引数に0
を渡し、rusage
(リソース使用量)の取得も行わないように変更されました。これは、Goのos
パッケージが提供するプロセス待機が、プロセスの終了を待つという最も一般的なユースケースに特化されたことを示しています。
-
gofix
ツールの導入:- この変更によって影響を受ける既存のGoコードを自動的に更新するために、
src/cmd/fix/oswait.go
とsrc/cmd/fix/oswait_test.go
が追加されました。 oswait.go
は、gofix
ツールが実行された際に、os.Wait(0)
という形式の呼び出しをos.Wait()
に自動的に書き換えるためのルールを定義しています。これは、options
引数が0
(デフォルト値、つまり特別なオプションなし)である場合にのみ自動変換を行い、それ以外の値が指定されている場合はコンパイラエラーとして手動での修正を促すことで、開発者が意図しない挙動変更に遭遇するのを防ぎます。
- この変更によって影響を受ける既存のGoコードを自動的に更新するために、
この変更は、Go言語の標準ライブラリが、よりシンプルで、より移植性が高く、そしてより堅牢なAPIを提供するための継続的な努力の一環として行われました。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
-
src/cmd/cgo/util.go
:p.Wait(0)
の呼び出しがp.Wait()
に変更されています。これは、os.Process.Wait
メソッドのオプション引数削除に伴う修正です。
-
src/cmd/fix/oswait.go
(新規追加):gofix
ツール用の新しい修正ルールを定義しています。oswait
関数は、AST (Abstract Syntax Tree) を走査し、os.Wait
の呼び出しを探します。- もし
os.Wait
が引数としてリテラル0
を持っている場合、その引数を削除してos.Wait()
に書き換えます。 - 引数が
0
以外の場合、またはos.Process.Wait
メソッドの呼び出しである場合は、手動での修正が必要であることを警告します。
-
src/cmd/fix/oswait_test.go
(新規追加):oswait.go
で定義されたgofix
ルールのテストケースです。os.Wait()
、os.Wait(0)
、os.Wait(1)
、os.Wait(A | B)
といった様々な呼び出しパターンに対して、gofix
がどのように変換を行うかを検証しています。特に、os.Wait(0)
がos.Wait()
に変換され、os.Wait(1)
やos.Wait(A | B)
はそのまま残る(手動修正が必要なことを示唆)ことがテストされています。
-
src/cmd/godoc/main.go
:p.Wait(0)
の呼び出しがp.Wait()
に変更されています。
-
src/pkg/os/exec/exec.go
:c.Process.Wait(0)
の呼び出しがc.Process.Wait()
に変更されています。
-
src/pkg/os/exec_plan9.go
:func (p *Process) Wait(options int)
のシグネチャがfunc (p *Process) Wait()
に変更され、options
引数が削除されています。- 独立した
func Wait(pid int, options int)
関数が完全に削除されています。
-
src/pkg/os/exec_posix.go
:- 独立した
func Wait(pid int, options int)
関数が完全に削除されています。
- 独立した
-
src/pkg/os/exec_unix.go
:func (p *Process) Wait(options int)
のシグネチャがfunc (p *Process) Wait()
に変更され、options
引数が削除されています。WNOHANG
,WSTOPPED
,WUNTRACED
,WRUSAGE
といった定数定義が削除されています。syscall.Wait4
の呼び出しからoptions
引数とrusage
関連のロジックが削除され、syscall.Wait4(p.Pid, &status, 0, nil)
のように簡素化されています。
-
src/pkg/os/exec_windows.go
:func (p *Process) Wait(options int)
のシグネチャがfunc (p *Process) Wait()
に変更され、options
引数が削除されています。
-
src/pkg/os/os_test.go
:- テストコード内で
p.Wait(0)
の呼び出しがp.Wait()
に変更されています。
- テストコード内で
-
doc/go1.html
およびdoc/go1.tmpl
:- Go 1のリリースノートに、
Process.Wait
メソッドからオプション引数が削除されたこと、およびWait
関数が削除されたことが追記されています。また、gofix
がos.Wait(0)
の呼び出しを自動的に書き換えること、その他の変更は手動で更新する必要があることが明記されています。
- Go 1のリリースノートに、
コアとなるコードの解説
このコミットのコアとなる変更は、Go言語のプロセス管理APIの簡素化と、それに伴う移行支援メカニズムの導入です。
1. os.Process.Wait
の簡素化:
最も重要な変更は、os.Process.Wait
メソッドからoptions
引数が削除されたことです。
- 変更前:
func (p *Process) Wait(options int) (w *Waitmsg, err error)
- 変更後:
func (p *Process) Wait() (w *Waitmsg, err error)
これにより、開発者はプロセスが終了するのを待つ際に、OS固有の複雑なオプションを意識する必要がなくなりました。内部的には、src/pkg/os/exec_unix.go
に見られるように、syscall.Wait4
の呼び出しはoptions
引数に0
(デフォルトの挙動)を渡すように変更され、リソース使用量(rusage
)の取得も行われなくなりました。これは、Goのos
パッケージが、プロセスの終了待機という最も一般的なユースケースに特化し、より高レベルでプラットフォームに依存しない抽象化を提供することを目指しているためです。
2. 独立したos.Wait
関数の削除:
os.Wait(pid int, options int)
という形式のグローバル関数が削除されました。これにより、プロセス待機はos.Process
オブジェクトのメソッドとしてのみ提供されることになり、APIの一貫性が向上しました。開発者はまずos.FindProcess
やexec.Command.Start
などを使って*os.Process
インスタンスを取得し、そのインスタンスに対してWait()
メソッドを呼び出すという、よりオブジェクト指向的なアプローチが強制されます。
3. gofix
による移行支援:
このAPI変更は、既存のGoコードベースに影響を与える可能性があります。特に、os.Wait(0)
のようにオプション引数に0
を明示的に渡していたコードは、コンパイルエラーになるでしょう。この問題を緩和するために、src/cmd/fix/oswait.go
に新しいgofix
ルールが追加されました。
このgofix
ルールは、os.Wait(0)
というパターンを検出し、自動的にos.Wait()
に書き換えます。これは、0
が「特別なオプションなし」を意味するため、挙動を変えずにコードを更新できるからです。しかし、os.Wait(1)
やos.Wait(A | B)
のように0
以外のオプションが指定されていた場合は、gofix
は自動変換を行わず、開発者に手動での修正を促す警告を発します。これは、0
以外のオプションはOS固有の挙動に依存しており、単純な削除では意図しない挙動変更につながる可能性があるためです。開発者はこれらのケースで、Goの新しいプロセス管理API(例: os/exec
パッケージのより高レベルな機能)を検討するか、あるいは必要に応じてsyscall
パッケージを直接使用してOS固有の待機オプションを扱う必要があります。
これらの変更は、Go言語が初期段階から成熟期へと移行する過程で、APIの洗練とプラットフォーム間の統一性を追求した結果と言えます。
関連リンク
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
os/exec
パッケージドキュメント: https://pkg.go.dev/os/exec - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall - Go 1リリースノート (関連セクション): https://go.dev/doc/go1#os_process
参考にした情報源リンク
- Go言語における
os.Process.Wait()
の移植性の問題に関する議論: https://mezhenskyi.dev/posts/go-wait-for-non-child-process/ syscall.Wait4
のオプション(WNOHANG
,WSTOPPED
,WUNTRACED
)に関するLinuxマニュアルページ: https://man7.org/linux/man-pages/man2/wait4.2.html- Go言語の
gofix
ツールに関する情報: https://go.dev/blog/gofix - Go言語の
exec.Command.Wait()
とos.Process.Wait()
の違いに関するStack Overflowの議論: https://stackoverflow.com/questions/10385551/how-to-kill-a-process-by-pid-in-go - Go言語におけるプロセスグループ管理と子プロセスの終了に関する記事: https://hackernoon.com/how-to-gracefully-kill-child-processes-in-go-lang-with-process-groups-and-signals-763e174c4b4f