[インデックス 18810] ファイルの概要
このコミットは、Go言語のos
パッケージにおけるProcess.Wait
メソッドのドキュメントを更新し、このメソッドがほとんどのオペレーティングシステムにおいて子プロセスに対してのみ機能するという重要な制約を明記するものです。これにより、ユーザーがProcess.Wait
の挙動について誤解するのを防ぎ、非子プロセスに対してWait
を呼び出した際に発生しうるエラーについての理解を深めることを目的としています。
コミット
commit a35b9e496073682cefdc0a533217683204ecb667
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Fri Mar 7 14:44:31 2014 -0800
os: document that Process.Wait only works on child processes
Fixes #7072
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/71900045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a35b9e496073682cefdc0a533217683204ecb667
元コミット内容
os: document that Process.Wait only works on child processes
Fixes #7072
変更の背景
この変更の背景には、Go言語のos
パッケージのProcess.Wait
メソッドの挙動に関するユーザーの誤解や混乱があったと考えられます。Process.Wait
は、指定されたプロセスが終了するのを待機し、そのステータスを返すためのメソッドですが、オペレーティングシステムの設計上、親プロセスが子プロセスの終了を待機することは一般的であるものの、任意のリモートプロセスや、現在のプロセスが生成していないプロセス(非子プロセス)の終了を直接待機することは、通常は許可されていません。
Goのos
パッケージは、基盤となるオペレーティングシステムのプロセス管理APIを抽象化しています。多くのUnix系システムでは、waitpid
のようなシステムコールは、呼び出し元のプロセスの子プロセスに対してのみ機能します。Windowsのようなシステムでも、プロセスのハンドルを取得して待機することは可能ですが、そのプロセスが現在のプロセスの「子」であるという概念は、リソース管理やシグナル処理において重要です。
ユーザーがProcess.Wait
を、例えばos.FindProcess
で取得した任意のプロセスIDに対して使用しようとした際に、期待通りの動作をせずエラーが発生することがあったため、この制約を明示的にドキュメントに追記する必要が生じました。これにより、開発者がProcess.Wait
の正しい使用方法を理解し、不必要なデバッグ時間を削減できるようになります。
前提知識の解説
プロセスと子プロセス
オペレーティングシステムにおいて、プロセスとは実行中のプログラムのインスタンスです。各プロセスは、独自のメモリ空間、ファイルディスクリプタ、およびその他のリソースを持ちます。プロセスは、他のプロセスを生成することができます。このとき、生成元のプロセスを親プロセス、生成されたプロセスを子プロセスと呼びます。
プロセス間には階層関係が存在し、通常、子プロセスは親プロセスから一部のリソース(例えば、開いているファイルディスクリプタのコピー)を継承します。この親子関係は、プロセスのライフサイクル管理において重要です。
os.Process
とos.Process.Wait
Go言語のos
パッケージは、オペレーティングシステムの機能へのプラットフォームに依存しないインターフェースを提供します。
os.Process
: これは、実行中の(または終了した)外部プロセスを表す構造体です。通常、os.StartProcess
やos.FindProcess
などの関数によって取得されます。os.Process
インスタンスは、プロセスのID(PID)などの情報を含みます。os.Process.Wait()
: このメソッドは、os.Process
インスタンスが表すプロセスが終了するまで呼び出し元のゴルーチンをブロックし、そのプロセスの終了ステータスを*os.ProcessState
として返します。また、このメソッドは、関連するオペレーティングシステムのリソースを解放します。
プロセスの終了待機とゾンビプロセス
Unix系システムでは、子プロセスが終了すると、その終了ステータスは親プロセスがwait
系のシステムコールを呼び出すまでカーネルによって保持されます。この状態のプロセスはゾンビプロセスと呼ばれます。親プロセスがwait
を呼び出すことで、子プロスのリソースが完全に解放され、ゾンビプロセスは消滅します。もし親プロセスがwait
を呼び出さずに終了した場合、子プロセスは孤児プロセスとなり、init
プロセス(PID 1)がその親となり、init
がwait
を呼び出してリソースを解放します。
os.Process.Wait
は、このwait
システムコール(またはそれに相当するOSのAPI)をGoから呼び出すためのラッパーです。
技術的詳細
os.Process.Wait
が「ほとんどのオペレーティングシステムで子プロセスに対してのみ機能する」という制約は、オペレーティングシステムのプロセス管理の根本的な設計に起因します。
Unix系システムにおけるwaitpid
LinuxやmacOSなどのUnix系システムでは、プロセスが他のプロセスの終了を待機するためにwaitpid()
やwait()
といったシステムコールを使用します。これらのシステムコールは、通常、呼び出し元のプロセスが生成した子プロセスに対してのみ機能するように設計されています。
- セキュリティと分離: 任意のプロセスがシステム上の他の任意のプロセスの終了を待機できるとすると、セキュリティ上の問題や、プロセスのライフサイクル管理における混乱が生じる可能性があります。親プロセスと子プロセスの関係は、リソースの継承、シグナルの伝達、そして終了ステータスの収集といった、密接な連携を前提としています。
- リソース管理: カーネルは、子プロセスの終了ステータスを親プロセスが収集するまで保持します。これは、親プロセスが子プロセスの終了理由を把握し、適切に後処理を行うために必要です。非子プロセスに対して
wait
を許可すると、カーネルがどのプロセスの終了ステータスを誰のために保持すべきかという管理が複雑になります。
もしwaitpid
が非子プロセスに対して呼び出された場合、通常はECHILD
(No child processes)のようなエラーが返されます。
Windows系システムにおけるプロセスの待機
Windowsでは、プロセスはハンドルを介して他のプロセスを操作します。OpenProcess
関数でプロセスのハンドルを取得し、WaitForSingleObject
などの関数でそのプロセスの終了を待機することができます。Windowsのセキュリティモデルでは、適切なアクセス権があれば、任意のプロセスのハンドルを取得し、その終了を待機することは可能です。
しかし、Goのos
パッケージは、プラットフォーム間の差異を吸収し、共通のインターフェースを提供することを目指しています。Unix系システムのwaitpid
の制約がより厳しいため、GoのProcess.Wait
のドキュメントでは、より一般的な「ほとんどのオペレーティングシステムで」という表現を用いて、この制約を明記しています。これは、Windowsであっても、os.StartProcess
で生成されたプロセス(つまり子プロセス)に対してWait
を使用することが意図された主要なユースケースであることを示唆しています。os.FindProcess
で取得したプロセスIDが、現在のGoプログラムの子プロセスではない場合、Wait
を呼び出すと、プラットフォームによってはエラーになるか、期待通りの動作をしない可能性があります。
このドキュメントの追加は、Goのos
パッケージが提供する抽象化の背後にあるOSの挙動をユーザーに理解させることで、より堅牢なアプリケーションを開発できるようにするための重要な情報提供です。
コアとなるコードの変更箇所
変更はsrc/pkg/os/doc.go
ファイルに対して行われました。具体的には、Process.Wait
メソッドのドキュメントコメントに2行が追加されています。
--- a/src/pkg/os/doc.go
+++ b/src/pkg/os/doc.go
@@ -39,6 +39,8 @@ func (p *Process) Kill() error {
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
コアとなるコードの解説
追加された2行は以下の通りです。
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
このコメントは、Process.Wait
メソッドの既存のドキュメントに追記されました。
On most operating systems, the Process must be a child
: これは、Process.Wait
が機能するための前提条件として、待機対象のプロセスが現在のGoプログラム(プロセス)の子プロセスである必要があることを明確に述べています。「ほとんどのオペレーティングシステム」という表現は、Unix系システムにおけるwaitpid
の挙動を主に指していますが、Goのクロスプラットフォームな性質を考慮し、より一般的な表現が選ばれています。of the current process or an error will be returned.
: この部分は、もし待機対象のプロセスが現在のプロセスの子プロセスではない場合、Process.Wait
がエラーを返す可能性があることを警告しています。これにより、開発者は非子プロセスに対してWait
を呼び出すことの危険性を認識し、適切なエラーハンドリングを実装するか、そもそもそのような状況を避けるように設計を調整することができます。
この変更は、コードの動作自体を変更するものではなく、その動作に関するドキュメントを改善し、ユーザーがAPIをより正確に理解できるようにするためのものです。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/a35b9e496073682cefdc0a533217683204ecb667
- Go Issue #7072: https://github.com/golang/go/issues/7072 (このコミットが修正したイシュー)
- Go Code Review 71900045: https://golang.org/cl/71900045 (このコミットのコードレビューページ)
参考にした情報源リンク
- Go
os
package documentation: https://pkg.go.dev/os waitpid
man page (Unix/Linux): (Web検索で一般的なwaitpid
のmanページを参照)- Windows Process and Thread Functions: (Web検索で一般的なWindows APIのプロセス関連ドキュメントを参照)
- Stack Overflow discussions regarding
waitpid
and non-child processes.# [インデックス 18810] ファイルの概要
このコミットは、Go言語のos
パッケージにおけるProcess.Wait
メソッドのドキュメントを更新し、このメソッドがほとんどのオペレーティングシステムにおいて子プロセスに対してのみ機能するという重要な制約を明記するものです。これにより、ユーザーがProcess.Wait
の挙動について誤解するのを防ぎ、非子プロセスに対してWait
を呼び出した際に発生しうるエラーについての理解を深めることを目的としています。
コミット
commit a35b9e496073682cefdc0a533217683204ecb667
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Fri Mar 7 14:44:31 2014 -0800
os: document that Process.Wait only works on child processes
Fixes #7072
LGTM=iant
R=iant
CC=golang-codereviews
https://golang.org/cl/71900045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a35b9e496073682cefdc0a533217683204ecb667
元コミット内容
os: document that Process.Wait only works on child processes
Fixes #7072
変更の背景
この変更の背景には、Go言語のos
パッケージのProcess.Wait
メソッドの挙動に関するユーザーの誤解や混乱があったと考えられます。Process.Wait
は、指定されたプロセスが終了するのを待機し、そのステータスを返すためのメソッドですが、オペレーティングシステムの設計上、親プロセスが子プロセスの終了を待機することは一般的であるものの、任意のリモートプロセスや、現在のプロセスが生成していないプロセス(非子プロセス)の終了を直接待機することは、通常は許可されていません。
Goのos
パッケージは、基盤となるオペレーティングシステムのプロセス管理APIを抽象化しています。多くのUnix系システムでは、waitpid
のようなシステムコールは、呼び出し元のプロセスの子プロセスに対してのみ機能します。Windowsのようなシステムでも、プロセスのハンドルを取得して待機することは可能ですが、そのプロセスが現在のプロセスの「子」であるという概念は、リソース管理やシグナル処理において重要です。
ユーザーがProcess.Wait
を、例えばos.FindProcess
で取得した任意のプロセスIDに対して使用しようとした際に、期待通りの動作をせずエラーが発生することがあったため、この制約を明示的にドキュメントに追記する必要が生じました。これにより、開発者がProcess.Wait
の正しい使用方法を理解し、不必要なデバッグ時間を削減できるようになります。
前提知識の解説
プロセスと子プロセス
オペレーティングシステムにおいて、プロセスとは実行中のプログラムのインスタンスです。各プロセスは、独自のメモリ空間、ファイルディスクリプタ、およびその他のリソースを持ちます。プロセスは、他のプロセスを生成することができます。このとき、生成元のプロセスを親プロセス、生成されたプロセスを子プロセスと呼びます。
プロセス間には階層関係が存在し、通常、子プロセスは親プロセスから一部のリソース(例えば、開いているファイルディスクリプタのコピー)を継承します。この親子関係は、プロセスのライフサイクル管理において重要です。
os.Process
とos.Process.Wait
Go言語のos
パッケージは、オペレーティングシステムの機能へのプラットフォームに依存しないインターフェースを提供します。
os.Process
: これは、実行中の(または終了した)外部プロセスを表す構造体です。通常、os.StartProcess
やos.FindProcess
などの関数によって取得されます。os.Process
インスタンスは、プロセスのID(PID)などの情報を含みます。os.Process.Wait()
: このメソッドは、os.Process
インスタンスが表すプロセスが終了するまで呼び出し元のゴルーチンをブロックし、そのプロセスの終了ステータスを*os.ProcessState
として返します。また、このメソッドは、関連するオペレーティングシステムのリソースを解放します。
プロセスの終了待機とゾンビプロセス
Unix系システムでは、子プロセスが終了すると、その終了ステータスは親プロセスがwait
系のシステムコールを呼び出すまでカーネルによって保持されます。この状態のプロセスはゾンビプロセスと呼ばれます。親プロセスがwait
を呼び出すことで、子プロスンのリソースが完全に解放され、ゾンビプロセスは消滅します。もし親プロセスがwait
を呼び出さずに終了した場合、子プロセスは孤児プロセスとなり、init
プロセス(PID 1)がその親となり、init
がwait
を呼び出してリソースを解放します。
os.Process.Wait
は、このwait
システムコール(またはそれに相当するOSのAPI)をGoから呼び出すためのラッパーです。
技術的詳細
os.Process.Wait
が「ほとんどのオペレーティングシステムで子プロセスに対してのみ機能する」という制約は、オペレーティングシステムのプロセス管理の根本的な設計に起因します。
Unix系システムにおけるwaitpid
LinuxやmacOSなどのUnix系システムでは、プロセスが他のプロセスの終了を待機するためにwaitpid()
やwait()
といったシステムコールを使用します。これらのシステムコールは、通常、呼び出し元のプロセスが生成した子プロセスに対してのみ機能するように設計されています。
- セキュリティと分離: 任意のプロセスがシステム上の他の任意のプロセスの終了を待機できるとすると、セキュリティ上の問題や、プロセスのライフサイクル管理における混乱が生じる可能性があります。親プロセスと子プロセスの関係は、リソースの継承、シグナルの伝達、そして終了ステータスの収集といった、密接な連携を前提としています。
- リソース管理: カーネルは、子プロセスの終了ステータスを親プロセスが収集するまで保持します。これは、親プロセスが子プロセスの終了理由を把握し、適切に後処理を行うために必要です。非子プロセスに対して
wait
を許可すると、カーネルがどのプロセスの終了ステータスを誰のために保持すべきかという管理が複雑になります。
もしwaitpid
が非子プロセスに対して呼び出された場合、通常はECHILD
(No child processes)のようなエラーが返されます。
Windows系システムにおけるプロセスの待機
Windowsでは、プロセスはハンドルを介して他のプロセスを操作します。OpenProcess
関数でプロセスのハンドルを取得し、WaitForSingleObject
などの関数でそのプロセスの終了を待機することができます。Windowsのセキュリティモデルでは、適切なアクセス権があれば、任意のプロセスのハンドルを取得し、その終了を待機することは可能です。
しかし、Goのos
パッケージは、プラットフォーム間の差異を吸収し、共通のインターフェースを提供することを目指しています。Unix系システムのwaitpid
の制約がより厳しいため、GoのProcess.Wait
のドキュメントでは、より一般的な「ほとんどのオペレーティングシステムで」という表現を用いて、この制約を明記しています。これは、Windowsであっても、os.StartProcess
で生成されたプロセス(つまり子プロセス)に対してWait
を使用することが意図された主要なユースケースであることを示唆しています。os.FindProcess
で取得したプロセスIDが、現在のGoプログラムの子プロセスではない場合、Wait
を呼び出すと、プラットフォームによってはエラーになるか、期待通りの動作をしない可能性があります。
このドキュメントの追加は、Goのos
パッケージが提供する抽象化の背後にあるOSの挙動をユーザーに理解させることで、より堅牢なアプリケーションを開発できるようにするための重要な情報提供です。
コアとなるコードの変更箇所
変更はsrc/pkg/os/doc.go
ファイルに対して行われました。具体的には、Process.Wait
メソッドのドキュメントコメントに2行が追加されています。
--- a/src/pkg/os/doc.go
+++ b/src/pkg/os/doc.go
@@ -39,6 +39,8 @@ func (p *Process) Kill() error {
// Wait waits for the Process to exit, and then returns a
// ProcessState describing its status and an error, if any.
// Wait releases any resources associated with the Process.
+// On most operating systems, the Process must be a child
+// of the current process or an error will be returned.
func (p *Process) Wait() (*ProcessState, error) {
return p.wait()
}
コアとなるコードの解説
追加された2行は以下の通りです。
// On most operating systems, the Process must be a child
// of the current process or an error will be returned.
このコメントは、Process.Wait
メソッドの既存のドキュメントに追記されました。
On most operating systems, the Process must be a child
: これは、Process.Wait
が機能するための前提条件として、待機対象のプロセスが現在のGoプログラム(プロセス)の子プロセスである必要があることを明確に述べています。「ほとんどのオペレーティングシステム」という表現は、Unix系システムにおけるwaitpid
の挙動を主に指していますが、Goのクロスプラットフォームな性質を考慮し、より一般的な表現が選ばれています。of the current process or an error will be returned.
: この部分は、もし待機対象のプロセスが現在のプロセスの子プロセスではない場合、Process.Wait
がエラーを返す可能性があることを警告しています。これにより、開発者は非子プロセスに対してWait
を呼び出すことの危険性を認識し、適切なエラーハンドリングを実装するか、そもそもそのような状況を避けるように設計を調整することができます。
この変更は、コードの動作自体を変更するものではなく、その動作に関するドキュメントを改善し、ユーザーがAPIをより正確に理解できるようにするためのものです。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/a35b9e496073682cefdc0a533217683204ecb667
- Go Issue #7072: https://github.com/golang/go/issues/7072 (このコミットが修正したイシュー)
- Go Code Review 71900045: https://golang.org/cl/71900045 (このコミットのコードレビューページ)
参考にした情報源リンク
- Go
os
package documentation: https://pkg.go.dev/os waitpid
man page (Unix/Linux): (Web検索で一般的なwaitpid
のmanページを参照)- Windows Process and Thread Functions: (Web検索で一般的なWindows APIのプロセス関連ドキュメントを参照)
- Stack Overflow discussions regarding
waitpid
and non-child processes.