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

[インデックス 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)として扱わないという方針が取られました。

前提知識の解説

このコミットの変更内容を理解するためには、以下の技術的な前提知識が必要です。

  1. システムコール (System Call):

    • ユーザー空間で動作するアプリケーションが、カーネル空間で提供されるOSの機能(ファイル操作、ネットワーク通信、メモリ管理、プロセス制御など)を利用するためのインターフェースです。
    • アプリケーションは直接ハードウェアにアクセスできないため、システムコールを介してカーネルに処理を依頼します。
    • システムコールはOSやCPUアーキテクチャによって呼び出し規約(レジスタの使用方法、引数の渡し方など)が異なります。
  2. Go言語の syscall パッケージ:

    • GoプログラムからOSのシステムコールを直接呼び出すための低レベルなインターフェースを提供します。
    • OS固有の定数、構造体、関数などが定義されており、GoプログラムがOSのネイティブAPIと連携できるようにします。
    • 多くのOS固有のコードは、CヘッダファイルやOSのシステムコール定義ファイルから自動生成されます。これにより、GoのコードベースがOSの変更に追従しやすくなっています。
  3. ビルドタグ (+build):

    • Go言語のソースファイルに記述される特殊なコメントで、そのファイルがどのOSやアーキテクチャでコンパイルされるべきかを指定します。
    • 例: // +build linux,amd64 はLinuxかつAMD64アーキテクチャの場合にのみコンパイルされることを意味します。
    • このコミットでは、既存のUnix系OS向けのファイルにnetbsdタグが追加され、NetBSDでも共通のコードが利用されるようになっています。
  4. Cgo:

    • Go言語とC言語のコードを相互に呼び出すためのGoの機能です。
    • syscallパッケージでは、OSのCヘッダファイルで定義されている構造体や定数をGoのコードで利用するためにCgoが活用されます。cgo -godefsコマンドは、Cの定義からGoの構造体定義を自動生成するために使用されます。
  5. アセンブリ言語 (x86/x64):

    • システムコールは、通常、アセンブリ言語で記述された低レベルなコードを介してカーネルに制御を渡します。
    • 32ビットシステム(i386)では、INT 0x80命令がよく使われます。
    • 64ビットシステム(AMD64)では、SYSCALL命令が使われることが多いです。
    • このコミットでは、NetBSDの386およびAMD64アーキテクチャ向けに、GoのSyscall関数などからカーネルのシステムコールを呼び出すためのアセンブリコードが追加されています。
  6. NetBSDのシステムコール定義:

    • NetBSDでは、システムコールの定義がsys/kern/syscalls.masterのようなファイルに記述されています。このファイルは、システムコールの名前、番号、引数などを定義しており、Goのsyscallパッケージが自動生成ツールを使ってこれらの情報を解析し、Goのコードに変換するために利用します。
  7. コード生成スクリプト:

    • Goのsyscallパッケージには、OS固有の定数、エラーコード、システムコールラッパーなどを自動生成するためのPerlスクリプトやシェルスクリプトが含まれています。
    • mkall.sh: 全ての生成スクリプトを呼び出すメインスクリプト。
    • mksyscall.pl: //sysディレクティブに基づいてGoのシステムコールラッパー関数を生成。
    • mkerrors.sh: Cヘッダからエラーコードや定数を抽出してGoのコードを生成。
    • mksysnum_netbsd.pl (新規): NetBSDのsyscalls.masterからシステムコール番号を抽出してGoのコードを生成。

これらの知識は、GoがどのようにOSと連携し、特に新しいOSをサポートする際にどのようなプロセスを踏むのかを理解する上で不可欠です。

技術的詳細

このコミットは、GoのsyscallパッケージにNetBSDサポートを統合するために、多岐にわたる技術的変更を加えています。

  1. アセンブリ言語によるシステムコールエントリーポイントの追加:

    • 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スケジューラがシステムコール中のゴルーチンを適切に管理できるようにしています。
  2. ビルドシステムとコード生成スクリプトの更新:

    • 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のシステムコールを名前で参照できるようにするために不可欠です。
  3. 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の対応する型として定義されます。
  4. 自動生成されたファイルの追加:

    • 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.gocgo -godefsによって生成された、NetBSD固有のGoの型定義(構造体、定数)が含まれています。

これらの変更は、GoがNetBSDのカーネルと効率的かつ正確に連携するための基盤を構築するものであり、Goのクロスプラットフォーム対応戦略の重要な一歩を示しています。

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

このコミットにおけるコアとなるコードの変更箇所は、主に以下の新規追加ファイルと、既存のビルドスクリプトおよび共通Goファイルの修正です。

  1. 新規追加されたアセンブリファイル:

    • src/pkg/syscall/asm_netbsd_386.s
    • src/pkg/syscall/asm_netbsd_amd64.s これらのファイルは、GoのSyscallSyscall6Syscall9RawSyscallRawSyscall6といった関数が、NetBSDのカーネルにシステムコールをディスパッチするための低レベルなアセンブリコードを提供します。
  2. 新規追加された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固有のルーティングソケットメッセージの解析ロジック。
  3. 新規追加されたコード生成スクリプト:

    • src/pkg/syscall/mksysnum_netbsd.pl: NetBSDのシステムコール番号を生成するためのPerlスクリプト。
  4. 既存のビルドスクリプトの修正:

    • 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引数の処理ロジックの拡張。
  5. 既存の共通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系システムコール関連コードがコンパイルされるようになりました。
  6. 自動生成されたファイル群:

    • 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から呼び出すためのメカニズムの確立です。

  1. アセンブリによるシステムコール呼び出し (asm_netbsd_*.s):

    • これらのファイルは、GoのSyscallSyscall6Syscall9RawSyscallRawSyscall6といった関数が、実際に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ランタイムがブロックされるのを防ぎ、並行性を維持します。
  2. Go言語でのシステムコール定義 (syscall_netbsd.go):

    • このファイルは、GoのsyscallパッケージがNetBSDのシステムコールをどのように扱うかを定義します。
    • 最も重要なのは、//sysディレクティブです。例えば、//sys Access(path string, mode uint32) (err error)という行は、AccessというGo関数が、pathmodeを引数に取り、エラーを返すシステムコールであることを示します。
    • mksyscall.plスクリプトは、これらの//sysディレクティブを解析し、対応するGoの関数スタブ(例: zsyscall_netbsd_386.go内のfunc Access(path string, mode uint32) (err error))を自動生成します。これらのスタブは、最終的に前述のアセンブリコードを呼び出して実際のシステムコールを実行します。
    • ParseDirentのようなヘルパー関数は、NetBSDのディレクトリエントリー構造体をGoのバイトスライスから解析し、ファイル名を抽出する役割を担います。これは、GoがOSの低レベルなデータ構造を扱う上で必要となる変換ロジックの一例です。
  3. 型定義と定数の生成 (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カーネルが使用するデータ構造を正しく扱えるようになります。
  4. システムコール番号の生成 (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言語のソースコード(特にsrc/pkg/syscallディレクトリ)
  • NetBSDのソースコード(特にsys/kern/syscalls.masterや関連するヘッダファイル)
  • Go言語の公式ドキュメントおよびブログ
  • Unix系OSにおけるシステムコール呼び出し規約に関する一般的な情報