Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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.PrintlnPrintlnはエクスポートされた関数です。
  • 小文字で始まる識別子: その識別子が定義されているパッケージ内でのみアクセス可能です。これらは「エクスポートされていない」識別子と呼ばれ、パッケージの内部実装の詳細を隠蔽するために使用されます。

この規則は、関数、変数、定数、型、構造体のフィールドなど、すべての識別子に適用されます。

システムコール (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種類の変更が広範囲にわたって適用されています。

  1. システムコール関数のエクスポート: src/lib/syscallディレクトリ内のファイルで定義されている多くのシステムコールラッパー関数が、小文字で始まる名前(例: syscall.open, syscall.close, syscall.read, syscall.write)から、大文字で始まる名前(例: syscall.Open, syscall.Close, syscall.Read, syscall.Write)に変更されました。 これは、これらの関数がsyscallパッケージの外部(例: osパッケージやnetパッケージ)から利用されることを意図しているため、Goのエクスポート規則に従って公開APIとしてマークされたことを意味します。

  2. 構造体フィールドのエクスポートと内部変数名の調整: src/lib/syscall/types_amd64_darwin.gosrc/lib/syscall/types_amd64_linux.goなどのファイルで定義されている構造体(例: Sockaddr, Kevent, Timeval, Stat, Rusage, Linger, EpollEvent)のフィールド名も、同様に小文字から大文字に変更されました(例: sa.familyからsa.Familytv.secからtv.Sec)。 これにより、これらの構造体のフィールドがパッケージ外から直接アクセス可能になり、APIの使いやすさが向上します。 一方で、パッケージ内部でのみ使用される変数や定数(例: ErrorTabからerrorTabNameBufsizeからnameBufsize)は、Goの命名規則に従って小文字で始まる名前に変更され、内部実装の詳細として扱われるようになりました。

これらの変更は、doc/progs/fd.gosrc/lib/net/以下のファイル、src/lib/os/以下のファイル、そしてsrc/lib/syscall/以下のファイルなど、syscallパッケージを利用する広範なコードベースに波及しています。これは、syscallパッケージがGoの低レベルなI/O操作やネットワーク操作の基盤となっているため、そのAPIの変更が多くの依存箇所に影響を与えることを示しています。

このリファクタリングは、Go言語のAPI設計における一貫性と可読性を確立する上で重要なステップでした。これにより、Goの標準ライブラリがより成熟し、開発者にとって予測可能で使いやすいものとなる基盤が築かれました。

コアとなるコードの変更箇所

このコミットでは、多数のファイルで同様のパターンで識別子名が変更されています。以下に代表的な変更箇所をいくつか示します。

  1. 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)
     }
    
  2. 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
     	}
    
  3. src/lib/syscall/types_amd64_darwin.go: 構造体のフィールド名が小文字から大文字に変更されています。また、構造体名自体もStatからStat_tKeventから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_INETAF_INET6など)やポート番号、IPアドレスなどの情報は、ソケット通信を行う上で外部から設定・参照される必要があるため、エクスポートされるべきです。

  • ErrorTab から errorTab への変更: src/lib/os/os_error.goにおけるErrorTabErrorStringTabのような内部的なマップ変数が、小文字で始まるerrorTaberrorStringTabに変更されました。これは、これらの変数がosパッケージの内部実装の詳細であり、外部から直接アクセスされるべきではないことを示しています。Goの命名規則に従うことで、APIの利用者はどの識別子が公開されているか、どの識別子が内部実装であるかを一目で判断できるようになります。

  • Stat から Stat_tKevent から Kevent_t への変更: 一部の構造体名に_tサフィックスが追加されています。これは、C言語のシステムプログラミングにおける慣習(型定義に_tを付ける)を反映している可能性があります。GoのsyscallパッケージはOSのC言語APIをラップしているため、このような命名が採用されたと考えられます。これにより、Goの型とCの型との対応関係がより明確になります。

これらの変更は、単なる名前の変更以上の意味を持ちます。それは、Go言語のAPI設計原則、特に「エクスポート」の概念をコードベース全体に徹底し、ライブラリの使いやすさと保守性を向上させるための重要なステップでした。これにより、Goの標準ライブラリは、その後の発展において一貫性のある堅牢な基盤を持つことになります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (Effective Go)
  • Go言語のsyscallパッケージのソースコード (コミット時点および現在のバージョン)
  • Unix系OSのシステムコールに関する一般的な知識
  • ファイルディスクリプタ、ソケットアドレス、kqueueなどの概念に関する一般的なプログラミング知識
  • GitHubのコミット履歴と差分表示