[インデックス 13029] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるPlan 9オペレーティングシステム向けのシグナル処理に関する変更です。具体的には、既存のSignal
型を廃止し、代わりにNote
という新しい型を導入しています。この変更により、エクスポートされていたos.Plan9Note
型が削除され、Plan 9におけるシグナル(Goでは「ノート」と呼ばれる)の扱いがよりシンプルかつ統一されたものになります。
コミット
commit fe5005f721d3036dd3c6fa5c0e7b43c188342859
Author: Anthony Martin <ality@pbrane.org>
Date: Fri May 4 03:44:41 2012 -0700
syscall: remove the Signal type on Plan 9
Instead use a new type, "Note", whose underlying
type is just a string. This change allows us to
remove the exported os.Plan9Note type.
R=bradfitz, seed, rsc
CC=golang-dev
https://golang.org/cl/6015046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fe5005f721d3036dd3c6fa5c0e7b43c188342859
元コミット内容
Plan 9向けのsyscall
パッケージからSignal
型を削除し、代わりに基底型が文字列である新しいNote
型を使用する。この変更により、エクスポートされていたos.Plan9Note
型を削除することが可能になる。
変更の背景
Go言語は、様々なオペレーティングシステム(OS)をサポートするように設計されています。その中には、Unix系OS(Linux, macOSなど)やWindowsだけでなく、ベル研究所で開発された分散OSであるPlan 9も含まれます。
Unix系OSでは、プロセス間通信やプロセス制御のために「シグナル(Signal)」というメカニズムが広く使われています。Goのos
パッケージやsyscall
パッケージは、これらのシグナルを抽象化して扱うためのインターフェースを提供しています。
しかし、Plan 9ではUnixのシグナルとは異なる「ノート(Note)」という概念が使われています。ノートは、プロセスに対して文字列メッセージを送信するメカニズムであり、Unixのシグナルよりも柔軟な情報伝達が可能です。Goの初期の実装では、Plan 9のノートをUnixのシグナルインターフェースに合わせるために、syscall.Signal
型やos.Plan9Note
型といった抽象化レイヤーが導入されていました。
このコミットの背景には、Plan 9のノートをより自然な形でGoのシステムコール層で扱うこと、そしてUnix系OSのシグナルとPlan 9のノートという異なる概念を無理にSignal
という単一の型で表現することによる複雑さや不整合を解消する意図があったと考えられます。特に、os.Plan9Note
というPlan 9固有の型がos
パッケージでエクスポートされていることが、APIの統一性を損ねていた可能性があります。
この変更は、Plan 9のノートが本質的に文字列ベースであるという特性を活かし、syscall
パッケージ内でNote
型を文字列のエイリアスとして定義することで、よりシンプルで直感的なAPI設計を目指したものです。これにより、os
パッケージからPlan 9固有の型を削除し、クロスプラットフォームなos.Signal
インターフェースの背後で、各OSのシグナル/ノートの実装詳細を適切に隠蔽できるようになります。
前提知識の解説
1. Go言語のos
パッケージとsyscall
パッケージ
os
パッケージ: GoプログラムがOSと対話するための基本的な機能を提供します。ファイル操作、プロセス管理、環境変数へのアクセスなどが含まれます。os.Signal
インターフェースは、OSシグナルを抽象的に表現するためのものです。syscall
パッケージ: OS固有のシステムコールへの低レベルなインターフェースを提供します。このパッケージはOSごとに異なる実装を持ち、os
パッケージなどの高レベルなパッケージが内部で利用します。
2. Unix系OSにおけるシグナル (Signal)
Unix系OSでは、シグナルはソフトウェア割り込みの一種で、プロセスに特定のイベントが発生したことを通知するために使用されます。例えば、SIGINT
(Ctrl+Cによる割り込み)、SIGKILL
(強制終了)、SIGTERM
(終了要求)などがあります。シグナルは通常、整数値で識別されます。
3. Plan 9におけるノート (Note)
Plan 9では、Unixのシグナルに代わるメカニズムとして「ノート」が導入されています。ノートは、プロセスに対して文字列メッセージを送信する機能です。これにより、単なる数値のシグナルよりも詳細な情報をプロセスに伝えることができます。例えば、プロセスが終了する際に「kill
」というノートを受け取ったり、デバッガがプロセスに「debug
」というノートを送ったりすることが可能です。ノートは/proc/<pid>/note
というファイルに書き込むことで送信されます。
4. /proc
ファイルシステム
Unix系OSやPlan 9には、/proc
という仮想ファイルシステムが存在します。これは、実行中のプロセスに関する情報やシステムの状態をファイルとして公開するものです。各プロセスは通常、/proc/<pid>/
というディレクトリを持ち、その中にプロセスのメモリマップ、ファイルディスクリプタ、そしてPlan 9の場合はノートを送信するためのnote
ファイルなどが含まれます。
5. Goのインターフェース
Goのインターフェースは、メソッドのシグネチャの集合を定義する型です。ある型がインターフェースのすべてのメソッドを実装していれば、その型はそのインターフェースを満たしていると見なされます。os.Signal
インターフェースは、Signal()
というメソッドを持つことで、任意の型がシグナルとして扱われることを可能にします。
技術的詳細
このコミットの主要な技術的変更点は以下の通りです。
-
syscall.Signal
型の削除とsyscall.Note
型の導入:- Plan 9向けの
syscall
パッケージ(src/pkg/syscall/syscall_plan9.go
)から、以前定義されていたtype Signal int
が削除されました。 - 代わりに、
type Note string
という新しい型が導入されました。このNote
型は、os.Signal
インターフェース(Signal() {}
)とString()
メソッドを実装しています。これにより、Plan 9のノートがGoのos.Signal
インターフェースを満たしつつ、その実体が文字列であることを明確に表現できるようになりました。
- Plan 9向けの
-
os.Plan9Note
型の削除:src/pkg/os/exec.go
から、os.Plan9Note
型が完全に削除されました。これは、syscall.Note
が直接os.Signal
インターフェースを満たすようになったため、os
パッケージ側でPlan 9固有のシグナル型をエクスポートする必要がなくなったためです。
-
os.Interrupt
とos.Kill
のPlan 9実装の変更:src/pkg/os/exec_plan9.go
において、os.Interrupt
とos.Kill
の具体的な値が、以前のsyscall.SIGINT
やsyscall.SIGKILL
(これらも削除された)から、新しく定義されたsyscall.Note("interrupt")
とsyscall.Note("kill")
に変更されました。これにより、Plan 9のノートの概念が直接的に反映されるようになりました。
-
プロセスへのノート送信ロジックの変更:
src/pkg/os/exec_plan9.go
の(*Process).signal
メソッドにおいて、プロセスにノートを送信するロジックが変更されました。以前は/proc/$pid/note
ファイルに直接書き込んでいましたが、新しいwriteProcFile
ヘルパー関数が導入され、これを通じてノートが書き込まれるようになりました。Kill
シグナル(ノート)の扱いが特別視され、(*Process).Kill()
メソッドが直接呼び出されるようになりました。これは、Plan 9においてkill
ノートは/proc/$pid/note
ではなく、/proc/$pid/ctl
ファイルに「kill
」という文字列を書き込むことで実現されるためです。この変更により、Plan 9のkill
メカニズムがより正確に反映されています。
-
zerrors_plan9_386.go
からのシグナル定数削除:src/pkg/syscall/zerrors_plan9_386.go
から、SIGINT
とSIGKILL
の定数が削除されました。これらは以前syscall.Signal
型として定義されていましたが、Signal
型自体が削除されたため、不要になりました。
これらの変更により、GoのPlan 9サポートにおけるシグナル(ノート)の扱いが、よりPlan 9のネイティブなメカニズムに即したものとなり、かつGoのAPI設計の統一性が向上しました。
コアとなるコードの変更箇所
src/pkg/os/exec.go
Signal
インターフェースの定義は残るが、Interrupt
とKill
のグローバル変数の定義が削除された。これは、OS固有のファイル(exec_plan9.go
やexec_posix.go
)で定義されるようになったため。
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -54,14 +54,6 @@ type Signal interface {
Signal() // to distinguish from other Stringers
}
-// The only signal values guaranteed to be present on all systems
-// are Interrupt (send the process an interrupt) and
-// Kill (force the process to exit).\n-var (\n-\tInterrupt Signal = syscall.SIGINT\n-\tKill Signal = syscall.SIGKILL\n-)\n-\n // Getpid returns the process id of the caller.\n func Getpid() int { return syscall.Getpid() }\n
src/pkg/os/exec_plan9.go
Interrupt
とKill
がsyscall.Note
型として再定義された。Plan9Note
型が削除された。writeProcFile
ヘルパー関数が追加された。signal
メソッドとkill
メソッドがwriteProcFile
を使用するように変更された。
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -11,6 +11,14 @@ import (
"time"
)
+// The only signal values guaranteed to be present on all systems
+// are Interrupt (send the process an interrupt) and Kill (force
+// the process to exit).
+var (
+ Interrupt Signal = syscall.Note("interrupt")
+ Kill Signal = syscall.Note("kill")
+)
+
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
@@ -30,35 +38,35 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
return newProcess(pid, h), nil
}
-// Plan9Note implements the Signal interface on Plan 9.
-type Plan9Note string
-
-func (note Plan9Note) String() string {
- return string(note)
+func (p *Process) writeProcFile(file string, data string) error {
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0)
+ if e != nil {
+ return e
+ }
+ defer f.Close()
+ _, e = f.Write([]byte(data))
+ return e
}
func (p *Process) signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
-
- f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
- if e != nil {
+ 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)
}
- defer f.Close()
- _, e = f.Write([]byte(sig.String()))
- return e
+ return nil
}
func (p *Process) kill() error {
- f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
- if e != nil {
+ if e := p.writeProcFile("ctl", "kill"); e != nil {
return NewSyscallError("kill", e)
}
- defer f.Close()
- _, e = f.Write([]byte("kill"))
- return e
+ return nil
}
func (p *Process) wait() (ps *ProcessState, err error) {
src/pkg/os/exec_posix.go
Interrupt
とKill
がsyscall.SIGINT
とsyscall.SIGKILL
として再定義された。これは、os/exec.go
から移動されたもの。
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -10,6 +10,14 @@ import (
"syscall"
)
+// The only signal values guaranteed to be present on all systems
+// are Interrupt (send the process an interrupt) and Kill (force
+// the process to exit).
+var (
+ Interrupt Signal = syscall.SIGINT
+ Kill Signal = syscall.SIGKILL
+)
+
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
// Double-check existence of the directory we want
// to chdir into. We can make the error clearer this way.
src/pkg/syscall/syscall_plan9.go
Note
型が新しく定義され、os.Signal
インターフェースを実装するようになった。- 以前の
Signal
型が削除された。
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -23,6 +23,16 @@ func (e ErrorString) Error() string { return string(e) }\n // NewError converts s to an ErrorString, which satisfies the Error interface.\n func NewError(s string) { return ErrorString(s) }\n \n+// A Note is a string describing a process note.\n+// It implements the os.Signal interface.\n+type Note string\n+\n+func (n Note) Signal() {}\n+\n+func (n Note) String() string {\n+\treturn string(n)\n+}\n+\n var (\n Stdin = 0\n Stdout = 1
@@ -322,14 +332,6 @@ func Getgroups() (gids []int, err error) {\n return make([]int, 0), nil\n }\n \n-type Signal int\n-\n-func (s Signal) Signal() {}\n-\n-func (s Signal) String() string {\n-\treturn ""\n-}\n-\n //sys Dup(oldfd int, newfd int) (fd int, err error)\n //sys Open(path string, mode int) (fd int, err error)\n //sys Create(path string, mode int, perm uint32) (fd int, err error)\n```
### `src/pkg/syscall/zerrors_plan9_386.go`
- `SIGINT`と`SIGKILL`の定数が削除された。
```diff
--- a/src/pkg/syscall/zerrors_plan9_386.go
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -24,9 +24,6 @@ const (
S_IFREG = 0x8000
S_IFLNK = 0xa000
S_IFSOCK = 0xc000
-\n-\tSIGINT = Signal(0x2)\n-\tSIGKILL = Signal(0x9)\n )
// Errors
コアとなるコードの解説
このコミットの核心は、Plan 9におけるシグナル(ノート)の表現方法を、Goの型システム内でより自然で効率的なものにすることです。
-
syscall.Note
の導入:- 以前は
syscall.Signal
という整数ベースの型が使われていましたが、Plan 9のノートは本質的に文字列です。この不整合を解消するため、type Note string
が導入されました。 - この
Note
型は、Signal() {}
メソッドとString() string
メソッドを実装することで、Goのos.Signal
インターフェースを満たします。これにより、os
パッケージの汎用的なシグナル処理ロジックが、Plan 9のノートに対しても透過的に機能するようになります。 String()
メソッドは、Note
の基底となる文字列値をそのまま返すため、ノートの内容を直接文字列として利用できます。
- 以前は
-
os.Plan9Note
の削除:syscall.Note
が直接os.Signal
インターフェースを満たすようになったため、os
パッケージ内でPlan 9固有のos.Plan9Note
型をエクスポートする必要がなくなりました。これは、APIのクリーンアップと、OS固有の概念をより低レベルのsyscall
パッケージに閉じ込めるという設計原則に合致します。
-
os.Interrupt
とos.Kill
のPlan 9固有の実装:os.Interrupt
とos.Kill
は、GoプログラムがOSに依存せず利用できる汎用的なシグナルです。Plan 9では、これらがそれぞれsyscall.Note("interrupt")
とsyscall.Note("kill")
として定義されました。これにより、Goの汎用シグナルがPlan 9のノートとして適切にマッピングされます。
-
writeProcFile
ヘルパー関数とkill
の特殊処理:os/exec_plan9.go
に導入されたwriteProcFile
関数は、/proc/$pid/
以下のファイルにデータを書き込むための汎用的なヘルパーです。これにより、コードの重複が減り、可読性が向上します。(*Process).signal
メソッド内でsig == Kill
の特殊処理が追加されたのは重要です。Plan 9では、プロセスを強制終了させる「kill
」ノートは、他のノートとは異なり/proc/$pid/note
ではなく/proc/$pid/ctl
ファイルに書き込むことで行われます。この変更は、Plan 9のシステムコール規約に厳密に従うためのものです。これにより、Goのos.Kill
がPlan 9上で正しく機能するようになります。
これらの変更は、Goのクロスプラットフォーム対応において、各OSの特性を尊重しつつ、共通のインターフェースを通じて一貫したプログラミングモデルを提供するというGoの設計哲学を反映しています。特に、Plan 9のノートというユニークなメカニズムを、Goの型システムとos.Signal
インターフェースにうまく統合した例と言えます。
関連リンク
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall - Plan 9のノートに関するドキュメント (例:
note(2)
man page): https://9p.io/magic/man2html/2/note - Goのコードレビューシステム (Gerrit) の変更リスト: https://golang.org/cl/6015046
参考にした情報源リンク
- 上記のGitHubコミットページ
- Go言語の公式ドキュメント
- Plan 9のシステムに関する一般的な情報源
- Go言語のソースコード
[インデックス 13029] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるPlan 9オペレーティングシステム向けのシグナル処理に関する変更です。具体的には、既存のSignal
型を廃止し、代わりにNote
という新しい型を導入しています。この変更により、エクスポートされていたos.Plan9Note
型が削除され、Plan 9におけるシグナル(Goでは「ノート」と呼ばれる)の扱いがよりシンプルかつ統一されたものになります。
コミット
commit fe5005f721d3036dd3c6fa5c0e7b43c188342859
Author: Anthony Martin <ality@pbrane.org>
Date: Fri May 4 03:44:41 2012 -0700
syscall: remove the Signal type on Plan 9
Instead use a new type, "Note", whose underlying
type is just a string. This allows us to
remove the exported os.Plan9Note type.
R=bradfitz, seed, rsc
CC=golang-dev
https://golang.org/cl/6015046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fe5005f721d3036dd3c6fa5c0e7b43c188342859
元コミット内容
Plan 9向けのsyscall
パッケージからSignal
型を削除し、代わりに基底型が文字列である新しいNote
型を使用する。この変更により、エクスポートされていたos.Plan9Note
型を削除することが可能になる。
変更の背景
Go言語は、様々なオペレーティングシステム(OS)をサポートするように設計されています。その中には、Unix系OS(Linux, macOSなど)やWindowsだけでなく、ベル研究所で開発された分散OSであるPlan 9も含まれます。
Unix系OSでは、プロセス間通信やプロセス制御のために「シグナル(Signal)」というメカニズムが広く使われています。Goのos
パッケージやsyscall
パッケージは、これらのシグナルを抽象化して扱うためのインターフェースを提供しています。
しかし、Plan 9ではUnixのシグナルとは異なる「ノート(Note)」という概念が使われています。ノートは、プロセスに対して文字列メッセージを送信するメカニズムであり、Unixのシグナルよりも柔軟な情報伝達が可能です。Goの初期の実装では、Plan 9のノートをUnixのシグナルインターフェースに合わせるために、syscall.Signal
型やos.Plan9Note
型といった抽象化レイヤーが導入されていました。
このコミットの背景には、Plan 9のノートをより自然な形でGoのシステムコール層で扱うこと、そしてUnix系OSのシグナルとPlan 9のノートという異なる概念を無理にSignal
という単一の型で表現することによる複雑さや不整合を解消する意図があったと考えられます。特に、os.Plan9Note
というPlan 9固有の型がos
パッケージでエクスポートされていることが、APIの統一性を損ねていた可能性があります。
この変更は、Plan 9のノートが本質的に文字列ベースであるという特性を活かし、syscall
パッケージ内でNote
型を文字列のエイリアスとして定義することで、よりシンプルで直感的なAPI設計を目指したものです。これにより、os
パッケージからPlan 9固有の型を削除し、クロスプラットフォームなos.Signal
インターフェースの背後で、各OSのシグナル/ノートの実装詳細を適切に隠蔽できるようになります。
前提知識の解説
1. Go言語のos
パッケージとsyscall
パッケージ
os
パッケージ: GoプログラムがOSと対話するための基本的な機能を提供します。ファイル操作、プロセス管理、環境変数へのアクセスなどが含まれます。os.Signal
インターフェースは、OSシグナルを抽象的に表現するためのものです。syscall
パッケージ: OS固有のシステムコールへの低レベルなインターフェースを提供します。このパッケージはOSごとに異なる実装を持ち、os
パッケージなどの高レベルなパッケージが内部で利用します。
2. Unix系OSにおけるシグナル (Signal)
Unix系OSでは、シグナルはソフトウェア割り込みの一種で、プロセスに特定のイベントが発生したことを通知するために使用されます。例えば、SIGINT
(Ctrl+Cによる割り込み)、SIGKILL
(強制終了)、SIGTERM
(終了要求)などがあります。シグナルは通常、整数値で識別されます。
3. Plan 9におけるノート (Note)
Plan 9では、Unixのシグナルに代わるメカニズムとして「ノート」が導入されています。ノートは、プロセスに対して文字列メッセージを送信する機能です。これにより、単なる数値のシグナルよりも詳細な情報をプロセスに伝えることができます。例えば、プロセスが終了する際に「kill
」というノートを受け取ったり、デバッガがプロセスに「debug
」というノートを送ったりすることが可能です。ノートは/proc/<pid>/note
というファイルに書き込むことで送信されます。
4. /proc
ファイルシステム
Unix系OSやPlan 9には、/proc
という仮想ファイルシステムが存在します。これは、実行中のプロセスに関する情報やシステムの状態をファイルとして公開するものです。各プロセスは通常、/proc/<pid>/
というディレクトリを持ち、その中にプロセスのメモリマップ、ファイルディスクリプタ、そしてPlan 9の場合はノートを送信するためのnote
ファイルなどが含まれます。
5. Goのインターフェース
Goのインターフェースは、メソッドのシグネチャの集合を定義する型です。ある型がインターフェースのすべてのメソッドを実装していれば、その型はそのインターフェースを満たしていると見なされます。os.Signal
インターフェースは、Signal()
というメソッドを持つことで、任意の型がシグナルとして扱われることを可能にします。
技術的詳細
このコミットの主要な技術的変更点は以下の通りです。
-
syscall.Signal
型の削除とsyscall.Note
型の導入:- Plan 9向けの
syscall
パッケージ(src/pkg/syscall/syscall_plan9.go
)から、以前定義されていたtype Signal int
が削除されました。 - 代わりに、
type Note string
という新しい型が導入されました。このNote
型は、os.Signal
インターフェース(Signal() {}
)とString()
メソッドを実装しています。これにより、Plan 9のノートがGoのos.Signal
インターフェースを満たしつつ、その実体が文字列であることを明確に表現できるようになりました。
- Plan 9向けの
-
os.Plan9Note
型の削除:src/pkg/os/exec.go
から、os.Plan9Note
型が完全に削除されました。これは、syscall.Note
が直接os.Signal
インターフェースを満たすようになったため、os
パッケージ側でPlan 9固有のシグナル型をエクスポートする必要がなくなったためです。
-
os.Interrupt
とos.Kill
のPlan 9実装の変更:src/pkg/os/exec_plan9.go
において、os.Interrupt
とos.Kill
の具体的な値が、以前のsyscall.SIGINT
やsyscall.SIGKILL
(これらも削除された)から、新しく定義されたsyscall.Note("interrupt")
とsyscall.Note("kill")
に変更されました。これにより、Plan 9のノートの概念が直接的に反映されるようになりました。
-
プロセスへのノート送信ロジックの変更:
src/pkg/os/exec_plan9.go
の(*Process).signal
メソッドにおいて、プロセスにノートを送信するロジックが変更されました。以前は/proc/$pid/note
ファイルに直接書き込んでいましたが、新しいwriteProcFile
ヘルパー関数が導入され、これを通じてノートが書き込まれるようになりました。Kill
シグナル(ノート)の扱いが特別視され、(*Process).Kill()
メソッドが直接呼び出されるようになりました。これは、Plan 9においてkill
ノートは/proc/$pid/note
ではなく、/proc/$pid/ctl
ファイルに「kill
」という文字列を書き込むことで実現されるためです。この変更により、Plan 9のkill
メカニズムがより正確に反映されています。
-
zerrors_plan9_386.go
からのシグナル定数削除:src/pkg/syscall/zerrors_plan9_386.go
から、SIGINT
とSIGKILL
の定数が削除されました。これらは以前syscall.Signal
型として定義されていましたが、Signal
型自体が削除されたため、不要になりました。
これらの変更により、GoのPlan 9サポートにおけるシグナル(ノート)の扱いが、よりPlan 9のネイティブなメカニズムに即したものとなり、かつGoのAPI設計の統一性が向上しました。
コアとなるコードの変更箇所
src/pkg/os/exec.go
Signal
インターフェースの定義は残るが、Interrupt
とKill
のグローバル変数の定義が削除された。これは、OS固有のファイル(exec_plan9.go
やexec_posix.go
)で定義されるようになったため。
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -54,14 +54,6 @@ type Signal interface {
Signal() // to distinguish from other Stringers
}
-// The only signal values guaranteed to be present on all systems
-// are Interrupt (send the process an interrupt) and
-// Kill (force the process to exit).\n-var (\n-\tInterrupt Signal = syscall.SIGINT\n-\tKill Signal = syscall.SIGKILL\n-)\n-\n // Getpid returns the process id of the caller.\n func Getpid() int { return syscall.Getpid() }\n
src/pkg/os/exec_plan9.go
Interrupt
とKill
がsyscall.Note
型として再定義された。Plan9Note
型が削除された。writeProcFile
ヘルパー関数が追加された。signal
メソッドとkill
メソッドがwriteProcFile
を使用するように変更された。
--- a/src/pkg/os/exec_plan9.go
+++ b/src/pkg/os/exec_plan9.go
@@ -11,6 +11,14 @@ import (
"time"
)
+// The only signal values guaranteed to be present on all systems
+// are Interrupt (send the process an interrupt) and Kill (force
+// the process to exit).
+var (
+ Interrupt Signal = syscall.Note("interrupt")
+ Kill Signal = syscall.Note("kill")
+)
+
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
sysattr := &syscall.ProcAttr{
Dir: attr.Dir,
@@ -30,35 +38,35 @@ func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err e
return newProcess(pid, h), nil
}
-// Plan9Note implements the Signal interface on Plan 9.
-type Plan9Note string
-
-func (note Plan9Note) String() string {
- return string(note)
+func (p *Process) writeProcFile(file string, data string) error {
+ f, e := OpenFile("/proc/"+itoa(p.Pid)+"/"+file, O_WRONLY, 0)
+ if e != nil {
+ return e
+ }
+ defer f.Close()
+ _, e = f.Write([]byte(data))
+ return e
}
func (p *Process) signal(sig Signal) error {
if p.done {
return errors.New("os: process already finished")
}
-
- f, e := OpenFile("/proc/"+itoa(p.Pid)+"/note", O_WRONLY, 0)
- if e != nil {
+ 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)
}
- defer f.Close()
- _, e = f.Write([]byte(sig.String()))
- return e
+ return nil
}
func (p *Process) kill() error {
- f, e := OpenFile("/proc/"+itoa(p.Pid)+"/ctl", O_WRONLY, 0)
- if e != nil {
+ if e := p.writeProcFile("ctl", "kill"); e != nil {
return NewSyscallError("kill", e)
}
- defer f.Close()
- _, e = f.Write([]byte("kill"))
- return e
+ return nil
}
func (p *Process) wait() (ps *ProcessState, err error) {
src/pkg/os/exec_posix.go
Interrupt
とKill
がsyscall.SIGINT
とsyscall.SIGKILL
として再定義された。これは、os/exec.go
から移動されたもの。
--- a/src/pkg/os/exec_posix.go
+++ b/src/pkg/os/exec_posix.go
@@ -10,6 +10,14 @@ import (
"syscall"
)
+// The only signal values guaranteed to be present on all systems
+// are Interrupt (send the process an interrupt) and Kill (force
+// the process to exit).
+var (
+ Interrupt Signal = syscall.SIGINT
+ Kill Signal = syscall.SIGKILL
+)
+
func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
// Double-check existence of the directory we want
// to chdir into. We can make the error clearer this way.
src/pkg/syscall/syscall_plan9.go
Note
型が新しく定義され、os.Signal
インターフェースを実装するようになった。- 以前の
Signal
型が削除された。
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -23,6 +23,16 @@ func (e ErrorString) Error() string { return string(e) }\n // NewError converts s to an ErrorString, which satisfies the Error interface.\n func NewError(s string) { return ErrorString(s) }\n \n+// A Note is a string describing a process note.\n+// It implements the os.Signal interface.\n+type Note string\n+\n+func (n Note) Signal() {}\n+\n+func (n Note) String() string {\n+\treturn string(n)\n+}\n+\n var (\n Stdin = 0\n Stdout = 1
@@ -322,14 +332,6 @@ func Getgroups() (gids []int, err error) {\n return make([]int, 0), nil
}\n \n-type Signal int\n-\n-func (s Signal) Signal() {}\n-\n-func (s Signal) String() string {\n-\treturn ""\n-}\n-\n //sys Dup(oldfd int, newfd int) (fd int, err error)\n //sys Open(path string, mode int) (fd int, err error)\n //sys Create(path string, mode int, perm uint32) (fd int, err error)\n```
### `src/pkg/syscall/zerrors_plan9_386.go`
- `SIGINT`と`SIGKILL`の定数が削除された。
```diff
--- a/src/pkg/syscall/zerrors_plan9_386.go
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -24,9 +24,6 @@ const (
S_IFREG = 0x8000
S_IFLNK = 0xa000
S_IFSOCK = 0xc000
-\n-\tSIGINT = Signal(0x2)\n-\tSIGKILL = Signal(0x9)\n )
// Errors
コアとなるコードの解説
このコミットの核心は、Plan 9におけるシグナル(ノート)の表現方法を、Goの型システム内でより自然で効率的なものにすることです。
-
syscall.Note
の導入:- 以前は
syscall.Signal
という整数ベースの型が使われていましたが、Plan 9のノートは本質的に文字列です。この不整合を解消するため、type Note string
が導入されました。 - この
Note
型は、Signal() {}
メソッドとString() string
メソッドを実装することで、Goのos.Signal
インターフェースを満たします。これにより、os
パッケージの汎用的なシグナル処理ロジックが、Plan 9のノートに対しても透過的に機能するようになります。 String()
メソッドは、Note
の基底となる文字列値をそのまま返すため、ノートの内容を直接文字列として利用できます。
- 以前は
-
os.Plan9Note
の削除:syscall.Note
が直接os.Signal
インターフェースを満たすようになったため、os
パッケージ内でPlan 9固有のos.Plan9Note
型をエクスポートする必要がなくなりました。これは、APIのクリーンアップと、OS固有の概念をより低レベルのsyscall
パッケージに閉じ込めるという設計原則に合致します。
-
os.Interrupt
とos.Kill
のPlan 9固有の実装:os.Interrupt
とos.Kill
は、GoプログラムがOSに依存せず利用できる汎用的なシグナルです。Plan 9では、これらがそれぞれsyscall.Note("interrupt")
とsyscall.Note("kill")
として定義されました。これにより、Goの汎用シグナルがPlan 9のノートとして適切にマッピングされます。
-
writeProcFile
ヘルパー関数とkill
の特殊処理:os/exec_plan9.go
に導入されたwriteProcFile
関数は、/proc/$pid/
以下のファイルにデータを書き込むための汎用的なヘルパーです。これにより、コードの重複が減り、可読性が向上します。(*Process).signal
メソッド内でsig == Kill
の特殊処理が追加されたのは重要です。Plan 9では、プロセスを強制終了させる「kill
」ノートは、他のノートとは異なり/proc/$pid/note
ではなく/proc/$pid/ctl
ファイルに書き込むことで行われます。この変更は、Plan 9のシステムコール規約に厳密に従うためのものです。これにより、Goのos.Kill
がPlan 9上で正しく機能するようになります。
これらの変更は、Goのクロスプラットフォーム対応において、各OSの特性を尊重しつつ、共通のインターフェースを通じて一貫したプログラミングモデルを提供するというGoの設計哲学を反映しています。特に、Plan 9のノートというユニークなメカニズムを、Goの型システムとos.Signal
インターフェースにうまく統合した例と言えます。
関連リンク
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall - Plan 9のノートに関するドキュメント (例:
note(2)
man page): https://9p.io/magic/man2html/2/note - Goのコードレビューシステム (Gerrit) の変更リスト: https://golang.org/cl/6015046
参考にした情報源リンク
- 上記のGitHubコミットページ
- Go言語の公式ドキュメント
- Plan 9のシステムに関する一般的な情報源
- Go言語のソースコード
- Web検索結果: "In Plan 9, the concept of "signals" as known in Unix-like systems is replaced by "notes." Unlike Unix signals, which are typically integer values, Plan 9 notes are arbitrary strings that can be sent between processes. This allows for more descriptive and flexible inter-process communication. In the Go programming language, when running on a Plan 9 system, the
os/signal
package adapts to this system. Specifically, a "Signal Note type" refers to thesyscall.Note
type, which is a string. When you usesignal.Notify
in Go on Plan 9, you can register to receive these string-based notes. If a process posts a note that matches the string you've registered, that string value will be sent on the Go channel." (ycombinator.com, github.io, wikipedia.org, go.dev)