[インデックス 13272] ファイルの概要
このコミットは、Go言語のsyscall
パッケージにおけるNetBSD向けのパイプ作成処理を改善するものです。具体的には、pipe2
システムコールからpipe
システムコールへの変更を行い、NetBSD 5との互換性を向上させています。
コミット
commit 677cdb800d85025b01173e44925189c822869168
Author: Benny Siegert <bsiegert@gmail.com>
Date: Tue Jun 5 01:29:34 2012 +1000
syscall: use pipe instead of pipe2 on NetBSD
pipe2 is equivalent to pipe with flags set to 0.
However, pipe2 was only added recently. Using pipe
instead improves compatibility with NetBSD 5.
R=jsing
CC=golang-dev
https://golang.org/cl/6268045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/677cdb800d85025b01173e44925189c822869168
元コミット内容
syscall: use pipe instead of pipe2 on NetBSD
このコミットは、NetBSD上でパイプを作成する際にpipe2
システムコールではなくpipe
システムコールを使用するように変更します。pipe2
はフラグを0に設定した場合にpipe
と同等ですが、pipe2
は比較的新しく追加されたシステムコールであるため、pipe
を使用することでNetBSD 5との互換性が向上します。
変更の背景
Go言語は、様々なオペレーティングシステム(OS)上で動作するように設計されています。そのため、各OSのシステムコールを適切に利用し、互換性を維持することが重要です。このコミットの背景には、NetBSDという特定のOSバージョン(NetBSD 5)におけるシステムコールの可用性の問題がありました。
pipe2
システムコールは、従来のpipe
システムコールに加えて、パイプの作成時に追加のフラグ(例えば、O_NONBLOCK
やO_CLOEXEC
など)を指定できる機能を提供します。これにより、パイプの動作をより細かく制御できるようになります。しかし、このpipe2
は比較的新しいシステムコールであり、古いバージョンのOSでは利用できない場合があります。
NetBSD 5は、このpipe2
システムコールがまだ導入されていなかった、あるいは安定していなかった時期のバージョンであると考えられます。Goのsyscall
パッケージがpipe2
を使用するように実装されていた場合、NetBSD 5上でGoプログラムがパイプを作成しようとすると、pipe2
システムコールが見つからない、または正しく動作しないためにエラーが発生する可能性がありました。
この互換性の問題を解決するため、開発者はpipe2
の使用を避け、より広く利用可能なpipe
システムコールに切り替えることを決定しました。コミットメッセージにある「pipe2
is equivalent to pipe
with flags set to 0」という記述は、pipe2
がフラグなしで呼び出された場合、その機能がpipe
と全く同じであることを示しており、機能的な損失がないことを強調しています。
前提知識の解説
1. システムコール (System Call)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。プログラムがファイルを開いたり、メモリを割り当てたり、ネットワーク通信を行ったりする際には、直接ハードウェアを操作するのではなく、OSのシステムコールを呼び出します。これにより、OSはシステムリソースを管理し、複数のプログラムが安全かつ効率的に動作できるようにします。
Go言語では、syscall
パッケージがOSのシステムコールへの低レベルなアクセスを提供します。これにより、GoプログラムはOS固有の機能を利用したり、パフォーマンスが重要な処理を行ったりすることができます。
2. パイプ (Pipe)
パイプは、プロセス間通信(IPC: Inter-Process Communication)の一種で、一方のプロセスが書き込んだデータを、もう一方のプロセスが読み取ることができる単方向のデータストリームです。UNIX系OSでは、シェルコマンドの|
(パイプ)演算子でおなじみです。
プログラム内でパイプを作成するには、通常、pipe()
またはpipe2()
といったシステムコールを使用します。これらのシステムコールは、2つのファイルディスクリプタ(通常は整数値)を返します。1つはパイプへの書き込み用、もう1つはパイプからの読み取り用です。
3. pipe()
システムコール
pipe()
システムコールは、最も基本的なパイプ作成関数です。通常、以下のようなシグネチャを持ちます(C言語の場合):
int pipe(int pipefd[2]);
この関数は、pipefd
という2要素の整数配列を受け取ります。成功すると、pipefd[0]
には読み取り用のファイルディスクリプタが、pipefd[1]
には書き込み用のファイルディスクリプタが格納されます。エラーが発生した場合は-1を返します。
pipe()
で作成されたパイプは、デフォルトでブロッキングI/Oモードで動作し、O_CLOEXEC
(exec
系システムコールで子プロセスにファイルディスクリプタが継承されないようにするフラグ)は設定されません。これらの挙動を変更するには、別途fcntl()
システムコールなどを使用する必要があります。
4. pipe2()
システムコール
pipe2()
システムコールは、pipe()
の拡張版です。以下のようなシグネチャを持ちます(C言語の場合):
int pipe2(int pipefd[2], int flags);
pipe2()
はpipefd
配列に加えて、flags
引数を受け取ります。このflags
引数を使用することで、パイプの作成時にO_NONBLOCK
(非ブロッキングI/O)やO_CLOEXEC
などのフラグを原子的に設定できます。これにより、pipe()
でパイプを作成した後にfcntl()
を呼び出す必要がなくなり、競合状態のリスクを減らすことができます。
コミットメッセージにある「pipe2
is equivalent to pipe
with flags set to 0」とは、pipe2(pipefd, 0)
と呼び出すことが、pipe(pipefd)
と呼び出すことと機能的に同じであることを意味します。
5. NetBSD
NetBSDは、BSD系UNIXオペレーティングシステムの一つで、高い移植性を特徴としています。様々なハードウェアアーキテクチャ上で動作するように設計されており、組み込みシステムからサーバーまで幅広い用途で利用されています。Go言語は、このような多様なOS環境をサポートしており、NetBSDもその対象の一つです。
このコミットは、NetBSDの特定のバージョン(NetBSD 5)におけるシステムコールの実装状況を考慮したものであり、Go言語が異なるOSバージョン間での互換性をどのように維持しているかを示す良い例です。
技術的詳細
このコミットの技術的な核心は、Go言語のsyscall
パッケージがNetBSD上でパイプを作成する際に、どのシステムコールを使用するかという点にあります。
元の実装では、Goのsyscall
パッケージはNetBSD向けにpipe2
システムコールを利用していました。これは、pipe2
がpipe
よりも新しい機能を提供し、パイプ作成時にフラグを原子的に設定できるという利点があるため、より現代的なアプローチと見なされていた可能性があります。
しかし、NetBSD 5のような古いバージョンのOSでは、pipe2
システムコールが利用できないか、あるいはその挙動が期待通りではないという問題がありました。GoプログラムがNetBSD 5上で動作し、パイプを作成しようとすると、pipe2
の呼び出しが失敗し、プログラムのクラッシュや予期せぬエラーにつながる可能性がありました。
この問題を解決するため、コミットではpipe2
の使用を中止し、代わりにpipe
システムコールを使用するように変更されました。
pipe2
からpipe
への切り替え:pipe2
はflags
引数を取りますが、このコミットではpipe2
を呼び出す際にflags
を0
に設定していました。これは、機能的にはpipe
システムコールと全く同じ挙動を意味します。したがって、pipe2
をpipe
に置き換えても、機能的な影響は全くありません。- 互換性の向上:
pipe
システムコールはpipe2
よりも古くから存在し、より多くのOSバージョンでサポートされています。特にNetBSD 5のような古い環境では、pipe
が確実に利用できるため、この変更によってGoプログラムのNetBSD 5における互換性が大幅に向上します。 - Goの
syscall
パッケージの抽象化: Goのsyscall
パッケージは、OS固有のシステムコールをGoの関数として抽象化しています。このコミットでは、GoのPipe
関数が内部的にpipe2
を呼び出す代わりにpipe
を呼び出すように変更されました。これにより、GoのユーザーはPipe
関数を呼び出すだけで、OSのバージョンに関わらず適切なパイプ作成メカニズムが利用されるようになります。
この変更は、Go言語が多様なOS環境で安定して動作するための、地道ながらも重要な互換性維持の取り組みの一環と言えます。
コアとなるコードの変更箇所
このコミットでは、以下の3つのファイルが変更されています。
src/pkg/syscall/syscall_netbsd.go
src/pkg/syscall/zsyscall_netbsd_386.go
src/pkg/syscall/zsyscall_netbsd_amd64.go
src/pkg/syscall/syscall_netbsd.go
このファイルは、NetBSD固有のシステムコールに関するGo言語のラッパー関数を定義しています。
--- a/src/pkg/syscall/syscall_netbsd.go
+++ b/src/pkg/syscall/syscall_netbsd.go
@@ -118,15 +118,12 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,\
return origlen - len(buf), count, names
}
-//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
+//sysnb pipe() (fd1 int, fd2 int, err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
- var pp [2]_C_int
- err = pipe2(&pp, 0)
- p[0] = int(pp[0])
- p[1] = int(pp[1])
+ p[0], p[1], err = pipe()
return
}
//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
が削除され、//sysnb pipe() (fd1 int, fd2 int, err error)
が追加されました。これは、Goのビルドシステムがシステムコールを生成する際に使用するディレクティブです。pipe2
システムコールへのバインディングを削除し、pipe
システムコールへの新しいバインディングを指示しています。Pipe
Go関数内で、pipe2
を呼び出していた部分が削除され、代わりに新しく定義されたpipe()
関数(Goの内部的なシステムコールラッパー)を呼び出すように変更されました。var pp [2]_C_int
とerr = pipe2(&pp, 0)
の行が削除されました。p[0] = int(pp[0])
とp[1] = int(pp[1])
の行が削除されました。p[0], p[1], err = pipe()
の行が追加されました。これにより、pipe()
システムコールが返す2つのファイルディスクリプタとエラーを直接Goのp
スライスに代入しています。
src/pkg/syscall/zsyscall_netbsd_386.go
および src/pkg/syscall/zsyscall_netbsd_amd64.go
これらのファイルは、Goのビルドプロセスによって自動生成される、NetBSDの386およびAMD64アーキテクチャ向けのシステムコールラッパーです。
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -253,8 +253,10 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe2(p *[2]_C_int, flags _C_int) (err error) {
- _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+func pipe() (fd1 int, fd2 int, err error) {
+ r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ fd1 = int(r0)
+ fd2 = int(r1)
if e1 != 0 {
err = e1
}
src/pkg/syscall/zsyscall_netbsd_amd64.go
も同様の変更です。
func pipe2(...)
の定義が削除され、func pipe(...)
の定義が追加されました。RawSyscall
の呼び出しがSYS_PIPE2
からSYS_PIPE
に変更されました。pipe2
はポインタとフラグを引数に取っていましたが、pipe
は引数を取らず、戻り値として2つのファイルディスクリプタとエラーを返します。これに合わせて、RawSyscall
の戻り値の処理も変更されています。r0
とr1
がそれぞれfd1
とfd2
にマッピングされています。
これらの変更により、Goのsyscall
パッケージはNetBSD上でパイプを作成する際に、古いpipe
システムコールを呼び出すように完全に切り替わりました。
コアとなるコードの解説
このコミットの核心は、Go言語のsyscall
パッケージがNetBSD上でパイプを作成する際のシステムコール呼び出しの変更にあります。
syscall_netbsd.go
の変更
このファイルは、Goのsyscall
パッケージがNetBSD固有のシステムコールをどのようにラップしているかを示しています。
元のコードでは、GoのPipe
関数は内部的にpipe2
システムコールを呼び出していました。
//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
err = pipe2(&pp, 0) // pipe2システムコールを呼び出し
p[0] = int(pp[0])
p[1] = int(pp[1])
return
}
ここで注目すべきは、pipe2(&pp, 0)
という呼び出しです。pipe2
は通常、パイプの動作を制御するためのフラグを第2引数に取りますが、ここでは0
が渡されています。これは、pipe2
をフラグなしで呼び出すことで、従来のpipe
システムコールと同じ挙動を期待していることを意味します。
変更後のコードでは、pipe2
の代わりにpipe
システムコールを直接呼び出すように変更されています。
//sysnb pipe() (fd1 int, fd2 int, err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
p[0], p[1], err = pipe() // pipeシステムコールを呼び出し
return
}
//sysnb pipe() (fd1 int, fd2 int, err error)
というコメントは、Goのビルドツール(mksyscall
など)に対する指示で、引数なしでpipe
システムコールを呼び出し、2つの整数(ファイルディスクリプタ)とエラーを返すGo関数を生成するように伝えています。
この変更により、GoのPipe
関数は、NetBSD 5のような古い環境でも確実に利用できるpipe
システムコールを使用するようになり、互換性が向上しました。機能的にはpipe2
をフラグなしで呼び出すのと同等であるため、Goプログラムの動作に影響はありません。
zsyscall_netbsd_386.go
および zsyscall_netbsd_amd64.go
の変更
これらのファイルは、Goのsyscall
パッケージが実際にOSのシステムコールを呼び出すための低レベルなラッパー関数を含んでいます。これらは通常、mksyscall
などのツールによって自動生成されます。
元のコードでは、pipe2
というGo関数が定義されており、これがSYS_PIPE2
というシステムコール番号を使ってRawSyscall
を呼び出していました。
func pipe2(p *[2]_C_int, flags _C_int) (err error) {
_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
// ... エラー処理 ...
}
変更後、pipe2
関数は削除され、代わりにpipe
関数が定義されました。このpipe
関数はSYS_PIPE
システムコールを呼び出します。
func pipe() (fd1 int, fd2 int, err error) {
r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
fd1 = int(r0)
fd2 = int(r1)
// ... エラー処理 ...
}
RawSyscall
は、GoがOSのシステムコールを直接呼び出すための最も低レベルな関数です。SYS_PIPE2
やSYS_PIPE
は、それぞれのシステムコールに対応するOS固有の番号です。
pipe2
は引数としてポインタとフラグを受け取っていましたが、pipe
は引数を取らず、戻り値として2つのファイルディスクリプタ(r0
, r1
)を返します。この変更は、Goのsyscall
パッケージがOSのpipe
システムコールのシグネチャに合わせて、低レベルな呼び出しを調整したことを示しています。
これらの自動生成されるファイルの変更は、syscall_netbsd.go
で指定された//sysnb
ディレクティブの変更の結果として発生します。つまり、Goのビルドツールが、新しいディレクティブに基づいて適切なシステムコールラッパーを再生成したということです。
関連リンク
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - NetBSDのシステムコールに関する情報 (一般的な情報源): https://man.netbsd.org/ (manページを参照)
- Go言語の変更リスト (Gerrit): https://golang.org/cl/6268045
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- UNIX系OSにおける
pipe()
とpipe2()
システムコールのmanページ (例: Linuxのmanページ): - NetBSDの公式ウェブサイト: https://www.netbsd.org/
- Go言語のシステムコール生成に関する情報 (Goの内部ドキュメントやソースコードコメント):
src/cmd/go/mksyscall.go
など - プロセス間通信 (IPC) に関する一般的な情報源 (オペレーティングシステム概論など)
- Go言語のクロスプラットフォーム開発に関する情報I have retrieved the commit information and have a good understanding of the changes. I will now generate the detailed technical explanation in Markdown format, following all the specified sections and requirements. I will not save it to a file, only print to standard output.
# [インデックス 13272] ファイルの概要
このコミットは、Go言語の`syscall`パッケージにおけるNetBSD向けのパイプ作成処理を改善するものです。具体的には、`pipe2`システムコールから`pipe`システムコールへの変更を行い、NetBSD 5との互換性を向上させています。
## コミット
commit 677cdb800d85025b01173e44925189c822869168 Author: Benny Siegert bsiegert@gmail.com Date: Tue Jun 5 01:29:34 2012 +1000
syscall: use pipe instead of pipe2 on NetBSD
pipe2 is equivalent to pipe with flags set to 0.
However, pipe2 was only added recently. Using pipe
instead improves compatibility with NetBSD 5.
R=jsing
CC=golang-dev
https://golang.org/cl/6268045
## GitHub上でのコミットページへのリンク
[https://github.com/golang/go/commit/677cdb800d85025b01173e44925189c822869168](https://github.com/golang/go/commit/677cdb800d85025b01173e44925189c822869168)
## 元コミット内容
`syscall: use pipe instead of pipe2 on NetBSD`
このコミットは、NetBSD上でパイプを作成する際に`pipe2`システムコールではなく`pipe`システムコールを使用するように変更します。`pipe2`はフラグを0に設定した場合に`pipe`と同等ですが、`pipe2`は比較的新しく追加されたシステムコールであるため、`pipe`を使用することでNetBSD 5との互換性が向上します。
## 変更の背景
Go言語は、様々なオペレーティングシステム(OS)上で動作するように設計されています。そのため、各OSのシステムコールを適切に利用し、互換性を維持することが重要です。このコミットの背景には、NetBSDという特定のOSバージョン(NetBSD 5)におけるシステムコールの可用性の問題がありました。
`pipe2`システムコールは、従来の`pipe`システムコールに加えて、パイプの作成時に追加のフラグ(例えば、`O_NONBLOCK`や`O_CLOEXEC`など)を指定できる機能を提供します。これにより、パイプの動作をより細かく制御できるようになります。しかし、この`pipe2`は比較的新しいシステムコールであり、古いバージョンのOSでは利用できない場合があります。
NetBSD 5は、この`pipe2`システムコールがまだ導入されていなかった、あるいは安定していなかった時期のバージョンであると考えられます。Goの`syscall`パッケージが`pipe2`を使用するように実装されていた場合、NetBSD 5上でGoプログラムがパイプを作成しようとすると、`pipe2`システムコールが見つからない、または正しく動作しないためにエラーが発生する可能性がありました。
この互換性の問題を解決するため、開発者は`pipe2`の使用を避け、より広く利用可能な`pipe`システムコールに切り替えることを決定しました。コミットメッセージにある「`pipe2` is equivalent to `pipe` with flags set to 0」という記述は、`pipe2`がフラグなしで呼び出された場合、その機能が`pipe`と全く同じであることを示しており、機能的な損失がないことを強調しています。
## 前提知識の解説
### 1. システムコール (System Call)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。プログラムがファイルを開いたり、メモリを割り当てたり、ネットワーク通信を行ったりする際には、直接ハードウェアを操作するのではなく、OSのシステムコールを呼び出します。これにより、OSはシステムリソースを管理し、複数のプログラムが安全かつ効率的に動作できるようにします。
Go言語では、`syscall`パッケージがOSのシステムコールへの低レベルなアクセスを提供します。これにより、GoプログラムはOS固有の機能を利用したり、パフォーマンスが重要な処理を行ったりすることができます。
### 2. パイプ (Pipe)
パイプは、プロセス間通信(IPC: Inter-Process Communication)の一種で、一方のプロセスが書き込んだデータを、もう一方のプロセスが読み取ることができる単方向のデータストリームです。UNIX系OSでは、シェルコマンドの`|`(パイプ)演算子でおなじみです。
プログラム内でパイプを作成するには、通常、`pipe()`または`pipe2()`といったシステムコールを使用します。これらのシステムコールは、2つのファイルディスクリプタ(通常は整数値)を返します。1つはパイプへの書き込み用、もう1つはパイプからの読み取り用です。
### 3. `pipe()` システムコール
`pipe()`システムコールは、最も基本的なパイプ作成関数です。通常、以下のようなシグネチャを持ちます(C言語の場合):
```c
int pipe(int pipefd[2]);
この関数は、pipefd
という2要素の整数配列を受け取ります。成功すると、pipefd[0]
には読み取り用のファイルディスクリプタが、pipefd[1]
には書き込み用のファイルディスクリプタが格納されます。エラーが発生した場合は-1を返します。
pipe()
で作成されたパイプは、デフォルトでブロッキングI/Oモードで動作し、O_CLOEXEC
(exec
系システムコールで子プロセスにファイルディスクリプタが継承されないようにするフラグ)は設定されません。これらの挙動を変更するには、別途fcntl()
システムコールなどを使用する必要があります。
4. pipe2()
システムコール
pipe2()
システムコールは、pipe()
の拡張版です。以下のようなシグネチャを持ちます(C言語の場合):
int pipe2(int pipefd[2], int flags);
pipe2()
はpipefd
配列に加えて、flags
引数を受け取ります。このflags
引数を使用することで、パイプの作成時にO_NONBLOCK
(非ブロッキングI/O)やO_CLOEXEC
などのフラグを原子的に設定できます。これにより、pipe()
でパイプを作成した後にfcntl()
を呼び出す必要がなくなり、競合状態のリスクを減らすことができます。
コミットメッセージにある「pipe2
is equivalent to pipe
with flags set to 0」とは、pipe2(pipefd, 0)
と呼び出すことが、pipe(pipefd)
と呼び出すことと機能的に同じであることを意味します。
5. NetBSD
NetBSDは、BSD系UNIXオペレーティングシステムの一つで、高い移植性を特徴としています。様々なハードウェアアーキテクチャ上で動作するように設計されており、組み込みシステムからサーバーまで幅広い用途で利用されています。Go言語は、このような多様なOS環境をサポートしており、NetBSDもその対象の一つです。
このコミットは、NetBSDの特定のバージョン(NetBSD 5)におけるシステムコールの実装状況を考慮したものであり、Go言語が異なるOSバージョン間での互換性をどのように維持しているかを示す良い例です。
技術的詳細
このコミットの技術的な核心は、Go言語のsyscall
パッケージがNetBSD上でパイプを作成する際に、どのシステムコールを使用するかという点にあります。
元の実装では、Goのsyscall
パッケージはNetBSD向けにpipe2
システムコールを利用していました。これは、pipe2
がpipe
よりも新しい機能を提供し、パイプ作成時にフラグを原子的に設定できるという利点があるため、より現代的なアプローチと見なされていた可能性があります。
しかし、NetBSD 5のような古いバージョンのOSでは、pipe2
システムコールが利用できないか、あるいはその挙動が期待通りではないという問題がありました。GoプログラムがNetBSD 5上で動作し、パイプを作成しようとすると、pipe2
の呼び出しが失敗し、プログラムのクラッシュや予期せぬエラーにつながる可能性がありました。
この問題を解決するため、コミットではpipe2
の使用を中止し、代わりにpipe
システムコールを使用するように変更されました。
pipe2
からpipe
への切り替え:pipe2
はflags
引数を取りますが、このコミットではpipe2
を呼び出す際にflags
を0
に設定していました。これは、機能的にはpipe
システムコールと全く同じ挙動を意味します。したがって、pipe2
をpipe
に置き換えても、機能的な影響は全くありません。- 互換性の向上:
pipe
システムコールはpipe2
よりも古くから存在し、より多くのOSバージョンでサポートされています。特にNetBSD 5のような古い環境では、pipe
が確実に利用できるため、この変更によってGoプログラムのNetBSD 5における互換性が大幅に向上します。 - Goの
syscall
パッケージの抽象化: Goのsyscall
パッケージは、OS固有のシステムコールをGoの関数として抽象化しています。このコミットでは、GoのPipe
関数が内部的にpipe2
を呼び出す代わりにpipe
を呼び出すように変更されました。これにより、GoのユーザーはPipe
関数を呼び出すだけで、OSのバージョンに関わらず適切なパイプ作成メカニズムが利用されるようになります。
この変更は、Go言語が多様なOS環境で安定して動作するための、地道ながらも重要な互換性維持の取り組みの一環と言えます。
コアとなるコードの変更箇所
このコミットでは、以下の3つのファイルが変更されています。
src/pkg/syscall/syscall_netbsd.go
src/pkg/syscall/zsyscall_netbsd_386.go
src/pkg/syscall/zsyscall_netbsd_amd64.go
src/pkg/syscall/syscall_netbsd.go
このファイルは、NetBSD固有のシステムコールに関するGo言語のラッパー関数を定義しています。
--- a/src/pkg/syscall/syscall_netbsd.go
+++ b/src/pkg/syscall/syscall_netbsd.go
@@ -118,15 +118,12 @@ func ParseDirent(buf []byte, max int, names []string) (consumed int, count int,\
return origlen - len(buf), count, names
}
-//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
+//sysnb pipe() (fd1 int, fd2 int, err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
- var pp [2]_C_int
- err = pipe2(&pp, 0)
- p[0] = int(pp[0])
- p[1] = int(pp[1])
+ p[0], p[1], err = pipe()
return
}
//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
が削除され、//sysnb pipe() (fd1 int, fd2 int, err error)
が追加されました。これは、Goのビルドシステムがシステムコールを生成する際に使用するディレクティブです。pipe2
システムコールへのバインディングを削除し、pipe
システムコールへの新しいバインディングを指示しています。Pipe
Go関数内で、pipe2
を呼び出していた部分が削除され、代わりに新しく定義されたpipe()
関数(Goの内部的なシステムコールラッパー)を呼び出すように変更されました。var pp [2]_C_int
とerr = pipe2(&pp, 0)
の行が削除されました。p[0] = int(pp[0])
とp[1] = int(pp[1])
の行が削除されました。p[0], p[1], err = pipe()
の行が追加されました。これにより、pipe()
システムコールが返す2つのファイルディスクリプタとエラーを直接Goのp
スライスに代入しています。
src/pkg/syscall/zsyscall_netbsd_386.go
および src/pkg/syscall/zsyscall_netbsd_amd64.go
これらのファイルは、Goのビルドプロセスによって自動生成される、NetBSDの386およびAMD64アーキテクチャ向けのシステムコールラッパーです。
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -253,8 +253,10 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func pipe2(p *[2]_C_int, flags _C_int) (err error) {
- _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+func pipe() (fd1 int, fd2 int, err error) {
+ r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+ fd1 = int(r0)
+ fd2 = int(r1)
if e1 != 0 {
err = e1
}
src/pkg/syscall/zsyscall_netbsd_amd64.go
も同様の変更です。
func pipe2(...)
の定義が削除され、func pipe(...)
の定義が追加されました。RawSyscall
の呼び出しがSYS_PIPE2
からSYS_PIPE
に変更されました。pipe2
はポインタとフラグを引数に取っていましたが、pipe
は引数を取らず、戻り値として2つのファイルディスクリプタとエラーを返します。これに合わせて、RawSyscall
の戻り値の処理も変更されています。r0
とr1
がそれぞれfd1
とfd2
にマッピングされています。
これらの変更により、Goのsyscall
パッケージはNetBSD上でパイプを作成する際に、古いpipe
システムコールを呼び出すように完全に切り替わりました。
コアとなるコードの解説
このコミットの核心は、Go言語のsyscall
パッケージがNetBSD上でパイプを作成する際のシステムコール呼び出しの変更にあります。
syscall_netbsd.go
の変更
このファイルは、Goのsyscall
パッケージがNetBSD固有のシステムコールをどのようにラップしているかを示しています。
元のコードでは、GoのPipe
関数は内部的にpipe2
システムコールを呼び出していました。
//sysnb pipe2(p *[2]_C_int, flags _C_int) (err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
var pp [2]_C_int
err = pipe2(&pp, 0) // pipe2システムコールを呼び出し
p[0] = int(pp[0])
p[1] = int(pp[1])
return
}
ここで注目すべきは、pipe2(&pp, 0)
という呼び出しです。pipe2
は通常、パイプの動作を制御するためのフラグを第2引数に取りますが、ここでは0
が渡されています。これは、pipe2
をフラグなしで呼び出すことで、従来のpipe
システムコールと同じ挙動を期待していることを意味します。
変更後のコードでは、pipe2
の代わりにpipe
システムコールを直接呼び出すように変更されています。
//sysnb pipe() (fd1 int, fd2 int, err error)
func Pipe(p []int) (err error) {
if len(p) != 2 {
return EINVAL
}
p[0], p[1], err = pipe() // pipeシステムコールを呼び出し
return
}
//sysnb pipe() (fd1 int, fd2 int, err error)
というコメントは、Goのビルドツール(mksyscall
など)に対する指示で、引数なしでpipe
システムコールを呼び出し、2つの整数(ファイルディスクリプタ)とエラーを返すGo関数を生成するように伝えています。
この変更により、GoのPipe
関数は、NetBSD 5のような古い環境でも確実に利用できるpipe
システムコールを使用するようになり、互換性が向上しました。機能的にはpipe2
をフラグなしで呼び出すのと同等であるため、Goプログラムの動作に影響はありません。
zsyscall_netbsd_386.go
および zsyscall_netbsd_amd64.go
の変更
これらのファイルは、Goのsyscall
パッケージが実際にOSのシステムコールを呼び出すための低レベルなラッパー関数を含んでいます。これらは通常、mksyscall
などのツールによって自動生成されます。
元のコードでは、pipe2
というGo関数が定義されており、これがSYS_PIPE2
というシステムコール番号を使ってRawSyscall
を呼び出していました。
func pipe2(p *[2]_C_int, flags _C_int) (err error) {
_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
// ... エラー処理 ...
}
変更後、pipe2
関数は削除され、代わりにpipe
関数が定義されました。このpipe
関数はSYS_PIPE
システムコールを呼び出します。
func pipe() (fd1 int, fd2 int, err error) {
r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
fd1 = int(r0)
fd2 = int(r1)
// ... エラー処理 ...
}
RawSyscall
は、GoがOSのシステムコールを直接呼び出すための最も低レベルな関数です。SYS_PIPE2
やSYS_PIPE
は、それぞれのシステムコールに対応するOS固有の番号です。
pipe2
は引数としてポインタとフラグを受け取っていましたが、pipe
は引数を取らず、戻り値として2つのファイルディスクリプタ(r0
, r1
)を返します。この変更は、Goのsyscall
パッケージがOSのpipe
システムコールのシグネチャに合わせて、低レベルな呼び出しを調整したことを示しています。
これらの自動生成されるファイルの変更は、syscall_netbsd.go
で指定された//sysnb
ディレクティブの変更の結果として発生します。つまり、Goのビルドツールが、新しいディレクティブに基づいて適切なシステムコールラッパーを再生成したということです。
関連リンク
- Go言語の
syscall
パッケージのドキュメント: https://pkg.go.dev/syscall - NetBSDのシステムコールに関する情報 (一般的な情報源): https://man.netbsd.org/ (manページを参照)
- Go言語の変更リスト (Gerrit): https://golang.org/cl/6268045
参考にした情報源リンク
- Go言語のソースコード (GitHub): https://github.com/golang/go
- UNIX系OSにおける
pipe()
とpipe2()
システムコールのmanページ (例: Linuxのmanページ): - NetBSDの公式ウェブサイト: https://www.netbsd.org/
- Go言語のシステムコール生成に関する情報 (Goの内部ドキュメントやソースコードコメント):
src/cmd/go/mksyscall.go
など - プロセス間通信 (IPC) に関する一般的な情報源 (オペレーティングシステム概論など)
- Go言語のクロスプラットフォーム開発に関する情報