[インデックス 11988] ファイルの概要
このコミットは、Go言語の標準ライブラリにおいて、Plan 9オペレーティングシステムに特有のエラー定数 os.EPLAN9
を syscall.EPLAN9
へと移行し、それに伴う参照箇所の修正を行うものです。これにより、エラーの定義がより適切な syscall
パッケージに集約され、コードの整合性が向上するとともに、Plan 9向けのクロスビルドの問題が修正されます。
コミット
commit 03d4c7c7d79bbe7e1912f407fe1d5ddbccf0f73b
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Fri Feb 17 10:59:30 2012 +0900
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/03d4c7c7d79bbe7e1912f407fe1d5ddbccf0f73b
元コミット内容
net, os, syscall: delete os.EPLAN9
Also fixes plan9 cross-build.
R=rsc, r
CC=golang-dev
https://golang.org/cl/5675073
変更の背景
この変更の主な背景は、Go言語の標準ライブラリにおけるエラー定数の適切な配置と、Plan 9オペレーティングシステム向けのクロスビルドの修正です。
Go言語では、オペレーティングシステム固有の低レベルなエラーやシステムコールに関連する定数は通常 syscall
パッケージに定義されます。しかし、以前のバージョンでは、Plan 9に特有の「サポートされていない操作」を示すエラー EPLAN9
が os
パッケージに定義されていました。
この配置は、以下の点で問題がありました。
- 論理的な不整合:
os
パッケージはより高レベルなOS抽象化を提供しますが、EPLAN9
のような特定OSのエラーコードは、より低レベルなシステムコールインターフェースを提供するsyscall
パッケージに属するべきです。 - クロスビルドの問題:
os
パッケージに特定のOSのエラー定数が存在すると、異なるOS向けにGoプログラムをクロスコンパイルする際に、その定数が存在しない環境でビルドエラーが発生する可能性がありました。特にPlan 9は一般的なOSではないため、そのエラー定数が他のOSのビルドに影響を与えることは望ましくありませんでした。
このコミットは、EPLAN9
を os
パッケージから削除し、syscall
パッケージに移動することで、これらの問題を解決し、Go標準ライブラリの設計原則に沿った形に修正することを目的としています。
前提知識の解説
Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するというユニークな哲学を持っています。Go言語の開発者の一部はPlan 9の開発にも携わっており、Go言語の設計思想にもPlan 9の影響が見られます。Go言語は初期からPlan 9をサポート対象OSの一つとしていました。
Go言語の os
パッケージと syscall
パッケージ
os
パッケージ: Go言語のos
パッケージは、オペレーティングシステムとの基本的な相互作用を提供します。ファイル操作、プロセス管理、環境変数へのアクセスなど、OSに依存しない高レベルな抽象化を提供することを目的としています。例えば、os.Open
やos.Stat
などがあります。syscall
パッケージ:syscall
パッケージは、低レベルなシステムコールインターフェースを提供します。これは、各オペレーティングシステムが提供するネイティブなシステムコールをGoから直接呼び出すためのものです。OSごとに異なる実装を持ち、OS固有の定数や構造体、関数が含まれます。例えば、syscall.Open
やsyscall.Stat
などがあります。エラー定数も、通常はsyscall
パッケージ内でOS固有に定義されます。
Go言語のエラーハンドリング
Go言語では、エラーは error
インターフェースを実装する値として扱われます。多くの標準ライブラリ関数は、最後の戻り値として error
型を返します。エラーが発生しなかった場合は nil
を返します。
os
パッケージや syscall
パッケージで定義されるエラー定数は、特定の状況で発生する可能性のあるエラーを示すために使用されます。例えば、os.ErrNotExist
はファイルが存在しないことを示し、syscall.EINVAL
は無効な引数がシステムコールに渡されたことを示します。
技術的詳細
このコミットの技術的な核心は、os.EPLAN9
というエラー定数の定義を os
パッケージから削除し、syscall
パッケージに移動したことです。
以前は、Plan 9環境でサポートされていない操作が行われた場合に返されるエラーとして os.EPLAN9
が存在しました。これは、os
パッケージが提供する高レベルなAPIが、内部的にPlan 9の特定の機能に依存しており、それが利用できない場合にこのエラーを返すという設計になっていたためと考えられます。
しかし、EPLAN9
は「Plan 9に特有の、サポートされていない操作」という、非常にOS固有かつ低レベルな意味合いを持つエラーです。このようなエラーは、OSのシステムコール層と直接関連する syscall
パッケージで定義されるのがより適切です。syscall
パッケージは、各OSのシステムコールインターフェースを直接ラップするため、OS固有のエラー定数を保持するのに適した場所です。
この変更により、以下の影響があります。
- エラー定義の一元化:
EPLAN9
のようなOS固有のエラーがsyscall
パッケージに集約され、エラーの定義がより論理的に整理されました。 - クロスビルドの改善:
os
パッケージは、Goプログラムが動作するすべてのOSで共通のインターフェースを提供することを目指しています。os.EPLAN9
のような特定のOSにしか存在しないエラー定数がos
パッケージにあると、他のOS向けにクロスビルドする際に、その定数が未定義であるためにコンパイルエラーが発生する可能性がありました。syscall
パッケージはOSごとに異なる実装を持つことが前提であるため、そこにEPLAN9
を定義してもクロスビルドの問題は発生しません。 - 依存関係の整理:
net
パッケージ内のPlan 9固有のファイル (file_plan9.go
,iprawsock_plan9.go
など) やos/exec/lp_plan9.go
などでos.EPLAN9
を参照していた箇所がsyscall.EPLAN9
に変更されました。これにより、これらのファイルはos
パッケージではなくsyscall
パッケージに依存するようになり、依存関係がより明確になりました。 syscall/zerrors_plan9_386.go
の変更: このファイルはPlan 9 (386アーキテクチャ) 向けのエラー定数を定義するファイルです。このコミットでは、EPLAN9
を含む複数のエラー定数(EINVAL
,ENOTDIR
,ENOENT
,EEXIST
,EIO
,ENAMETOOLONG
,EPERM
)がerrors.New
を使ってvar
として定義されるようになりました。これにより、これらのエラーがGoのerror
インターフェースを実装する具体的なエラー値として利用可能になります。また、Signal
型の定義とSIGINT
,SIGKILL
定数も追加され、Plan 9におけるシグナルハンドリングの基礎が整備されています。os/signal/signal_stub.go
の追加: Plan 9環境では、一般的なUnix系OSのようなシグナルハンドリングの仕組みが異なるため、signal_stub.go
というスタブファイルが追加されました。これは、os/signal
パッケージがPlan 9向けにビルドされる際に、シグナル関連の関数が適切に処理されるようにするためのものです。enableSignal
関数が空の実装で提供されており、Plan 9ではシグナルがサポートされていないか、異なる方法で処理されることを示唆しています。
コアとなるコードの変更箇所
このコミットでは、主に以下のファイルが変更されています。
src/pkg/net/file_plan9.go
src/pkg/net/iprawsock_plan9.go
src/pkg/net/ipsock_plan9.go
src/pkg/net/lookup_plan9.go
src/pkg/net/tcpsock_plan9.go
src/pkg/net/udpsock_plan9.go
src/pkg/net/unixsock_plan9.go
src/pkg/os/exec/lp_plan9.go
src/pkg/os/signal/signal_stub.go
(新規追加)src/pkg/syscall/syscall_plan9.go
src/pkg/syscall/zerrors_plan9_386.go
主要な変更は、os.EPLAN9
の参照を syscall.EPLAN9
に変更する部分と、syscall/zerrors_plan9_386.go
で EPLAN9
を含むエラー定数を syscall
パッケージ内で定義する部分です。
例: src/pkg/net/file_plan9.go
の変更
--- a/src/pkg/net/file_plan9.go
+++ b/src/pkg/net/file_plan9.go
@@ -6,6 +6,7 @@ package net
import (
"os"
+ "syscall"
)
// FileConn returns a copy of the network connection corresponding to
@@ -13,7 +14,7 @@ import (
// finished. Closing c does not affect f, and closing f does not
// affect c.
func FileConn(f *os.File) (c Conn, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// FileListener returns a copy of the network listener corresponding
@@ -21,7 +22,7 @@ func FileConn(f *os.File) (c Conn, err error) {
// when finished. Closing c does not affect l, and closing l does not
// affect c.
func FileListener(f *os.File) (l Listener, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
// FilePacketConn returns a copy of the packet network connection
@@ -29,5 +30,5 @@ func FileListener(f *os.File) (l Listener, err error) {
// responsibility to close f when finished. Closing c does not affect
// f, and closing f does not affect c.
func FilePacketConn(f *os.File) (c PacketConn, err error) {
- return nil, os.EPLAN9
+ return nil, syscall.EPLAN9
}
例: src/pkg/syscall/zerrors_plan9_386.go
の変更
--- a/src/pkg/syscall/zerrors_plan9_386.go
+++ b/src/pkg/syscall/zerrors_plan9_386.go
@@ -4,6 +4,8 @@
package syscall
+import "errors"
+
// Constants
const (
// Invented values to support what package os expects.
@@ -22,6 +24,19 @@ const (
S_IFREG = 0x8000
S_IFLNK = 0xa000
S_IFSOCK = 0xc000
+\
+\tSIGINT = Signal(0x2)
+\tSIGKILL = Signal(0x9)
)
-// Error table
+// Errors
+var (
+\tEINVAL = errors.New("bad arg in system call")
+\tENOTDIR = errors.New("not a directory")
+\tENOENT = errors.New("file does not exist")
+\tEEXIST = errors.New("file already exists")
+\tEIO = errors.New("i/o error")
+\tENAMETOOLONG = errors.New("file name too long")
+\tEPERM = errors.New("permission denied")
+\tEPLAN9 = errors.New("not supported by plan 9")
+)
コアとなるコードの解説
上記のコード変更は、Go言語の標準ライブラリにおけるエラーハンドリングとOS抽象化の設計原則を強化するものです。
net
パッケージ内のPlan 9固有のファイル群 (file_plan9.go
, iprawsock_plan9.go
など) では、FileConn
, FileListener
, FilePacketConn
などの関数が、Plan 9環境ではサポートされていない機能に対して os.EPLAN9
を返していました。これらの関数は、ファイルディスクリプタからネットワーク接続を生成するような、OSの低レベルな機能に密接に関連しています。このコミットでは、これらの関数が返すエラーを syscall.EPLAN9
に変更することで、エラーの発生源が syscall
パッケージに由来することを明確にしています。これは、os
パッケージが提供する高レベルな抽象化のレイヤーではなく、より低レベルなシステムコール層で発生するエラーであることを示唆しています。
src/pkg/syscall/zerrors_plan9_386.go
の変更は、Plan 9 (386アーキテクチャ) 向けに、Goの error
インターフェースを実装する具体的なエラー値を syscall
パッケージ内で定義したものです。以前はコメントアウトされていた Error table
の部分が、var
宣言と errors.New
を用いて実際のGoのエラー値として定義されました。これにより、syscall.EINVAL
や syscall.EPLAN9
などのエラーを、Goの標準的なエラーハンドリングメカニズム (if err == syscall.EPLAN9
) で直接比較できるようになります。
また、syscall/syscall_plan9.go
に Signal
型が追加され、Signal
インターフェースを実装することで、Goの os.Signal
型との互換性を持たせています。これは、Plan 9におけるシグナル処理の基盤を整備するものです。
src/pkg/os/signal/signal_stub.go
の追加は、Plan 9が他のUnix系OSとは異なるシグナル処理モデルを持つため、os/signal
パッケージがPlan 9向けにビルドされる際に、シグナル関連の関数が適切に処理されるようにするためのものです。このスタブファイルは、Plan 9ではシグナルがサポートされていないか、異なる方法で処理されることを示唆しており、クロスビルド時のエラーを回避する役割も果たします。
これらの変更は、Go言語の標準ライブラリが、各OSの特性を尊重しつつ、よりクリーンで一貫性のあるAPIを提供するための継続的な努力の一環と言えます。
関連リンク
- Go言語の
os
パッケージ: https://pkg.go.dev/os - Go言語の
syscall
パッケージ: https://pkg.go.dev/syscall - Plan 9 from Bell Labs: https://9p.io/plan9/
- Go言語のエラーハンドリング: https://go.dev/blog/error-handling-and-go
参考にした情報源リンク
- https://github.com/golang/go/commit/03d4c7c7d79bbe7e1912f407fe1d5ddbccf0f73b
- Go言語の公式ドキュメント (pkg.go.dev)
- Plan 9 from Bell Labsの公式ウェブサイト
- Go言語のエラーハンドリングに関するブログ記事