Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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.Processos.Process.Wait

Go言語のosパッケージは、オペレーティングシステムの機能へのプラットフォームに依存しないインターフェースを提供します。

  • os.Process: これは、実行中の(または終了した)外部プロセスを表す構造体です。通常、os.StartProcessos.FindProcessなどの関数によって取得されます。os.Processインスタンスは、プロセスのID(PID)などの情報を含みます。
  • os.Process.Wait(): このメソッドは、os.Processインスタンスが表すプロセスが終了するまで呼び出し元のゴルーチンをブロックし、そのプロセスの終了ステータスを*os.ProcessStateとして返します。また、このメソッドは、関連するオペレーティングシステムのリソースを解放します。

プロセスの終了待機とゾンビプロセス

Unix系システムでは、子プロセスが終了すると、その終了ステータスは親プロセスがwait系のシステムコールを呼び出すまでカーネルによって保持されます。この状態のプロセスはゾンビプロセスと呼ばれます。親プロセスがwaitを呼び出すことで、子プロスのリソースが完全に解放され、ゾンビプロセスは消滅します。もし親プロセスがwaitを呼び出さずに終了した場合、子プロセスは孤児プロセスとなり、initプロセス(PID 1)がその親となり、initwaitを呼び出してリソースを解放します。

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をより正確に理解できるようにするためのものです。

関連リンク

参考にした情報源リンク

  • 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.Processos.Process.Wait

Go言語のosパッケージは、オペレーティングシステムの機能へのプラットフォームに依存しないインターフェースを提供します。

  • os.Process: これは、実行中の(または終了した)外部プロセスを表す構造体です。通常、os.StartProcessos.FindProcessなどの関数によって取得されます。os.Processインスタンスは、プロセスのID(PID)などの情報を含みます。
  • os.Process.Wait(): このメソッドは、os.Processインスタンスが表すプロセスが終了するまで呼び出し元のゴルーチンをブロックし、そのプロセスの終了ステータスを*os.ProcessStateとして返します。また、このメソッドは、関連するオペレーティングシステムのリソースを解放します。

プロセスの終了待機とゾンビプロセス

Unix系システムでは、子プロセスが終了すると、その終了ステータスは親プロセスがwait系のシステムコールを呼び出すまでカーネルによって保持されます。この状態のプロセスはゾンビプロセスと呼ばれます。親プロセスがwaitを呼び出すことで、子プロスンのリソースが完全に解放され、ゾンビプロセスは消滅します。もし親プロセスがwaitを呼び出さずに終了した場合、子プロセスは孤児プロセスとなり、initプロセス(PID 1)がその親となり、initwaitを呼び出してリソースを解放します。

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をより正確に理解できるようにするためのものです。

関連リンク

参考にした情報源リンク

  • 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.