[インデックス 15473] ファイルの概要
このコミットは、Go言語の実験的なSSA (Static Single Assignment) パッケージ exp/ssa
における、BSD系OSでの動作不良(breakage)を修正するものです。具体的には、ディレクトリの内容を読み取るためのシステムコールとして、Linux固有の syscall.Getdents
の代わりに、よりポータブルな syscall.ReadDirent
を使用するように変更しています。
コミット
commit 877153f04aef18d25757ad3bf4b097460c7c4699
Author: Alan Donovan <adonovan@google.com>
Date: Wed Feb 27 17:00:02 2013 -0500
exp/ssa: fix *bsd breakage.
Use portable ReadDirent, not linux Getdents.
R=gri
TBR=gri
CC=golang-dev
https://golang.org/cl/7405051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/877153f04aef18d25757ad3bf4b097460c7c4699
元コミット内容
Go言語の実験的なSSAパッケージにおいて、BSD系OSで発生していた不具合を修正しました。この修正は、Linux固有の syscall.Getdents
システムコールではなく、よりポータブルな syscall.ReadDirent
を使用するように変更することで実現されました。
変更の背景
このコミットの背景には、Go言語の exp/ssa
パッケージが、異なるオペレーティングシステム間でのシステムコール互換性の問題に直面していたことがあります。特に、ディレクトリの内容を読み取るためのシステムコール Getdents
はLinuxに特化したものであり、FreeBSDやOpenBSDなどのBSD系OSでは直接利用できませんでした。この非互換性が原因で、exp/ssa
パッケージがBSD環境で正しく動作しない「breakage」が発生していました。
Go言語はクロスプラットフォーム対応を重視しており、特定のOSに依存するシステムコールを直接使用することは、移植性の観点から望ましくありません。そのため、より広範なOSで利用可能な、抽象化されたシステムコールまたは同等の機能に置き換える必要がありました。このコミットは、その問題に対処し、exp/ssa
パッケージのBSD系OSでの動作を保証することを目的としています。
前提知識の解説
Go言語の syscall
パッケージ
Go言語の syscall
パッケージは、オペレーティングシステムが提供する低レベルなシステムコールへのインターフェースを提供します。これにより、Goプログラムからファイル操作、プロセス管理、ネットワーク通信など、OSカーネルの機能に直接アクセスできます。しかし、システムコールはOSによってその名称、引数、戻り値が異なるため、syscall
パッケージを直接使用するコードは、OS間の移植性に課題を抱えることがあります。
Getdents
と ReadDirent
-
Getdents
: これは主にLinuxカーネルが提供するシステムコールで、ディレクトリ内のエントリ(ファイルやサブディレクトリ)を効率的に読み取るために使用されます。getdents
は、ディレクトリの内容を特定のバッファにまとめて読み込み、そのバッファを解析することで個々のエントリ情報を取得します。このシステムコールはLinuxに特化しており、他のUnix系OS(特にBSD系)では同名のシステムコールが存在しないか、あるいは異なるインターフェースを持つことが一般的です。 -
ReadDirent
:ReadDirent
は、Go言語のsyscall
パッケージ(またはより新しいgolang.org/x/sys
パッケージ)において、ディレクトリの内容を読み取るためのよりポータブルな抽象化された関数です。これは、内部的に各OSに最適なシステムコール(Linuxではgetdents
、BSDではgetdirentries
など)を呼び出すことで、OS間の差異を吸収し、開発者がプラットフォームの違いを意識せずにディレクトリを読み取れるように設計されています。つまり、ReadDirent
は、特定のOSのシステムコールに直接依存するのではなく、複数のOSで共通のインターフェースを提供する役割を担っています。
BSD系OS
BSD (Berkeley Software Distribution) 系OSは、Unixの派生であり、FreeBSD, OpenBSD, NetBSD, macOS (Darwin) などが含まれます。これらのOSは、Linuxとは異なるカーネル設計やシステムコールインターフェースを持つことが多く、特に低レベルなシステムプログラミングにおいては、OS間の互換性を考慮する必要があります。
exp/ssa
パッケージ
exp/ssa
は、Go言語のコンパイラやツールチェインの一部として開発されていた実験的なパッケージで、プログラムの静的単一代入 (Static Single Assignment: SSA) 形式を扱うための機能を提供します。SSA形式は、コンパイラの最適化や静的解析において非常に重要な中間表現です。このパッケージは、プログラムの実行をシミュレートするインタープリタ機能も持っており、その中でファイルシステム操作(ディレクトリの読み取りなど)が必要となる場合があります。
技術的詳細
このコミットの核心は、Go言語の syscall
パッケージにおけるシステムコール選択の移植性に関する問題です。
syscall.Getdents
は、Linuxカーネルが提供する getdents
システムコールを直接ラップしたものです。このシステムコールは、ディレクトリ内のエントリを効率的に読み取るために設計されており、一度のシステムコールで複数のディレクトリエントリをバッファに格納します。しかし、この getdents
システムコールはLinux固有であり、BSD系OSには同名のシステムコールが存在しません。BSD系OSでは、ディレクトリの内容を読み取るために getdirentries
などの異なるシステムコールが使用されます。
一方、syscall.ReadDirent
は、Go言語の syscall
パッケージが提供する、より高レベルで抽象化されたディレクトリ読み取り関数です。この関数は、内部的にコンパイルターゲットとなるOSに応じて適切なシステムコール(Linuxでは getdents
、BSDでは getdirentries
など)を呼び出すように実装されています。これにより、開発者は ReadDirent
を使用することで、基盤となるOSのシステムコールの違いを意識することなく、ポータブルなコードを書くことができます。
exp/ssa/interp/external.go
ファイルは、exp/ssa
パッケージのインタープリタが外部のシステムコールをどのように扱うかを定義しています。以前は、このファイルが syscall.Getdents
を直接参照していました。これは、Linux環境では問題なく動作しますが、BSD環境では syscall.Getdents
が利用できないため、コンパイルエラーまたは実行時エラーを引き起こしていました。
このコミットでは、syscall.Getdents
への参照を削除し、代わりに syscall.ReadDirent
を使用するように変更することで、この移植性の問題を解決しています。これにより、exp/ssa
パッケージは、LinuxだけでなくBSD系OSでも正しくディレクトリの内容を読み取れるようになり、クロスプラットフォームでの動作が保証されます。
各OS固有の実装ファイル(external_plan9.go
, external_unix.go
, external_windows.go
)では、ext۰syscall۰Getdents
関数が削除され、代わりに ext۰syscall۰ReadDirent
関数が追加または修正されています。特に external_unix.go
では、ext۰syscall۰Getdents
の実装が ext۰syscall۰ReadDirent
に置き換えられ、内部で syscall.ReadDirent
を呼び出すように変更されています。これにより、Unix系のOS(LinuxやBSDを含む)で共通のインターフェースを通じてディレクトリ読み取りが可能になります。
コアとなるコードの変更箇所
このコミットでは、以下の4つのファイルが変更されています。
src/pkg/exp/ssa/interp/external.go
src/pkg/exp/ssa/interp/external_plan9.go
src/pkg/exp/ssa/interp/external_unix.go
src/pkg/exp/ssa/interp/external_windows.go
src/pkg/exp/ssa/interp/external.go
--- a/src/pkg/exp/ssa/interp/external.go
+++ b/src/pkg/exp/ssa/interp/external.go
@@ -70,7 +70,6 @@ var externals = map[string]externalFn{
"syscall.Close": ext۰syscall۰Close,
"syscall.Exit": ext۰syscall۰Exit,
"syscall.Fstat": ext۰syscall۰Fstat,
- "syscall.Getdents": ext۰syscall۰Getdents,
"syscall.Getpid": ext۰syscall۰Getpid,
"syscall.Getwd": ext۰syscall۰Getwd,
"syscall.Kill": ext۰syscall۰Kill,
@@ -78,6 +77,7 @@ var externals = map[string]externalFn{
"syscall.Open": ext۰syscall۰Open,
"syscall.ParseDirent": ext۰syscall۰ParseDirent,
"syscall.Read": ext۰syscall۰Read,
+\t"syscall.ReadDirent": ext۰syscall۰ReadDirent,
"syscall.Stat": ext۰syscall۰Stat,
"syscall.Write": ext۰syscall۰Write,
"time.Sleep": ext۰time۰Sleep,
src/pkg/exp/ssa/interp/external_plan9.go
--- a/src/pkg/exp/ssa/interp/external_plan9.go
+++ b/src/pkg/exp/ssa/interp/external_plan9.go
@@ -15,9 +15,6 @@ func ext۰syscall۰Close(fn *ssa.Function, args []value) value {
func ext۰syscall۰Fstat(fn *ssa.Function, args []value) value {
panic("syscall.Fstat not yet implemented")
}
-func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
- panic("syscall.Getdents not yet implemented")
-}
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
panic("syscall.Kill not yet implemented")
}
@@ -33,6 +30,9 @@ func ext۰syscall۰ParseDirent(fn *ssa.Function, args []value) value {
func ext۰syscall۰Read(fn *ssa.Function, args []value) value {
panic("syscall.Read not yet implemented")
}
+func ext۰syscall۰ReadDirent(fn *ssa.Function, args []value) value {
+\tpanic("syscall.ReadDirent not yet implemented")
+}
func ext۰syscall۰Stat(fn *ssa.Function, args []value) value {
panic("syscall.Stat not yet implemented")
}
src/pkg/exp/ssa/interp/external_unix.go
--- a/src/pkg/exp/ssa/interp/external_unix.go
+++ b/src/pkg/exp/ssa/interp/external_unix.go
@@ -54,12 +54,12 @@ func ext۰syscall۰Fstat(fn *ssa.Function, args []value) value {
return wrapError(err)
}
-func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
- // func GetDents(fd int, buf []byte) (n int, err error)
+func ext۰syscall۰ReadDirent(fn *ssa.Function, args []value) value {
+ // func ReadDirent(fd int, buf []byte) (n int, err error)
fd := args[0].(int)
p := args[1].([]value)
b := make([]byte, len(p))
- n, err := syscall.Getdents(fd, b)
+ n, err := syscall.ReadDirent(fd, b)
for i := 0; i < n; i++ {
p[i] = b[i]
}
src/pkg/exp/ssa/interp/external_windows.go
--- a/src/pkg/exp/ssa/interp/external_windows.go
+++ b/src/pkg/exp/ssa/interp/external_windows.go
@@ -16,9 +16,6 @@ func ext۰syscall۰Close(fn *ssa.Function, args []value) value {
func ext۰syscall۰Fstat(fn *ssa.Function, args []value) value {
panic("syscall.Fstat not yet implemented")
}
-func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
- panic("syscall.Getdents not yet implemented")
-}
func ext۰syscall۰Kill(fn *ssa.Function, args []value) value {
panic("syscall.Kill not yet implemented")
}
@@ -34,6 +31,9 @@ func ext۰syscall۰ParseDirent(fn *ssa.Function, args []value) value {
func ext۰syscall۰Read(fn *ssa.Function, args []value) value {
panic("syscall.Read not yet implemented")
}
+func ext۰syscall۰ReadDirent(fn *ssa.Function, args []value) value {
+\tpanic("syscall.ReadDirent not yet implemented")
+}
func ext۰syscall۰Stat(fn *ssa.Function, args []value) value {
panic("syscall.Stat not yet implemented")
}
コアとなるコードの解説
src/pkg/exp/ssa/interp/external.go
の変更
このファイルは、exp/ssa
インタープリタが外部の syscall
関数をどのようにマッピングするかを定義する externals
マップを含んでいます。
- "syscall.Getdents": ext۰syscall۰Getdents,
の行が削除されました。これは、Linux固有のGetdents
システムコールへの参照を完全に削除するためです。+ "syscall.ReadDirent": ext۰syscall۰ReadDirent,
の行が追加されました。これにより、よりポータブルなReadDirent
システムコールがインタープリタの外部関数として利用可能になります。
この変更により、インタープリタは Getdents
ではなく ReadDirent
を使用するように切り替わります。
src/pkg/exp/ssa/interp/external_plan9.go
, src/pkg/exp/ssa/interp/external_windows.go
の変更
これらのファイルは、それぞれPlan 9とWindows環境における syscall
関数のインタープリタ実装を提供します。
func ext۰syscall۰Getdents(...)
の定義が削除されました。これらのOSではGetdents
がサポートされていないため、以前はpanic
を発生させるだけのスタブ実装でした。func ext۰syscall۰ReadDirent(...)
の定義が追加されました。これらのOSでもReadDirent
はまだ実装されておらず、同様にpanic
を発生させるスタブ実装となっています。これは、ReadDirent
がこれらのプラットフォームでまだ完全にサポートされていないことを示していますが、コードベース全体でGetdents
からReadDirent
への移行を進めるための一貫した変更です。
src/pkg/exp/ssa/interp/external_unix.go
の変更
このファイルは、Unix系OS(Linux、BSDなど)における syscall
関数のインタープリタ実装を提供します。
- func ext۰syscall۰Getdents(fn *ssa.Function, args []value) value {
の行が削除されました。+ func ext۰syscall۰ReadDirent(fn *ssa.Function, args []value) value {
の行が追加されました。これにより、Getdents
の実装がReadDirent
の実装に置き換えられました。- 内部の呼び出しも
- n, err := syscall.Getdents(fd, b)
から+ n, err := syscall.ReadDirent(fd, b)
に変更されました。
この変更が最も重要です。external_unix.go
はLinuxとBSDの両方をカバーするため、ここで syscall.Getdents
を syscall.ReadDirent
に置き換えることで、BSD系OSでの動作不良が修正されます。syscall.ReadDirent
は、内部的に各Unix系OSの適切なディレクトリ読み取りシステムコール(Linuxの getdents
やBSDの getdirentries
など)を呼び出すため、この変更によりコードの移植性が大幅に向上します。
全体として、このコミットは、Go言語の exp/ssa
パッケージが特定のOSに依存するシステムコールを使用する問題を解決し、よりポータブルな syscall.ReadDirent
を採用することで、クロスプラットフォーム互換性を向上させています。
関連リンク
参考にした情報源リンク
- Go言語の
syscall
パッケージとgolang.org/x/sys
パッケージに関する情報: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQH9uQJoEO_9kf_bVMJuoLddrJjBW8-XGG6g-EAyha2aVFq9oOQxmMK1mjcP-TQaK_bFOjr2xQANSSIO_d6RqAxoZ2WYaB4YjjSbXH5YWDRouRcLP8-Qx3a_1fhH4V921C4zLhGsRacrojZ5imUm syscall.ReadDirent
のBSD系OSでの実装と利用に関する情報: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF8NrbIbj0lwmyn5cESpJ9tCn47dN4gvyR3xNBdZ1NVmiNqolfAV_Z1ErS-_nNsTI7cRt2_mjI-LQiVri8EszWn2GJIZMHqyEUhGJYp4MFfeZ27sZ5eIvKdWfd19cvWQKnJ3fl-GCnn2MObxsTvjgwsJCw9PaHoAiPMf2w=syscall.Getdents
がLinux固有のシステムコールであることに関する情報: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEZ13aAe8upVduzccBmBLXFPVFzJJWwIvd958PjP874NZz4Km_SW08_Dw7Sl6APMIrimThiZFLeIgrs5Nszi6MknhdghP0620ceDvnByeyg4TsGiIjGMBljibNuEdyhyWDs950KH9b6Eecr_bID9Mo- Go言語でディレクトリを読み取るための推奨される方法(
os
パッケージ)に関する情報: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGEPA5sJIM_RfD6MvFbL3OoIEIqcjJHRkfYjNd6DHgSStLSbFOUbLyuA7Ew8BYtqBsamGew4aTCmj3QX3q1NZCW8UgmMYbz0Or5HQIcjoVU6ekJra3ioqxctIQ36uIXnosrmKJ3qy8WAtFzGxhclLIXlV5IuqyfDeSunR3MKitvLFCKLKy2duXls7t7AJDa