[インデックス 1504] ファイルの概要
このコミットは、Go言語の標準ライブラリにおけるsyscall
パッケージとその関連コードベース全体にわたる大規模なリファクタリングです。主な目的は、Go言語の命名規則(エクスポートされる識別子は大文字で始まる)に準拠させるために、システムコール関数や構造体のフィールド名を一貫して変更することです。これにより、syscall
パッケージのAPIがより明確になり、外部から利用しやすくなります。
コミット
- コミットハッシュ:
1a91b9a8a9b118536db775e215c09091fd72c35f
- Author: Rob Pike r@golang.org
- Date: Fri Jan 16 11:36:44 2009 -0800
- 変更ファイル数: 21
- 変更行数: 298行追加, 299行削除, 336行変更 (実質的な変更は337行)
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1a91b9a8a9b118536db775e215c09091fd72c35f
元コミット内容
casify syscall and sequelae
R=rsc
DELTA=337 (0 added, 1 deleted, 336 changed)
OCL=22950
CL=22950
変更の背景
Go言語では、パッケージ外からアクセス可能な(エクスポートされる)識別子(関数、変数、型、構造体フィールドなど)は、その名前が大文字で始まる必要があります。一方、パッケージ内部でのみ使用される(エクスポートされない)識別子は、小文字で始まります。
このコミットが行われた2009年1月時点のGo言語はまだ開発初期段階であり、APIの設計や命名規則の統一が進行中でした。syscall
パッケージは、オペレーティングシステムの低レベルな機能にアクセスするための重要なインターフェースを提供しますが、初期の実装では、Goの命名規則に完全に準拠していない関数名や構造体フィールド名が存在していました。
このコミットの背景には、syscall
パッケージのAPIをGo言語の標準的な命名規則に合わせ、外部パッケージからシステムコールを呼び出す際の整合性と使いやすさを向上させるという明確な意図があります。これにより、Goのコードベース全体の一貫性が保たれ、開発者がより直感的にAPIを理解し、利用できるようになります。
前提知識の解説
Go言語の命名規則とエクスポート
Go言語における識別子の可視性(エクスポート)は、その名前の最初の文字が大文字か小文字かによって決まります。
- 大文字で始まる識別子: パッケージ外からアクセス可能です。これらは「エクスポートされた」識別子と呼ばれ、他のパッケージからインポートして利用できます。例えば、
fmt.Println
のPrintln
はエクスポートされた関数です。 - 小文字で始まる識別子: その識別子が定義されているパッケージ内でのみアクセス可能です。これらは「エクスポートされていない」識別子と呼ばれ、パッケージの内部実装の詳細を隠蔽するために使用されます。
この規則は、関数、変数、定数、型、構造体のフィールドなど、すべての識別子に適用されます。
システムコール (Syscall)
システムコールは、オペレーティングシステム(OS)のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイル操作(開く、読み書き、閉じる)、プロセス管理(プロセスの作成、終了)、ネットワーク通信(ソケットの作成、接続、データの送受信)など、OSの機能に直接アクセスするために使用されます。
Go言語のsyscall
パッケージは、これらのシステムコールをGoプログラムから呼び出すためのラッパーを提供します。これにより、GoプログラムはOSの低レベルな機能にアクセスできますが、通常はより高レベルな標準ライブラリ(例: os
パッケージやnet
パッケージ)を介して間接的に利用されます。
構造体とフィールド
Go言語では、関連するデータをまとめるために構造体(struct
)が使用されます。構造体内の個々のデータ要素は「フィールド」と呼ばれます。構造体のフィールドも、その名前の最初の文字が大文字か小文字かによって、エクスポートされるかどうかが決まります。エクスポートされたフィールドは、構造体のインスタンスを介してパッケージ外から直接アクセスできます。
fd
(File Descriptor)
ファイルディスクリプタ(File Descriptor, FD)は、Unix系OSにおいて、開かれたファイルやソケット、パイプなどのI/Oリソースを識別するためにカーネルが割り当てる非負の整数です。プログラムはファイルディスクリプタを使って、対応するリソースに対して読み書きなどの操作を行います。
Sockaddr
Sockaddr
は、ソケット通信において、ネットワークアドレス(IPアドレスとポート番号など)を表現するための汎用的な構造体です。OSによって具体的な構造は異なりますが、通常はアドレスファミリー(IPv4, IPv6など)とアドレス情報を含みます。
Kevent
(kqueue)
kqueue
は、macOSやFreeBSDなどのBSD系OSで利用される、効率的なイベント通知メカニズムです。ファイルI/O、ソケットI/O、プロセス状態の変化など、様々な種類のイベントを監視し、発生したイベントをアプリケーションに通知します。Kevent
は、kqueue
システムコールで使用されるイベント情報を記述するための構造体です。
Timeval
/ Timespec
これらは、時間値を表現するための構造体です。
Timeval
: 秒とマイクロ秒(100万分の1秒)で時間を表します。Timespec
: 秒とナノ秒(10億分の1秒)で時間を表します。 システムコールによっては、タイムアウト値や時刻情報をこれらの構造体で渡す必要があります。
Stat
Stat
は、ファイルやディレクトリのメタデータ(サイズ、パーミッション、最終更新時刻など)を格納するための構造体です。stat()
システムコールなどによって取得されます。
技術的詳細
このコミットの核心は、Go言語の命名規則に準拠させるための識別子名の変更です。具体的には、以下の2種類の変更が広範囲にわたって適用されています。
-
システムコール関数のエクスポート:
src/lib/syscall
ディレクトリ内のファイルで定義されている多くのシステムコールラッパー関数が、小文字で始まる名前(例:syscall.open
,syscall.close
,syscall.read
,syscall.write
)から、大文字で始まる名前(例:syscall.Open
,syscall.Close
,syscall.Read
,syscall.Write
)に変更されました。 これは、これらの関数がsyscall
パッケージの外部(例:os
パッケージやnet
パッケージ)から利用されることを意図しているため、Goのエクスポート規則に従って公開APIとしてマークされたことを意味します。 -
構造体フィールドのエクスポートと内部変数名の調整:
src/lib/syscall/types_amd64_darwin.go
やsrc/lib/syscall/types_amd64_linux.go
などのファイルで定義されている構造体(例:Sockaddr
,Kevent
,Timeval
,Stat
,Rusage
,Linger
,EpollEvent
)のフィールド名も、同様に小文字から大文字に変更されました(例:sa.family
からsa.Family
、tv.sec
からtv.Sec
)。 これにより、これらの構造体のフィールドがパッケージ外から直接アクセス可能になり、APIの使いやすさが向上します。 一方で、パッケージ内部でのみ使用される変数や定数(例:ErrorTab
からerrorTab
、NameBufsize
からnameBufsize
)は、Goの命名規則に従って小文字で始まる名前に変更され、内部実装の詳細として扱われるようになりました。
これらの変更は、doc/progs/fd.go
、src/lib/net/
以下のファイル、src/lib/os/
以下のファイル、そしてsrc/lib/syscall/
以下のファイルなど、syscall
パッケージを利用する広範なコードベースに波及しています。これは、syscall
パッケージがGoの低レベルなI/O操作やネットワーク操作の基盤となっているため、そのAPIの変更が多くの依存箇所に影響を与えることを示しています。
このリファクタリングは、Go言語のAPI設計における一貫性と可読性を確立する上で重要なステップでした。これにより、Goの標準ライブラリがより成熟し、開発者にとって予測可能で使いやすいものとなる基盤が築かれました。
コアとなるコードの変更箇所
このコミットでは、多数のファイルで同様のパターンで識別子名が変更されています。以下に代表的な変更箇所をいくつか示します。
-
doc/progs/fd.go
:syscall
パッケージの関数呼び出しが小文字から大文字に変更されています。--- a/doc/progs/fd.go +++ b/doc/progs/fd.go @@ -28,7 +28,7 @@ export var ( ) export func Open(name string, mode int64, perm int64) (fd *FD, err *os.Error) { - r, e := syscall.open(name, mode, perm); + r, e := syscall.Open(name, mode, perm); return newFD(r, name), os.ErrnoToError(e) } @@ -36,7 +36,7 @@ func (fd *FD) Close() *os.Error { if fd == nil { return os.EINVAL } - r, e := syscall.close(fd.fildes); + r, e := syscall.Close(fd.fildes); fd.fildes = -1; // so it can't be closed again return nil } @@ -45,7 +45,7 @@ func (fd *FD) Read(b []byte) (ret int, err *os.Error) { if fd == nil { return -1, os.EINVAL } - r, e := syscall.read(fd.fildes, &b[0], int64(len(b))); + r, e := syscall.Read(fd.fildes, &b[0], int64(len(b))); return int(r), os.ErrnoToError(e) } @@ -53,7 +53,7 @@ func (fd *FD) Write(b []byte) (ret int, err *os.Error) { if fd == nil { return -1, os.EINVAL } - r, e := syscall.write(fd.fildes, &b[0], int64(len(b))); + r, e := syscall.Write(fd.fildes, &b[0], int64(len(b))); return int(r), os.ErrnoToError(e) }
-
src/lib/syscall/file_darwin.go
: システムコールラッパー関数の定義が小文字から大文字に変更されています。また、内部定数名も変更されています。--- a/src/lib/syscall/file_darwin.go +++ b/src/lib/syscall/file_darwin.go @@ -11,10 +11,10 @@ import ( "unsafe"; ) -const NameBufsize = 512 +const nameBufsize = 512 -export func open(name string, mode int64, perm int64) (ret int64, errno int64) { - var namebuf [NameBufsize]byte; +export func Open(name string, mode int64, perm int64) (ret int64, errno int64) { + var namebuf [nameBufsize]byte; if !StringToBytes(namebuf, name) { return -1, ENAMETOOLONG } @@ -22,8 +22,8 @@ export func open(name string, mode int64, perm int64) (ret int64, errno int64) { return r1, err; } -export func creat(name string, perm int64) (ret int64, errno int64) { - var namebuf [NameBufsize]byte; +export func Creat(name string, perm int64) (ret int64, errno int64) { + var namebuf [nameBufsize]byte; if !StringToBytes(namebuf, name) { return -1, ENAMETOOLONG }
-
src/lib/syscall/types_amd64_darwin.go
: 構造体のフィールド名が小文字から大文字に変更されています。また、構造体名自体もStat
からStat_t
、Kevent
からKevent_t
に変更されています。--- a/src/lib/syscall/types_amd64_darwin.go +++ b/src/lib/syscall/types_amd64_darwin.go @@ -11,35 +11,35 @@ package syscall // Time export type Timespec struct { - sec int64; - nsec uint64; + Sec int64; + Nsec uint64; } export type Timeval struct { - sec int64; - usec uint32; + Sec int64; + Usec uint32; } // Processes export type Rusage struct { - utime Timeval; - stime Timeval; - maxrss int64; - ixrss int64; - idrss int64; - isrss int64; - minflt int64; - majflt int64; - nswap int64; - inblock int64; - oublock int64; - msgsnd int64; - msgrcv int64; - nsignals int64; - nvcsw int64; - nivcsw int64; + Utime Timeval; + Stime Timeval; + Maxrss int64; + Ixrss int64; + Idrss int64; + Isrss int64; + Minflt int64; + Majflt int64; + Nswap int64; + Inblock int64; + Oublock int64; + Msgsnd int64; + Msgrcv int64; + Nsignals int64; + Nvcsw int64; + Nivcsw int64; } @@ -67,26 +67,26 @@ export const ( FD_CLOEXEC = 1; ) -export type Stat struct { - dev uint32; - mode uint16; - nlink uint16; - ino uint64; - uid uint32; - gid uint32; - rdev uint32; - pad1 uint32; - atime Timespec; - mtime Timespec; - ctime Timespec; - birthtime Timespec; - size uint64; - blocks uint64; - blksize uint32; - flags uint32; - gen uint32; - lspare uint32; - qspare [2]uint64; +export type Stat_t struct { + Dev uint32; + Mode uint16; + Nlink uint16; + Ino uint64; + Uid uint32; + Gid uint32; + Rdev uint32; + Pad1 uint32; + Atime Timespec; + Mtime Timespec; + Ctime Timespec; + Birthtime Timespec; + Size uint64; + Blocks uint64; + Blksize uint32; + Flags uint32; + Gen uint32; + Lspare uint32; + Qspare [2]uint64; } @@ -128,41 +128,41 @@ export const ( ) export type SockaddrUnix struct { - len byte; - family byte; - path [104]byte + Len byte; + Family byte; + Path [104]byte } export const SizeofSockaddrUnix = 106 export type SockaddrInet4 struct { - len byte; - family byte; - port [2]byte; - addr [4]byte; - zero [8]byte + Len byte; + Family byte; + Port [2]byte; + Addr [4]byte; + Zero [8]byte } export const SizeofSockaddrInet4 = 16 export type SockaddrInet6 struct { - len byte; - family byte; - port [2]byte; - flowinfo [4]byte; - addr [16]byte; - scopeid [4]byte; + Len byte; + Family byte; + Port [2]byte; + Flowinfo [4]byte; + Addr [16]byte; + Scopeid [4]byte; } export const SizeofSockaddrInet6 = 28 export type Sockaddr struct { - len byte; - family byte; - opaque [126]byte + Len byte; + Family byte; + Opaque [126]byte } export const SizeofSockaddr = 128 export type Linger struct { - yes int32; - sec int32; + Yes int32; + Sec int32; } @@ -201,12 +201,12 @@ export const ( EV_ERROR = 0x4000 ) -export type Kevent struct { - ident int64; - filter int16; - flags uint16; - fflags uint32; - data int64; - udata int64; +export type Kevent_t struct { + Ident int64; + Filter int16; + Flags uint16; + Fflags uint32; + Data int64; + Udata int64; }
コアとなるコードの解説
上記の変更は、Go言語の設計思想と密接に関連しています。
-
syscall.open
からsyscall.Open
への変更: これは、syscall
パッケージ内のopen
関数が、パッケージ外部から利用されることを意図しているため、Goのエクスポート規則に従って名前が大文字に変更されたことを意味します。同様に、close
,read
,write
などの基本的なシステムコールラッパーもすべてエクスポートされました。これにより、os
パッケージやnet
パッケージのような上位レイヤーのパッケージが、syscall
パッケージの公開APIとしてこれらの関数を安全に呼び出せるようになります。 -
sa.family
からsa.Family
への変更:Sockaddr
構造体(およびその派生構造体)のフィールド名が小文字から大文字に変更されたのは、これらのフィールドが構造体の公開インターフェースの一部として外部からアクセスされることを意図しているためです。例えば、ネットワークアドレスのファミリー(AF_INET
やAF_INET6
など)やポート番号、IPアドレスなどの情報は、ソケット通信を行う上で外部から設定・参照される必要があるため、エクスポートされるべきです。 -
ErrorTab
からerrorTab
への変更:src/lib/os/os_error.go
におけるErrorTab
やErrorStringTab
のような内部的なマップ変数が、小文字で始まるerrorTab
やerrorStringTab
に変更されました。これは、これらの変数がos
パッケージの内部実装の詳細であり、外部から直接アクセスされるべきではないことを示しています。Goの命名規則に従うことで、APIの利用者はどの識別子が公開されているか、どの識別子が内部実装であるかを一目で判断できるようになります。 -
Stat
からStat_t
、Kevent
からKevent_t
への変更: 一部の構造体名に_t
サフィックスが追加されています。これは、C言語のシステムプログラミングにおける慣習(型定義に_t
を付ける)を反映している可能性があります。Goのsyscall
パッケージはOSのC言語APIをラップしているため、このような命名が採用されたと考えられます。これにより、Goの型とCの型との対応関係がより明確になります。
これらの変更は、単なる名前の変更以上の意味を持ちます。それは、Go言語のAPI設計原則、特に「エクスポート」の概念をコードベース全体に徹底し、ライブラリの使いやすさと保守性を向上させるための重要なステップでした。これにより、Goの標準ライブラリは、その後の発展において一貫性のある堅牢な基盤を持つことになります。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
- Go言語の命名規則に関する公式ガイドライン (Effective Go): https://go.dev/doc/effective_go#names
syscall
パッケージのドキュメント (現在のバージョン): https://pkg.go.dev/syscall
参考にした情報源リンク
- Go言語の公式ドキュメント (Effective Go)
- Go言語の
syscall
パッケージのソースコード (コミット時点および現在のバージョン) - Unix系OSのシステムコールに関する一般的な知識
- ファイルディスクリプタ、ソケットアドレス、kqueueなどの概念に関する一般的なプログラミング知識
- GitHubのコミット履歴と差分表示