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

[インデックス 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シグナルに相当する、非常に強制的な終了方法です。

しかし、この強制終了にはいくつかの問題がありました。

  1. グレースフルシャットダウンの阻害: プロセスが「kill」コマンドによって強制終了されると、そのプロセスは自身の終了処理(リソースの解放、ファイルのクローズ、データの永続化など)を行う機会を失います。これにより、データ破損、リソースリーク、または予期せぬ状態に陥る可能性がありました。
  2. Goランタイムの特殊性: 特にGoプログラムの場合、この問題は顕著でした。Unix系システムでは、SIGKILLがGoプログラムに送信されると、Goランタイムは自動的に関連するすべてのランタイムスレッドを終了させます。しかし、Plan 9にはUnixのような「スレッド」の概念がありません。代わりに、Goランタイムは複数の「プロセス」(Plan 9の軽量プロセス)を使用して並行処理を実現しています。プログラムが終了する際には、これらのランタイムプロセスすべてに終了を通知し、適切なクリーンアップを行う必要があります。強制的な「kill」では、この通知とクリーンアップのメカニズムが機能せず、ランタイムが正常に終了できないという問題がありました。
  3. 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: このファイルはプロセスの制御に使用されます。特定のコマンド(例: killstopstartなど)を書き込むことで、プロセスの状態を操作できます。従来の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/noteKillシグナルの文字列表現(例: "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上でプロセスを終了させる際に、より協調的でグレースフルな方法を採用するようになりました。

関連リンク

参考にした情報源リンク

[インデックス 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シグナルに相当する、非常に強制的な終了方法です。

しかし、この強制終了にはいくつかの問題がありました。

  1. グレースフルシャットダウンの阻害: プロセスが「kill」コマンドによって強制終了されると、そのプロセスは自身の終了処理(リソースの解放、ファイルのクローズ、データの永続化など)を行う機会を失います。これにより、データ破損、リソースリーク、または予期せぬ状態に陥る可能性がありました。
  2. Goランタイムの特殊性: 特にGoプログラムの場合、この問題は顕著でした。Unix系システムでは、SIGKILLがGoプログラムに送信されると、Goランタイムは自動的に関連するすべてのランタイムスレッドを終了させます。しかし、Plan 9にはUnixのような「スレッド」の概念がありません。代わりに、Goランタイムは複数の「プロセス」(Plan 9の軽量プロセス)を使用して並行処理を実現しています。プログラムが終了する際には、これらのランタイムプロセスすべてに終了を通知し、適切なクリーンアップを行う必要があります。強制的な「kill」では、この通知とクリーンアップのメカニズムが機能せず、ランタイムが正常に終了できないという問題がありました。
  3. 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: このファイルはプロセスの制御に使用されます。特定のコマンド(例: killstopstartなど)を書き込むことで、プロセスの状態を操作できます。従来の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/noteKillシグナルの文字列表現(例: "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上でプロセスを終了させる際に、より協調的でグレースフルな方法を採用するようになりました。

関連リンク

参考にした情報源リンク