[インデックス 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パッケージは、プロセスの終了情報を扱うための堅牢でポータブルなメカニズムを提供できるようになりました。