[インデックス 18848] ファイルの概要
コミット
このコミットは、Go言語のos
パッケージにおけるPlan 9オペレーティングシステム上でのプロセス終了方法の変更に関するものです。具体的には、プロセスを強制終了させる従来の「kill」コマンドの使用を廃止し、代わりに「note」と呼ばれるメッセージングメカニズムを利用して、プロセスがより優雅に終了できるように修正されています。これにより、特にGoプログラムがPlan 9上で実行される際に、ランタイムがクリーンアップ処理を実行する機会が与えられ、リソースリークや予期せぬ動作を防ぐことが期待されます。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/189397df5855a35cd23c76becf5cd16b10bb4dce
元コミット内容
os: relax the way we kill processes on Plan 9
Previously, we wrote "kill" to the process control file
to kill a program. This is problematic because it doesn't
let the program gracefully exit.
This matters especially if the process we're killing is a
Go program. On Unix, sending SIGKILL to a Go program will
automatically kill all runtime threads. On Plan 9, there
are no threads so when the program wants to exit it has to
somehow signal all of the runtime processes. It can't do
this if we mercilessly kill it by writing to it's control
file.
Instead, we now send it a note to invoke it's note handler
and let it perform any cleanup before exiting.
LGTM=rsc
R=rsc, 0intro
CC=golang-codereviews
https://golang.org/cl/74440044
変更の背景
この変更の背景には、Plan 9オペレーティングシステムにおけるプロセスの終了メカニズムと、Goランタイムの特性が深く関わっています。
従来のGoのos
パッケージでは、Plan 9上でプロセスを終了させる際に、/proc/$pid/ctl
というプロセス制御ファイルに直接「kill」という文字列を書き込む方法が採用されていました。この方法は、Unix系システムにおけるSIGKILL
シグナルに相当する、非常に強制的な終了方法です。
しかし、この強制終了にはいくつかの問題がありました。
- グレースフルシャットダウンの阻害: プロセスが「kill」コマンドによって強制終了されると、そのプロセスは自身の終了処理(リソースの解放、ファイルのクローズ、データの永続化など)を行う機会を失います。これにより、データ破損、リソースリーク、または予期せぬ状態に陥る可能性がありました。
- Goランタイムの特殊性: 特にGoプログラムの場合、この問題は顕著でした。Unix系システムでは、
SIGKILL
がGoプログラムに送信されると、Goランタイムは自動的に関連するすべてのランタイムスレッドを終了させます。しかし、Plan 9にはUnixのような「スレッド」の概念がありません。代わりに、Goランタイムは複数の「プロセス」(Plan 9の軽量プロセス)を使用して並行処理を実現しています。プログラムが終了する際には、これらのランタイムプロセスすべてに終了を通知し、適切なクリーンアップを行う必要があります。強制的な「kill」では、この通知とクリーンアップのメカニズムが機能せず、ランタイムが正常に終了できないという問題がありました。 - Plan 9の「note」メカニズムの活用: Plan 9には、プロセスに対して非同期にメッセージを送信するための「note」というメカニズムが存在します。これはUnixのシグナルに似ていますが、より柔軟なハンドリングが可能です。プロセスはnoteを受け取ると、登録されたnoteハンドラを実行し、カスタムの終了処理を行うことができます。従来の「kill」コマンドはnoteメカニズムを迂回していたため、このPlan 9の設計思想に反していました。
これらの問題に対処するため、GoランタイムはPlan 9の「note」メカニズムを利用してプロセスを終了させるように変更されました。これにより、GoプログラムがPlan 9上でより堅牢かつ予測可能な方法で終了できるようになります。
前提知識の解説
このコミットを理解するためには、以下の概念について理解しておく必要があります。
1. Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、Unixの多くの概念を洗練させ、新しいアプローチを導入しています。
- すべてがファイル: Plan 9の最も重要な設計原則の一つは、「すべてがファイルである」というものです。デバイス、プロセス、ネットワーク接続など、システム内のあらゆるリソースがファイルシステム上のファイルとして表現されます。これにより、標準的なファイル操作(読み書き、オープン、クローズなど)を通じて、これらのリソースを操作できます。
- 名前空間: 各プロセスは独自の「名前空間」を持ち、これはファイルシステムのビューです。プロセスは、他のプロセスの名前空間をマウントしたり、自身のリソースを他のプロセスにエクスポートしたりできます。
- 軽量プロセス(Threads/Processes): Plan 9にはUnixのような重いプロセスと軽量なスレッドという厳密な区別がありません。代わりに、すべての実行単位は「プロセス」として扱われますが、これらは非常に軽量であり、Unixのスレッドに近い感覚で利用されます。GoランタイムがPlan 9上で並行処理を実現する際も、これらの軽量プロセスを利用します。
/proc
ファイルシステム: Plan 9にもUnixと同様に/proc
ファイルシステムが存在しますが、その構造と機能は異なります。各プロセスは/proc/$pid
というディレクトリを持ち、その中にプロセスの状態や制御に関するファイルが含まれます。
2. Plan 9におけるプロセス制御ファイル
Plan 9の/proc/$pid
ディレクトリ内には、プロセスの制御や情報取得のための特別なファイルが存在します。
/proc/$pid/ctl
: このファイルはプロセスの制御に使用されます。特定のコマンド(例:kill
、stop
、start
など)を書き込むことで、プロセスの状態を操作できます。従来のGoのos
パッケージでは、ここに「kill」を書き込むことでプロセスを強制終了していました。/proc/$pid/note
: このファイルは、プロセスに「note」(通知)を送信するために使用されます。noteは、Unixのシグナルに似ていますが、より柔軟な文字列ベースのメッセージを送信できます。プロセスはnoteを受け取ると、事前に登録されたnoteハンドラを実行できます。これにより、プロセスはnoteの内容に応じてカスタムのクリーンアップや終了処理を行うことが可能です。
3. UnixにおけるシグナルとSIGKILL
Unix系システムでは、プロセス間通信やイベント通知のために「シグナル」が使用されます。
- シグナル: プロセスに非同期にイベントを通知するメカニズムです。例えば、
SIGINT
(Ctrl+C)、SIGTERM
(終了要求)、SIGKILL
(強制終了)などがあります。 SIGKILL
: これは特別なシグナルで、プロセスはこれを捕捉したり無視したりすることはできません。SIGKILL
を受け取ったプロセスは、即座にカーネルによって終了させられます。これにより、プロセスはクリーンアップ処理を行う機会がありません。Goランタイムは、Unix上でSIGKILL
を受け取ると、関連するすべてのゴルーチンやスレッドを強制的に終了させるように設計されています。
4. Goランタイムのプロセス終了処理
Goプログラムは、その実行を管理する「ランタイム」を持っています。ランタイムは、ゴルーチンのスケジューリング、ガベージコレクション、メモリ管理、システムコールとのインターフェースなどを担当します。
- グレースフルシャットダウン: Goプログラムが正常に終了する場合、ランタイムは開いているファイルやネットワーク接続を閉じ、バッファをフラッシュし、その他のリソースを解放するなど、適切なクリーンアップ処理を行います。
- 強制終了時の挙動: Unix系システムでは、
SIGKILL
のような強制終了シグナルが送信されると、ランタイムはクリーンアップを行うことなく即座に終了させられます。しかし、Plan 9では、Goランタイムが複数の軽量プロセスで構成されているため、これらのプロセスすべてに終了を通知し、協調して終了する必要があります。強制的な/proc/$pid/ctl
への「kill」書き込みでは、この協調的な終了が不可能でした。
このコミットは、Plan 9のnote
メカニズムを活用することで、GoランタイムがPlan 9上でもグレースフルシャットダウンに近い形で終了処理を行えるようにするための重要な改善です。
技術的詳細
このコミットの技術的な核心は、Goのos
パッケージがPlan 9上でプロセスを終了させる際の内部実装の変更にあります。
従来のos
パッケージのProcess.signal
メソッド(Plan 9固有の実装であるexec_plan9.go
内)では、Kill
シグナル(Goのos
パッケージで定義されている抽象的なシグナル)が渡された場合に、特別な処理を行っていました。具体的には、p.Kill()
メソッドを呼び出し、その中で/proc/$pid/ctl
ファイルに「kill」という文字列を書き込むことで、プロセスを強制終了させていました。これは、UnixのSIGKILL
に相当する、プロセスが一切のクリーンアップを行う機会を与えずに即座に終了させる方法でした。
しかし、この変更により、Process.signal
メソッドからKill
シグナルに対する特別な処理が削除されました。その代わりに、Kill
シグナルも他のシグナルと同様に、p.writeProcFile("note", sig.String())
という呼び出しを通じて、/proc/$pid/note
ファイルに書き込まれるようになりました。
-
変更前:
Process.signal(Kill)
が呼ばれると、p.Kill()
が呼ばれる。p.Kill()
は/proc/$pid/ctl
に「kill」を書き込む。- これはプロセスを即座に、かつ強制的に終了させる。
-
変更後:
Process.signal(Kill)
が呼ばれると、他のシグナルと同様に処理される。p.writeProcFile("note", sig.String())
が呼ばれ、/proc/$pid/note
にKill
シグナルの文字列表現(例: "kill")が書き込まれる。- これにより、ターゲットプロセスはnoteを受け取り、そのnoteハンドラが起動される。Goランタイムは、このnoteハンドラ内で適切な終了処理(例えば、他のランタイムプロセスへの終了通知やリソースの解放)を実行できるようになる。
また、Process.kill()
メソッドも変更されました。変更前は、このメソッド内で直接/proc/$pid/ctl
に「kill」を書き込んでいましたが、変更後は単にp.signal(Kill)
を呼び出すように修正されました。これにより、Process.kill()
もnoteメカニズムを利用するようになり、一貫性が保たれます。
この変更は、Plan 9の設計思想である「note」メカニズムを尊重し、GoランタイムがPlan 9上でより協調的かつグレースフルに終了できるようにするための重要なステップです。これにより、Goプログラムの堅牢性と信頼性が向上します。
コアとなるコードの変更箇所
変更はsrc/pkg/os/exec_plan9.go
ファイルに集中しています。
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -52,10 +52,6 @@ func (p *Process) signal(sig Signal) error {
if p.done() {
return errors.New("os: process already finished")
}
- if sig == Kill {
- // Special-case the kill signal since it doesn't use /proc/$pid/note.
- return p.Kill()
- }
if e := p.writeProcFile("note", sig.String()); e != nil {
return NewSyscallError("signal", e)
}
@@ -63,10 +59,7 @@ func (p *Process) signal(sig Signal) error {
}
func (p *Process) kill() error {
- if e := p.writeProcFile("ctl", "kill"); e != nil {
- return NewSyscallError("kill", e)
- }
- return nil
+ return p.signal(Kill)
}
func (p *Process) wait() (ps *ProcessState, err error) {
コアとなるコードの解説
func (p *Process) signal(sig Signal) error
このメソッドは、特定のシグナルをプロセスに送信する役割を担っています。
-
変更前:
if sig == Kill { // Special-case the kill signal since it doesn't use /proc/$pid/note. return p.Kill() }
Kill
シグナルが渡された場合、このif
ブロックが実行され、p.Kill()
メソッドが呼び出されていました。コメントにあるように、これは/proc/$pid/note
を使用しない特別なケースとして扱われていました。つまり、Kill
シグナルはnoteメカニズムを介さずに、直接/proc/$pid/ctl
に「kill」を書き込むことで処理されていました。 -
変更後: 上記の
if
ブロックが完全に削除されました。これにより、Kill
シグナルも他のすべてのシグナルと同様に、以下の行で処理されるようになりました。if e := p.writeProcFile("note", sig.String()); e != nil { return NewSyscallError("signal", e) }
この行は、プロセスの
/proc/$pid/note
ファイルに、渡されたシグナル(sig
)の文字列表現を書き込みます。これにより、ターゲットプロセスはnoteを受け取り、そのnoteハンドラが起動されることになります。
func (p *Process) kill() error
このメソッドは、プロセスを終了させるための高レベルなインターフェースを提供します。
-
変更前:
if e := p.writeProcFile("ctl", "kill"); e != nil { return NewSyscallError("kill", e) } return nil
このメソッドは、直接
/proc/$pid/ctl
ファイルに「kill」という文字列を書き込むことで、プロセスを強制終了させていました。これは、Process.signal
メソッド内のKill
シグナルに対する特殊処理と同じメカニズムを使用していました。 -
変更後:
return p.signal(Kill)
このメソッドは、単に
p.signal(Kill)
を呼び出すように変更されました。これにより、Process.kill()
の呼び出しも、Process.signal
メソッドの新しいロジック(noteメカニズムを使用する)に従うようになります。この変更により、コードの重複が排除され、プロセス終了処理の一貫性が向上しました。
これらの変更により、Goのos
パッケージはPlan 9上でプロセスを終了させる際に、より協調的でグレースフルな方法を採用するようになりました。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/
- このコミットのGerritチェンジリスト: https://golang.org/cl/74440044
参考にした情報源リンク
- Plan 9: The
/proc
File System: https://9p.io/magic/man2html/2/proc - Plan 9:
note
andnotify
: https://9p.io/magic/man2html/2/note - Unix
kill
command and signals: https://man7.org/linux/man-pages/man1/kill.1.html - Go
os
package documentation: https://pkg.go.dev/os - Go
syscall
package documentation (forNewSyscallError
): https://pkg.go.dev/syscall - Go
errors
package documentation: https://pkg.go.dev/errors - Go runtime source code (for understanding how Go handles signals and process termination on different OSes): https://github.com/golang/go/tree/master/src/runtime
- Stack Overflow and other technical forums for discussions on Plan 9 process management and Go runtime specifics.```markdown
[インデックス 18848] ファイルの概要
コミット
このコミットは、Go言語のos
パッケージにおけるPlan 9オペレーティングシステム上でのプロセス終了方法の変更に関するものです。具体的には、プロセスを強制終了させる従来の「kill」コマンドの使用を廃止し、代わりに「note」と呼ばれるメッセージングメカニズムを利用して、プロセスがより優雅に終了できるように修正されています。これにより、特にGoプログラムがPlan 9上で実行される際に、ランタイムがクリーンアップ処理を実行する機会が与えられ、リソースリークや予期せぬ動作を防ぐことが期待されます。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/189397df5855a35cd23c76becf5cd16b10bb4dce
元コミット内容
os: relax the way we kill processes on Plan 9
Previously, we wrote "kill" to the process control file
to kill a program. This is problematic because it doesn't
let the program gracefully exit.
This matters especially if the process we're killing is a
Go program. On Unix, sending SIGKILL to a Go program will
automatically kill all runtime threads. On Plan 9, there
are no threads so when the program wants to exit it has to
somehow signal all of the runtime processes. It can't do
this if we mercilessly kill it by writing to it's control
file.
Instead, we now send it a note to invoke it's note handler
and let it perform any cleanup before exiting.
LGTM=rsc
R=rsc, 0intro
CC=golang-codereviews
https://golang.org/cl/74440044
変更の背景
この変更の背景には、Plan 9オペレーティングシステムにおけるプロセスの終了メカニズムと、Goランタイムの特性が深く関わっています。
従来のGoのos
パッケージでは、Plan 9上でプロセスを終了させる際に、/proc/$pid/ctl
というプロセス制御ファイルに直接「kill」という文字列を書き込む方法が採用されていました。この方法は、Unix系システムにおけるSIGKILL
シグナルに相当する、非常に強制的な終了方法です。
しかし、この強制終了にはいくつかの問題がありました。
- グレースフルシャットダウンの阻害: プロセスが「kill」コマンドによって強制終了されると、そのプロセスは自身の終了処理(リソースの解放、ファイルのクローズ、データの永続化など)を行う機会を失います。これにより、データ破損、リソースリーク、または予期せぬ状態に陥る可能性がありました。
- Goランタイムの特殊性: 特にGoプログラムの場合、この問題は顕著でした。Unix系システムでは、
SIGKILL
がGoプログラムに送信されると、Goランタイムは自動的に関連するすべてのランタイムスレッドを終了させます。しかし、Plan 9にはUnixのような「スレッド」の概念がありません。代わりに、Goランタイムは複数の「プロセス」(Plan 9の軽量プロセス)を使用して並行処理を実現しています。プログラムが終了する際には、これらのランタイムプロセスすべてに終了を通知し、適切なクリーンアップを行う必要があります。強制的な「kill」では、この通知とクリーンアップのメカニズムが機能せず、ランタイムが正常に終了できないという問題がありました。 - Plan 9の「note」メカニズムの活用: Plan 9には、プロセスに対して非同期にメッセージを送信するための「note」というメカニズムが存在します。これはUnixのシグナルに似ていますが、より柔軟なハンドリングが可能です。プロセスはnoteを受け取ると、登録されたnoteハンドラを実行し、カスタムの終了処理を行うことができます。従来の「kill」コマンドはnoteメカニズムを迂回していたため、このPlan 9の設計思想に反していました。
これらの問題に対処するため、GoランタイムはPlan 9の「note」メカニズムを利用してプロセスを終了させるように変更されました。これにより、GoプログラムがPlan 9上でより堅牢かつ予測可能な方法で終了できるようになります。
前提知識の解説
このコミットを理解するためには、以下の概念について理解しておく必要があります。
1. Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、Unixの多くの概念を洗練させ、新しいアプローチを導入しています。
- すべてがファイル: Plan 9の最も重要な設計原則の一つは、「すべてがファイルである」というものです。デバイス、プロセス、ネットワーク接続など、システム内のあらゆるリソースがファイルシステム上のファイルとして表現されます。これにより、標準的なファイル操作(読み書き、オープン、クローズなど)を通じて、これらのリソースを操作できます。
- 名前空間: 各プロセスは独自の「名前空間」を持ち、これはファイルシステムのビューです。プロセスは、他のプロセスの名前空間をマウントしたり、自身のリソースを他のプロセスにエクスポートしたりできます。
- 軽量プロセス(Threads/Processes): Plan 9にはUnixのような重いプロセスと軽量なスレッドという厳密な区別がありません。代わりに、すべての実行単位は「プロセス」として扱われますが、これらは非常に軽量であり、Unixのスレッドに近い感覚で利用されます。GoランタイムがPlan 9上で並行処理を実現する際も、これらの軽量プロセスを利用します。
/proc
ファイルシステム: Plan 9にもUnixと同様に/proc
ファイルシステムが存在しますが、その構造と機能は異なります。各プロセスは/proc/$pid
というディレクトリを持ち、その中にプロセスの状態や制御に関するファイルが含まれます。
2. Plan 9におけるプロセス制御ファイル
Plan 9の/proc/$pid
ディレクトリ内には、プロセスの制御や情報取得のための特別なファイルが存在します。
/proc/$pid/ctl
: このファイルはプロセスの制御に使用されます。特定のコマンド(例:kill
、stop
、start
など)を書き込むことで、プロセスの状態を操作できます。従来のGoのos
パッケージでは、ここに「kill」を書き込むことでプロセスを強制終了していました。/proc/$pid/note
: このファイルは、プロセスに「note」(通知)を送信するために使用されます。noteは、Unixのシグナルに似ていますが、より柔軟な文字列ベースのメッセージを送信できます。プロセスはnoteを受け取ると、事前に登録されたnoteハンドラを実行できます。これにより、プロセスはnoteの内容に応じてカスタムのクリーンアップや終了処理を行うことが可能です。
3. UnixにおけるシグナルとSIGKILL
Unix系システムでは、プロセス間通信やイベント通知のために「シグナル」が使用されます。
- シグナル: プロセスに非同期にイベントを通知するメカニズムです。例えば、
SIGINT
(Ctrl+C)、SIGTERM
(終了要求)、SIGKILL
(強制終了)などがあります。 SIGKILL
: これは特別なシグナルで、プロセスはこれを捕捉したり無視したりすることはできません。SIGKILL
を受け取ったプロセスは、即座にカーネルによって終了させられます。これにより、プロセスはクリーンアップ処理を行う機会がありません。Goランタイムは、Unix上でSIGKILL
を受け取ると、関連するすべてのゴルーチンやスレッドを強制的に終了させるように設計されています。
4. Goランタイムのプロセス終了処理
Goプログラムは、その実行を管理する「ランタイム」を持っています。ランタイムは、ゴルーチンのスケジューリング、ガベージコレクション、メモリ管理、システムコールとのインターフェースなどを担当します。
- グレースフルシャットダウン: Goプログラムが正常に終了する場合、ランタイムは開いているファイルやネットワーク接続を閉じ、バッファをフラッシュし、その他のリソースを解放するなど、適切なクリーンアップ処理を行います。
- 強制終了時の挙動: Unix系システムでは、
SIGKILL
のような強制終了シグナルが送信されると、ランタイムはクリーンアップを行うことなく即座に終了させられます。しかし、Plan 9では、Goランタイムが複数の軽量プロセスで構成されているため、これらのプロセスすべてに終了を通知し、協調して終了する必要があります。強制的な/proc/$pid/ctl
への「kill」書き込みでは、この協調的な終了が不可能でした。
このコミットは、Plan 9のnote
メカニズムを活用することで、GoランタイムがPlan 9上でもグレースフルシャットダウンに近い形で終了処理を行えるようにするための重要な改善です。
技術的詳細
このコミットの技術的な核心は、Goのos
パッケージがPlan 9上でプロセスを終了させる際の内部実装の変更にあります。
従来のos
パッケージのProcess.signal
メソッド(Plan 9固有の実装であるexec_plan9.go
内)では、Kill
シグナル(Goのos
パッケージで定義されている抽象的なシグナル)が渡された場合に、特別な処理を行っていました。具体的には、p.Kill()
メソッドを呼び出し、その中で/proc/$pid/ctl
というプロセス制御ファイルに直接「kill」という文字列を書き込むことで、プロセスを強制終了させていました。これは、UnixのSIGKILL
に相当する、プロセスが一切のクリーンアップを行う機会を与えずに即座に終了させる方法でした。
しかし、この変更により、Process.signal
メソッドからKill
シグナルに対する特別な処理が削除されました。その代わりに、Kill
シグナルも他のシグナルと同様に、p.writeProcFile("note", sig.String())
という呼び出しを通じて、/proc/$pid/note
ファイルに書き込まれるようになりました。
-
変更前:
Process.signal(Kill)
が呼ばれると、p.Kill()
が呼ばれる。p.Kill()
は/proc/$pid/ctl
に「kill」を書き込む。- これはプロセスを即座に、かつ強制的に終了させる。
-
変更後:
Process.signal(Kill)
が呼ばれると、他のシグナルと同様に処理される。p.writeProcFile("note", sig.String())
が呼ばれ、/proc/$pid/note
にKill
シグナルの文字列表現(例: "kill")が書き込まれる。- これにより、ターゲットプロセスはnoteを受け取り、そのnoteハンドラが起動される。Goランタイムは、このnoteハンドラ内で適切な終了処理(例えば、他のランタイムプロセスへの終了通知やリソースの解放)を実行できるようになる。
また、Process.kill()
メソッドも変更されました。変更前は、このメソッド内で直接/proc/$pid/ctl
に「kill」を書き込んでいましたが、変更後は単にp.signal(Kill)
を呼び出すように修正されました。これにより、Process.kill()
もnoteメカニズムを利用するようになり、一貫性が保たれます。
この変更は、Plan 9の設計思想である「note」メカニズムを尊重し、GoランタイムがPlan 9上でより協調的かつグレースフルに終了できるようにするための重要なステップです。これにより、Goプログラムの堅牢性と信頼性が向上します。
コアとなるコードの変更箇所
変更はsrc/pkg/os/exec_plan9.go
ファイルに集中しています。
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -52,10 +52,6 @@ func (p *Process) signal(sig Signal) error {
if p.done() {
return errors.New("os: process already finished")
}
- if sig == Kill {
- // Special-case the kill signal since it doesn't use /proc/$pid/note.
- return p.Kill()
- }
if e := p.writeProcFile("note", sig.String()); e != nil {
return NewSyscallError("signal", e)
}
@@ -63,10 +59,7 @@ func (p *Process) signal(sig Signal) error {
}
func (p *Process) kill() error {
- if e := p.writeProcFile("ctl", "kill"); e != nil {
- return NewSyscallError("kill", e)
- }
- return nil
+ return p.signal(Kill)
}
func (p *Process) wait() (ps *ProcessState, err error) {
コアとなるコードの解説
func (p *Process) signal(sig Signal) error
このメソッドは、特定のシグナルをプロセスに送信する役割を担っています。
-
変更前:
if sig == Kill { // Special-case the kill signal since it doesn't use /proc/$pid/note. return p.Kill() }
Kill
シグナルが渡された場合、このif
ブロックが実行され、p.Kill()
メソッドが呼び出されていました。コメントにあるように、これは/proc/$pid/note
を使用しない特別なケースとして扱われていました。つまり、Kill
シグナルはnoteメカニズムを介さずに、直接/proc/$pid/ctl
に「kill」を書き込むことで処理されていました。 -
変更後: 上記の
if
ブロックが完全に削除されました。これにより、Kill
シグナルも他のすべてのシグナルと同様に、以下の行で処理されるようになりました。if e := p.writeProcFile("note", sig.String()); e != nil { return NewSyscallError("signal", e) }
この行は、プロセスの
/proc/$pid/note
ファイルに、渡されたシグナル(sig
)の文字列表現を書き込みます。これにより、ターゲットプロセスはnoteを受け取り、そのnoteハンドラが起動されることになります。
func (p *Process) kill() error
このメソッドは、プロセスを終了させるための高レベルなインターフェースを提供します。
-
変更前:
if e := p.writeProcFile("ctl", "kill"); e != nil { return NewSyscallError("kill", e) } return nil
このメソッドは、直接
/proc/$pid/ctl
ファイルに「kill」という文字列を書き込むことで、プロセスを強制終了させていました。これは、Process.signal
メソッド内のKill
シグナルに対する特殊処理と同じメカニズムを使用していました。 -
変更後:
return p.signal(Kill)
このメソッドは、単に
p.signal(Kill)
を呼び出すように変更されました。これにより、Process.kill()
の呼び出しも、Process.signal
メソッドの新しいロジック(noteメカニズムを使用する)に従うようになります。この変更により、コードの重複が排除され、プロセス終了処理の一貫性が向上しました。
これらの変更により、Goのos
パッケージはPlan 9上でプロセスを終了させる際に、より協調的でグレースフルな方法を採用するようになりました。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
- Plan 9 from Bell Labs: https://9p.io/plan9/
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/
- このコミットのGerritチェンジリスト: https://golang.org/cl/74440044
参考にした情報源リンク
- Plan 9: The
/proc
File System: https://9p.io/magic/man2html/2/proc - Plan 9:
note
andnotify
: https://9p.io/magic/man2html/2/note - Unix
kill
command and signals: https://man7.org/linux/man-pages/man1/kill.1.html - Go
os
package documentation: https://pkg.go.dev/os - Go
syscall
package documentation (forNewSyscallError
): https://pkg.go.dev/syscall - Go
errors
package documentation: https://pkg.go.dev/errors - Go runtime source code (for understanding how Go handles signals and process termination on different OSes): https://github.com/golang/go/tree/master/src/runtime
- Stack Overflow and other technical forums for discussions on Plan 9 process management and Go runtime specifics.