[インデックス 12094] ファイルの概要
このコミットは、Go言語のos
パッケージにおけるプロセス状態の報告メカニズムを、非ポータブルなWaitmsg
から、よりポータブルで統一されたProcessState
に置き換えるものです。これにより、異なるオペレーティングシステム間でのプロセス管理の一貫性が向上し、プロセスの終了ステータス、CPU時間、リソース使用量などの情報へのアクセスが標準化されます。
コミット
os
パッケージにおいて、プロセスの終了情報を扱うWaitmsg
型を、よりポータブルなProcessState
型に置き換える変更です。これにより、主要な情報へのアクセスはメソッドを通じて行われ、非ポータブルな部分はポータブルなメソッドを通じて提供されます。WindowsおよびPlan 9向けのコードも更新されています。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ccacab641af54f51bdca228445f464efde47e935
元コミット内容
commit ccacab641af54f51bdca228445f464efde47e935
Author: Rob Pike <r@golang.org>
Date: Tue Feb 21 14:10:34 2012 +1100
os: replace non-portable Waitmsg with portable ProcessState
Use methods for key questions.
Provide access to non-portable pieces through portable methods.
Windows and Plan 9 updated.
R=golang-dev, bradfitz, bradfitz, r, dsymonds, rsc, iant, iant
CC=golang-dev
https://golang.org/cl/5673077
変更の背景
Go言語の初期のバージョンでは、プロセスの終了情報を取得するためにos.Waitmsg
という型が使用されていました。しかし、このWaitmsg
はプラットフォームに依存する部分が多く、特にUnix系のシステムで使われるsyscall.WaitStatus
を直接ラップする形であったため、WindowsやPlan 9といった異なるOSでの互換性に課題がありました。
Go 1のリリースに向けて、標準ライブラリのポータビリティと一貫性を高めることが重要な目標とされました。プロセス管理においても、各OSのシステムコールに直接依存するのではなく、より抽象化された共通のインターフェースを提供することで、開発者がプラットフォームの違いを意識せずにコードを書けるようにする必要がありました。
このコミットは、その目標を達成するための一環として、os.Waitmsg
をos.ProcessState
に置き換えるものです。ProcessState
は、プロセスの終了ステータス、CPU時間、リソース使用量などの情報を、OSに依存しない形で提供するための新しい抽象化レイヤーとして導入されました。これにより、Goプログラムが異なるOS上でより予測可能かつ一貫した動作をするようになります。
前提知識の解説
- プロセス (Process): 実行中のプログラムのインスタンスです。各プロセスは独自のメモリ空間、ファイルディスクリプタ、実行コンテキストを持ちます。Go言語の
os
パッケージは、プロセスの生成、管理、終了の待機などの機能を提供します。 os.Process
: Go言語で実行中のプロセスを表す型です。この型を通じて、プロセスのPID(プロセスID)を取得したり、プロセスにシグナルを送ったり、プロセスの終了を待機したりすることができます。os.Process.Wait()
:os.Process
型のメソッドで、対象のプロセスが終了するまで待機し、その終了に関する情報を返します。このコミット以前はos.Waitmsg
を返していましたが、コミット後は*os.ProcessState
を返します。- 終了ステータス (Exit Status): プロセスが終了する際に、その成否を示すために返す整数値です。慣例として、0は成功、0以外の値はエラーを示します。
- シグナル (Signal): オペレーティングシステムがプロセスに送信する非同期通知です。例えば、
SIGTERM
はプロセスに終了を要求し、SIGKILL
はプロセスを強制終了させます。 - リソース使用量 (Resource Usage): プロセスが実行中に消費したCPU時間(ユーザー時間、システム時間)、メモリ、I/Oなどのシステムリソースの量です。Unix系システムでは
rusage
構造体で表現されることが多いです。 syscall.WaitStatus
(Unix/POSIX): Unix系システムでwaitpid
などのシステムコールが返す、プロセスの終了ステータスに関する詳細情報を含む型です。プロセスが正常終了したか、シグナルによって終了したか、停止したかなどの情報が含まれます。syscall.Waitmsg
(Plan 9): Plan 9オペレーティングシステムにおけるプロセスの終了情報を表す型です。- ポータビリティ (Portability): ソフトウェアが異なる環境(OS、ハードウェアアーキテクチャなど)で変更なしに、または最小限の変更で動作する能力を指します。
技術的詳細
このコミットの核心は、プロセスの終了情報を扱うための抽象化レイヤーをos.Waitmsg
からos.ProcessState
へと変更した点にあります。
os.Waitmsg
の問題点:
従来のos.Waitmsg
は、Unix系システムではsyscall.WaitStatus
を、Plan 9ではsyscall.Waitmsg
を直接ラップする形でした。これは、各OSのシステムコールが返す生の情報に近いため、プラットフォーム間でインターフェースが異なり、コードのポータビリティを損ねていました。例えば、UnixのWaitStatus
にはシグナル情報やコアダンプの有無が含まれますが、Plan 9のWaitmsg
は異なる構造をしていました。
os.ProcessState
の導入:
os.ProcessState
は、これらのプラットフォーム固有の差異を吸収し、統一されたインターフェースを提供する新しい型として設計されました。
ProcessState
は以下の主要なメソッドを提供します。
Pid() int
: 終了したプロセスのプロセスIDを返します。Exited() bool
: プログラムが正常に終了したかどうかを報告します。Success() bool
: プログラムが成功裏に終了したかどうか(Unix系では終了ステータス0)を報告します。Sys() interface{}
: システム依存の終了情報を返します。これはinterface{}
型であるため、呼び出し側は適切な型アサーション(例:*syscall.WaitStatus
や*syscall.Waitmsg
)を行うことで、基盤となるOS固有の情報にアクセスできます。SysUsage() interface{}
: システム依存のリソース使用量情報を返します。これもinterface{}
型であり、*syscall.Rusage
などの型アサーションが必要です。UserTime() time.Duration
: 終了したプロセスとその子プロセスのユーザーCPU時間を返します。SystemTime() time.Duration
: 終了したプロセスとその子プロセスのシステムCPU時間を返します。
これらのメソッドにより、開発者はOSの違いを意識することなく、プロセスの終了情報を取得できるようになります。必要に応じて、Sys()
やSysUsage()
を通じて低レベルのOS固有の情報にアクセスすることも可能です。
プラットフォームごとの実装:
exec_plan9.go
: Plan 9では、syscall.Waitmsg
をProcessState
の内部フィールドstatus
として保持し、Pid()
、Exited()
、Success()
などのメソッドがこのstatus
フィールドを利用して情報を提供します。UserTime()
とSystemTime()
はsyscall.Waitmsg
のTime
フィールドからミリ秒単位で取得します。exec_posix.go
: POSIX準拠のシステム(Unix系)では、syscall.WaitStatus
をProcessState
の内部フィールドstatus
としてポインタで保持し、syscall.Rusage
をrusage
フィールドとして保持します。Pid()
、Exited()
、Success()
などのメソッドはstatus
フィールドを利用します。UserTime()
とSystemTime()
はsyscall.Rusage
からナノ秒単位で取得します。exec_unix.go
:exec_posix.go
と同様に、syscall.Wait4
システムコールを使用してsyscall.WaitStatus
とsyscall.Rusage
を取得し、これらをProcessState
に格納します。exec_windows.go
: Windowsでは、syscall.WaitForSingleObject
とGetExitCodeProcess
を使用してプロセスの終了を待機し、終了コードを取得します。UserTime()
とSystemTime()
はWindowsでは常に0を返します(当時の実装ではCPU時間のリソース使用量取得がサポートされていなかったため)。
このように、ProcessState
は各OSの特性に合わせて内部実装を切り替えつつ、外部には統一されたインターフェースを提供するという、Go言語のポータビリティ戦略を体現しています。
コアとなるコードの変更箇所
このコミットでは、主に以下のファイルが変更されています。
src/cmd/cgo/util.go
:p.Wait()
の戻り値がw, err := p.Wait()
からstate, err := p.Wait()
に変更され、w.Exited() && w.ExitStatus() == 0
がstate.Success()
に置き換えられています。
src/cmd/godoc/main.go
:wait.ExitStatus()
やwait.Exited()
の代わりにwait.Success()
が使用されるよう変更されています。- コメントで
Wait
がブール値の終了条件を持つようになったことが言及されています。
src/pkg/os/exec/exec.go
:Cmd
構造体のWaitmsg
フィールドがProcessState
フィールドに変更されています。ExitError
構造体が*os.Waitmsg
を埋め込む形から*os.ProcessState
を埋め込む形に変更されています。Cmd.Wait()
メソッド内でc.Process.Wait()
の戻り値がmsg
からstate
に変更され、c.Waitmsg = msg
がc.ProcessState = state
に、!msg.Exited() || msg.ExitStatus() != 0
が!state.Success()
に、&ExitError{msg}
が&ExitError{state}
にそれぞれ変更されています。
src/pkg/os/exec_plan9.go
:Waitmsg
型が削除され、ProcessState
型が新しく定義されています。ProcessState
型にはpid
、status
(syscall.Waitmsg
型)フィールドが含まれ、Pid()
、Exited()
、Success()
、Sys()
、SysUsage()
、UserTime()
、SystemTime()
、String()
メソッドが実装されています。Process.Wait()
の戻り値が*Waitmsg
から*ProcessState
に変更され、ProcessState
のインスタンスを生成して返すように修正されています。
src/pkg/os/exec_posix.go
:Waitmsg
型が削除され、ProcessState
型が新しく定義されています。ProcessState
型にはpid
、status
(*syscall.WaitStatus
型)、rusage
(*syscall.Rusage
型)フィールドが含まれ、Pid()
、Exited()
、Success()
、Sys()
、SysUsage()
メソッドが実装されています。ProcessState.String()
メソッドが、WaitStatus
の情報を利用してより詳細な終了理由を文字列で返すように変更されています。
src/pkg/os/exec_unix.go
:Process.Wait()
の戻り値が*Waitmsg
から*ProcessState
に変更され、syscall.Wait4
で取得したsyscall.WaitStatus
とsyscall.Rusage
を基にProcessState
のインスタンスを生成して返すように修正されています。ProcessState
にUserTime()
とSystemTime()
メソッドが追加され、rusage
からCPU時間を取得するように実装されています。
src/pkg/os/exec_windows.go
:Process.Wait()
の戻り値が*Waitmsg
から*ProcessState
に変更され、ProcessState
のインスタンスを生成して返すように修正されています。ProcessState
にUserTime()
とSystemTime()
メソッドが追加されていますが、Windowsでは常に0を返すように実装されています。
src/pkg/os/os_test.go
:TestNilWaitmsgString
テストがTestNilProcessStateString
にリネームされ、*Waitmsg
の代わりに*ProcessState
のString()
メソッドのテストを行うように修正されています。
コアとなるコードの解説
-
src/cmd/cgo/util.go
とsrc/cmd/godoc/main.go
の変更: これらのファイルは、os.Process.Wait()
の呼び出し元であり、Waitmsg
の代わりにProcessState
を使用するように更新されています。特に注目すべきは、w.Exited() && w.ExitStatus() == 0
のような複数の条件チェックが、新しいstate.Success()
という単一のメソッド呼び出しに置き換えられている点です。これは、ProcessState
が提供する高レベルな抽象化と、より意図が明確なAPI設計の恩恵を示しています。 -
src/pkg/os/exec/exec.go
の変更: このファイルは、os/exec
パッケージの主要なロジックを含んでいます。Cmd
構造体内のWaitmsg
フィールドがProcessState
に置き換えられたことで、exec
パッケージ全体が新しいProcessState
の抽象化を利用するようになります。ExitError
も同様にProcessState
をラップすることで、エラー報告の一貫性が保たれます。Cmd.Wait()
メソッドは、os.Process.Wait()
から返されるProcessState
を受け取り、それをCmd
構造体のフィールドに格納し、必要に応じてExitError
を生成します。これにより、exec
パッケージのユーザーは、プロセスの終了情報をProcessState
を通じて取得できるようになります。 -
src/pkg/os/exec_plan9.go
,src/pkg/os/exec_posix.go
,src/pkg/os/exec_unix.go
,src/pkg/os/exec_windows.go
の変更: これらのファイルは、各オペレーティングシステムに特化したos.Process.Wait()
の実装を含んでいます。- 各ファイルで、従来の
Waitmsg
型が削除され、新しいProcessState
型が定義されています。このProcessState
型は、各OSのシステムコール(例: Unix/POSIXのsyscall.Wait4
、Plan 9のsyscall.Waitmsg
、Windowsのsyscall.WaitForSingleObject
)から取得した生の情報(syscall.WaitStatus
やsyscall.Rusage
など)を内部に保持します。 ProcessState
型には、Pid()
、Exited()
、Success()
、Sys()
、SysUsage()
、UserTime()
、SystemTime()
、String()
といった、OSに依存しない共通のメソッドが実装されています。これらのメソッドは、内部に保持するOS固有の情報を適切に解釈し、共通の形式で返します。- 例えば、Unix/POSIXでは
UserTime()
とSystemTime()
がsyscall.Rusage
から正確なCPU時間を取得するのに対し、Windowsでは当時の実装の制約から0を返すように実装されています。これは、ProcessState
が提供するポータブルなインターフェースの下で、各OSの機能の差異を吸収している典型的な例です。 Process.Wait()
メソッドは、各OSのシステムコールを呼び出してプロセスの終了情報を取得し、その情報を基にProcessState
のインスタンスを構築して返します。
- 各ファイルで、従来の
これらの変更により、Goのos
パッケージは、プロセスの終了情報を扱うための堅牢でポータブルなメカニズムを提供できるようになりました。