[インデックス 10871] ファイルの概要
このコミットは、Go言語の標準ライブラリであるsyscall
パッケージにNetBSDオペレーティングシステムに対する初期サポートを追加するものです。具体的には、NetBSD上でGoプログラムがシステムコールを介してカーネルと対話できるようにするための、低レベルのアセンブリコード、Go言語のラッパー、およびコード生成スクリプトが導入されています。これにより、GoアプリケーションがNetBSDのファイルシステム、ネットワーク、プロセス管理などのOS機能を利用できるようになります。
コミット
commit 5425db8f99965c692e929bd0e373297ceca3394a
Author: Christopher Nielsen <m4dh4tt3r@gmail.com>
Date: Tue Dec 20 03:57:58 2011 +1100
syscall: Changes to the syscall package to support NetBSD.
Not all syscalls are implemented, but many are. On the suggestion
of Joel Sing <jsing@google.com>, the generated files were added
with hg add instead of hg cp, since they are generated on an OS
dependant basis.
R=golang-dev, jsing, mikioh.mikioh
CC=golang-dev
https://golang.org/cl/5491050
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5425db8f99965c692e929bd0e373297ceca3394a
元コミット内容
このコミットの元の内容は、Goのsyscall
パッケージにNetBSDのサポートを追加することです。コミットメッセージには以下の点が明記されています。
- NetBSDサポートの追加:
syscall
パッケージがNetBSD上で動作するように変更されました。 - 部分的な実装: 全てのシステムコールが実装されたわけではなく、多くのシステムコールが追加された段階です。
- 生成ファイルの扱い: Joel Sing氏の提案により、生成されたファイルは
hg cp
ではなくhg add
で追加されました。これは、これらのファイルがOSに依存して生成されるためです。hg
はGoがGitに移行する前に使用していたバージョン管理システムであるMercurialを指します。
変更の背景
Go言語は、その設計思想の一つとして、様々なプラットフォームでの動作を重視しています。syscall
パッケージは、Goプログラムが基盤となるオペレーティングシステムのカーネル機能にアクセスするための重要なインターフェースを提供します。このコミットが行われた2011年当時、Goはまだ比較的新しい言語であり、様々なUnix系OS(Linux、FreeBSD、OpenBSD、Darwinなど)への対応を進めている段階でした。
NetBSDは、移植性の高さで知られるオープンソースのUnix系オペレーティングシステムであり、多くの異なるハードウェアアーキテクチャで動作します。Goがより広範なプラットフォームで利用されるためには、NetBSDのような多様な環境への対応が不可欠でした。
このコミットは、GoプログラムがNetBSDのネイティブなシステムコールを直接呼び出せるようにすることで、NetBSD上でのGoアプリケーションの機能性とパフォーマンスを向上させることを目的としています。特に、ファイルI/O、ネットワーク通信、プロセス管理といった基本的なOS機能へのアクセスは、Goプログラムが実用的なアプリケーションを構築する上で不可欠です。
また、コミットメッセージにある「生成ファイルはhg add
で追加された」という点は、Goのsyscall
パッケージの設計思想を反映しています。多くのシステムコール関連の定数や構造体、関数は、各OSのCヘッダファイルから自動生成されます。これにより、手動での記述ミスを防ぎ、OSの変更に追従しやすくなります。しかし、OSごとに生成される内容が異なるため、バージョン管理システム上では新規ファイルとして追加(hg add
)し、既存ファイルのコピー(hg cp
)として扱わないという方針が取られました。
前提知識の解説
このコミットの変更内容を理解するためには、以下の技術的な前提知識が必要です。
-
システムコール (System Call):
- ユーザー空間で動作するアプリケーションが、カーネル空間で提供されるOSの機能(ファイル操作、ネットワーク通信、メモリ管理、プロセス制御など)を利用するためのインターフェースです。
- アプリケーションは直接ハードウェアにアクセスできないため、システムコールを介してカーネルに処理を依頼します。
- システムコールはOSやCPUアーキテクチャによって呼び出し規約(レジスタの使用方法、引数の渡し方など)が異なります。
-
Go言語の
syscall
パッケージ:- GoプログラムからOSのシステムコールを直接呼び出すための低レベルなインターフェースを提供します。
- OS固有の定数、構造体、関数などが定義されており、GoプログラムがOSのネイティブAPIと連携できるようにします。
- 多くのOS固有のコードは、CヘッダファイルやOSのシステムコール定義ファイルから自動生成されます。これにより、GoのコードベースがOSの変更に追従しやすくなっています。
-
ビルドタグ (
+build
):- Go言語のソースファイルに記述される特殊なコメントで、そのファイルがどのOSやアーキテクチャでコンパイルされるべきかを指定します。
- 例:
// +build linux,amd64
はLinuxかつAMD64アーキテクチャの場合にのみコンパイルされることを意味します。 - このコミットでは、既存のUnix系OS向けのファイルに
netbsd
タグが追加され、NetBSDでも共通のコードが利用されるようになっています。
-
Cgo:
- Go言語とC言語のコードを相互に呼び出すためのGoの機能です。
syscall
パッケージでは、OSのCヘッダファイルで定義されている構造体や定数をGoのコードで利用するためにCgoが活用されます。cgo -godefs
コマンドは、Cの定義からGoの構造体定義を自動生成するために使用されます。
-
アセンブリ言語 (x86/x64):
- システムコールは、通常、アセンブリ言語で記述された低レベルなコードを介してカーネルに制御を渡します。
- 32ビットシステム(i386)では、
INT 0x80
命令がよく使われます。 - 64ビットシステム(AMD64)では、
SYSCALL
命令が使われることが多いです。 - このコミットでは、NetBSDの386およびAMD64アーキテクチャ向けに、Goの
Syscall
関数などからカーネルのシステムコールを呼び出すためのアセンブリコードが追加されています。
-
NetBSDのシステムコール定義:
- NetBSDでは、システムコールの定義が
sys/kern/syscalls.master
のようなファイルに記述されています。このファイルは、システムコールの名前、番号、引数などを定義しており、Goのsyscall
パッケージが自動生成ツールを使ってこれらの情報を解析し、Goのコードに変換するために利用します。
- NetBSDでは、システムコールの定義が
-
コード生成スクリプト:
- Goの
syscall
パッケージには、OS固有の定数、エラーコード、システムコールラッパーなどを自動生成するためのPerlスクリプトやシェルスクリプトが含まれています。 mkall.sh
: 全ての生成スクリプトを呼び出すメインスクリプト。mksyscall.pl
://sys
ディレクティブに基づいてGoのシステムコールラッパー関数を生成。mkerrors.sh
: Cヘッダからエラーコードや定数を抽出してGoのコードを生成。mksysnum_netbsd.pl
(新規): NetBSDのsyscalls.master
からシステムコール番号を抽出してGoのコードを生成。
- Goの
これらの知識は、GoがどのようにOSと連携し、特に新しいOSをサポートする際にどのようなプロセスを踏むのかを理解する上で不可欠です。
技術的詳細
このコミットは、Goのsyscall
パッケージにNetBSDサポートを統合するために、多岐にわたる技術的変更を加えています。
-
アセンブリ言語によるシステムコールエントリーポイントの追加:
src/pkg/syscall/asm_netbsd_386.s
およびsrc/pkg/syscall/asm_netbsd_amd64.s
が新規追加されました。- これらのファイルは、Goの
Syscall
,Syscall6
,Syscall9
,RawSyscall
,RawSyscall6
といった低レベルの関数が、実際にNetBSDカーネルのシステムコールを呼び出すためのアセンブリコードを含んでいます。 - 386 (i386):
INT $0x80
命令を使用してシステムコールを呼び出します。引数はスタック経由で渡され、システムコール番号はAX
レジスタに設定されます。 - AMD64:
SYSCALL
命令を使用してシステムコールを呼び出します。引数はレジスタ(DI
,SI
,DX
,R10
,R8
,R9
など)経由で渡され、システムコール番号はAX
レジスタに設定されます。 - これらのアセンブリコードは、システムコール呼び出し前後にGoランタイムの
entersyscall
およびexitsyscall
関数を呼び出し、Goスケジューラがシステムコール中のゴルーチンを適切に管理できるようにしています。
-
ビルドシステムとコード生成スクリプトの更新:
src/pkg/syscall/Makefile
が更新され、NetBSD固有のファイルがビルドプロセスに含まれるようになりました。src/pkg/syscall/mkall.sh
は、Goのビルドプロセスにおいて、NetBSD向けのシステムコール関連ファイルを生成するためのロジックが追加されました。netbsd_386
およびnetbsd_amd64
のケースが追加され、それぞれmkerrors
,mksyscall
,mksysnum
,mktypes
コマンドが定義されています。- 特に
mksysnum
は、NetBSDの公式CVSリポジトリからsyscalls.master
ファイルをcurl
で取得し、それをmksysnum_netbsd.pl
にパイプしてシステムコール番号を生成しています。これは、NetBSDのシステムコール定義に直接依存することで、正確性と最新性を保つための重要な戦略です。
src/pkg/syscall/mkerrors.sh
には、NetBSDのCヘッダファイル(sys/types.h
,sys/socket.h
,net/if.h
など)をインクルードするためのincludes_NetBSD
セクションが追加されました。これにより、NetBSD固有のエラーコードや定数がGoのコードとして生成されます。src/pkg/syscall/mksyscall.pl
は、-netbsd
オプションを認識し、NetBSD固有のシステムコールラッパーを生成できるようになりました。特に、NetBSDのint64
型引数の扱いがOpenBSDと同様に処理されるように変更されています。src/pkg/syscall/mksysnum_netbsd.pl
が新規追加されました。このPerlスクリプトは、NetBSDのsyscalls.master
ファイルを解析し、システムコール名と対応する番号をGoの定数として出力します。これは、Goのsyscall
パッケージがNetBSDのシステムコールを名前で参照できるようにするために不可欠です。
-
Go言語によるNetBSD固有のシステムコールラッパーと型定義:
src/pkg/syscall/syscall_netbsd.go
が新規追加されました。このファイルは、NetBSD固有のGoシステムコールラッパーの主要な定義を含んでいます。OS = "netbsd"
定義。SockaddrDatalink
のようなNetBSD固有のソケットアドレス構造体。Syscall9
関数の宣言(9つの引数を持つシステムコール用)。ParseDirent
関数(ディレクトリエントリーの解析)やPipe
関数(パイプ作成)など、一部のGoレベルでのヘルパー関数。- 多数の
//sys
ディレクティブ。これらはmksyscall.pl
によって解析され、対応するGoのシステムコール関数(例:Access
,Chdir
,Open
,Read
,Write
など)がzsyscall_netbsd_*.go
ファイルに自動生成されます。 Unimplemented
セクションには、このコミットではまだ実装されていない多くのシステムコールがリストされており、今後の拡張の余地を示しています。
src/pkg/syscall/syscall_netbsd_386.go
およびsrc/pkg/syscall/syscall_netbsd_amd64.go
が新規追加されました。これらは、アーキテクチャ固有のヘルパー関数(例:Getpagesize
,TimespecToNsec
,NsecToTimespec
,TimevalToNsec
,NsecToTimeval
)を提供します。src/pkg/syscall/types_netbsd.go
が新規追加されました。このファイルは、cgo -godefs
によって生成されるGoの型定義の元となるCのヘッダインクルードと#define
を含んでいます。これにより、NetBSDのカーネル構造体(Timespec
,Timeval
,Stat_t
,Dirent
,sockaddr
関連、kevent
関連など)がGoの対応する型として定義されます。
-
自動生成されたファイルの追加:
zerrors_netbsd_386.go
,zerrors_netbsd_amd64.go
: NetBSD固有のエラーコードや定数(AF_INET
,IFF_UP
など)が定義されています。zsyscall_netbsd_386.go
,zsyscall_netbsd_amd64.go
:syscall_netbsd.go
の//sys
ディレクティブに基づいて生成された、実際のGoシステムコールラッパー関数が含まれています。これらの関数は、前述のアセンブリコードを呼び出します。zsysnum_netbsd_386.go
,zsysnum_netbsd_amd64.go
:mksysnum_netbsd.pl
によって生成された、システムコール名と番号のマッピングが含まれています。ztypes_netbsd_386.go
,ztypes_netbsd_amd64.go
:types_netbsd.go
とcgo -godefs
によって生成された、NetBSD固有のGoの型定義(構造体、定数)が含まれています。
これらの変更は、GoがNetBSDのカーネルと効率的かつ正確に連携するための基盤を構築するものであり、Goのクロスプラットフォーム対応戦略の重要な一歩を示しています。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、主に以下の新規追加ファイルと、既存のビルドスクリプトおよび共通Goファイルの修正です。
-
新規追加されたアセンブリファイル:
src/pkg/syscall/asm_netbsd_386.s
src/pkg/syscall/asm_netbsd_amd64.s
これらのファイルは、GoのSyscall
、Syscall6
、Syscall9
、RawSyscall
、RawSyscall6
といった関数が、NetBSDのカーネルにシステムコールをディスパッチするための低レベルなアセンブリコードを提供します。
-
新規追加されたNetBSD固有のGoファイル:
src/pkg/syscall/syscall_netbsd.go
: NetBSD固有のシステムコールラッパーのGo言語での定義と、//sys
ディレクティブによる自動生成対象のシステムコールリスト。src/pkg/syscall/syscall_netbsd_386.go
: NetBSD/386アーキテクチャ固有のヘルパー関数。src/pkg/syscall/syscall_netbsd_amd64.go
: NetBSD/AMD64アーキテクチャ固有のヘルパー関数。src/pkg/syscall/types_netbsd.go
: NetBSDのCヘッダからGoの型定義を生成するためのCgo入力ファイル。src/pkg/syscall/route_netbsd.go
: NetBSD固有のルーティングソケットメッセージの解析ロジック。
-
新規追加されたコード生成スクリプト:
src/pkg/syscall/mksysnum_netbsd.pl
: NetBSDのシステムコール番号を生成するためのPerlスクリプト。
-
既存のビルドスクリプトの修正:
src/pkg/syscall/Makefile
: NetBSD固有のファイルをビルド対象に含めるための変更。src/pkg/syscall/mkall.sh
: NetBSD向けのコード生成プロセスを定義するロジックの追加。src/pkg/syscall/mkerrors.sh
: NetBSD固有のCヘッダをインクルードするための定義の追加。src/pkg/syscall/mksyscall.pl
:-netbsd
オプションのサポートと、int64
引数の処理ロジックの拡張。
-
既存の共通Goファイルのビルドタグ修正:
src/pkg/syscall/bpf_bsd.go
src/pkg/syscall/env_unix.go
src/pkg/syscall/exec_unix.go
src/pkg/syscall/route_bsd.go
src/pkg/syscall/sockcmsg_unix.go
src/pkg/syscall/syscall_bsd.go
src/pkg/syscall/syscall_unix.go
これらのファイルには、// +build netbsd
タグが追加され、NetBSD環境でもこれらの共通のUnix/BSD系システムコール関連コードがコンパイルされるようになりました。
-
自動生成されたファイル群:
src/pkg/syscall/zerrors_netbsd_386.go
src/pkg/syscall/zerrors_netbsd_amd64.go
src/pkg/syscall/zsyscall_netbsd_386.go
src/pkg/syscall/zsyscall_netbsd_amd64.go
src/pkg/syscall/zsysnum_netbsd_386.go
src/pkg/syscall/zsysnum_netbsd_amd64.go
src/pkg/syscall/ztypes_netbsd_386.go
src/pkg/syscall/ztypes_netbsd_amd64.go
これらのファイルは、上記のスクリプトとGoのツールチェーンによって自動生成されたものであり、NetBSDのシステムコールインターフェースをGo言語で利用するための具体的な実装を提供します。
コアとなるコードの解説
このコミットの核となるのは、NetBSDのシステムコールをGoから呼び出すためのメカニズムの確立です。
-
アセンブリによるシステムコール呼び出し (
asm_netbsd_*.s
):- これらのファイルは、Goの
Syscall
、Syscall6
、Syscall9
、RawSyscall
、RawSyscall6
といった関数が、実際にNetBSDカーネルのシステムコールを呼び出すための低レベルなアセンブリコードを定義しています。 - 例えば、
Syscall
関数(386版)では、Goの関数呼び出し規約に従ってスタックに積まれた引数(システムコール番号と3つの引数)を、NetBSDのシステムコール呼び出し規約(システムコール番号をAX
レジスタに、引数をスタックに)に合わせて再配置し、INT $0x80
命令でカーネルに制御を渡します。 - システムコールが成功した場合は
JAE ok
で分岐し、戻り値(r1
,r2
)をGoの戻り値として設定します。エラーが発生した場合は、AX
レジスタに格納されたエラーコードをGoのerrno
として設定します。 runtime·entersyscall(SB)
とruntime·exitsyscall(SB)
の呼び出しは、Goランタイムがシステムコール中のゴルーチンをブロック状態にし、他のゴルーチンが実行できるようにするための重要なフックです。これにより、システムコールが完了するまでGoランタイムがブロックされるのを防ぎ、並行性を維持します。
- これらのファイルは、Goの
-
Go言語でのシステムコール定義 (
syscall_netbsd.go
):- このファイルは、Goの
syscall
パッケージがNetBSDのシステムコールをどのように扱うかを定義します。 - 最も重要なのは、
//sys
ディレクティブです。例えば、//sys Access(path string, mode uint32) (err error)
という行は、Access
というGo関数が、path
とmode
を引数に取り、エラーを返すシステムコールであることを示します。 mksyscall.pl
スクリプトは、これらの//sys
ディレクティブを解析し、対応するGoの関数スタブ(例:zsyscall_netbsd_386.go
内のfunc Access(path string, mode uint32) (err error)
)を自動生成します。これらのスタブは、最終的に前述のアセンブリコードを呼び出して実際のシステムコールを実行します。ParseDirent
のようなヘルパー関数は、NetBSDのディレクトリエントリー構造体をGoのバイトスライスから解析し、ファイル名を抽出する役割を担います。これは、GoがOSの低レベルなデータ構造を扱う上で必要となる変換ロジックの一例です。
- このファイルは、Goの
-
型定義と定数の生成 (
types_netbsd.go
,zerrors_netbsd_*.go
,ztypes_netbsd_*.go
):types_netbsd.go
は、cgo -godefs
コマンドの入力として使用され、NetBSDのCヘッダファイルで定義されている構造体(struct timespec
,struct stat
など)や定数をGoの対応する型に変換します。zerrors_netbsd_*.go
ファイルは、mkerrors.sh
スクリプトによって生成され、NetBSD固有のエラーコード(EINVAL
など)や、ネットワーク関連の定数(AF_INET
,IFF_UP
など)をGoの定数として定義します。ztypes_netbsd_*.go
ファイルは、cgo -godefs
によって生成され、types_netbsd.go
で指定されたCの構造体に対応するGoの構造体定義を含みます。これにより、GoプログラムはNetBSDカーネルが使用するデータ構造を正しく扱えるようになります。
-
システムコール番号の生成 (
mksysnum_netbsd.pl
,zsysnum_netbsd_*.go
):mksysnum_netbsd.pl
スクリプトは、NetBSDのsyscalls.master
ファイルからシステムコール名と対応する数値IDを抽出し、Goの定数としてzsysnum_netbsd_*.go
ファイルに書き出します。- 例えば、
SYS_READ = 3
のように、システムコール名がその数値IDにマッピングされます。これは、Goのシステムコールラッパーが、対応するシステムコールを呼び出す際に正しい数値IDをカーネルに渡すために不可欠です。
これらのコンポーネントが連携することで、GoプログラムはNetBSDのカーネル機能に安全かつ効率的にアクセスできるようになります。このコミットは、Goのクロスプラットフォーム戦略において、各OSの特性を吸収しつつ、共通のインターフェースを提供するsyscall
パッケージの設計思想を明確に示しています。
関連リンク
- Go言語の
syscall
パッケージのドキュメント (当時のバージョンに近いもの): https://pkg.go.dev/syscall (現在のドキュメントですが、基本的な概念は共通です) - NetBSDのシステムコールに関する情報: https://man.netbsd.org/syscall.2
- GoのMercurialからGitへの移行に関する情報: https://go.dev/blog/git
参考にした情報源リンク
- Go言語のソースコード(特に
src/pkg/syscall
ディレクトリ) - NetBSDのソースコード(特に
sys/kern/syscalls.master
や関連するヘッダファイル) - Go言語の公式ドキュメントおよびブログ
- Unix系OSにおけるシステムコール呼び出し規約に関する一般的な情報