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

[インデックス 14477] ファイルの概要

このコミットは、Go言語のランタイムがFreeBSDオペレーティングシステムと連携するために使用する定義ファイル群を再生成したものです。具体的には、godefsツールからcgo -cdefsツールへの移行に伴い、FreeBSDの異なるアーキテクチャ(386, amd64, ARM)向けのCヘッダーファイルと、それに対応するGoの定義ファイルが更新されました。これにより、GoランタイムがFreeBSDのシステムコールやデータ構造をより正確かつ効率的に利用できるようになります。

コミット

commit f02cf1997d84107cbdd53967748c1d8f3a2a8577
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Mon Nov 26 21:29:13 2012 +0900

    runtime: regenerate defs-files for freebsd
    
    R=minux.ma, jsing
    CC=golang-dev
    https://golang.org/cl/6855080
---
 src/pkg/runtime/defs_freebsd.go      |   1 -
 src/pkg/runtime/defs_freebsd_386.h   | 318 ++++++++++++++++----------------
 src/pkg/runtime/defs_freebsd_amd64.h | 340 +++++++++++++++++------------------
 src/pkg/runtime/defs_freebsd_arm.h   | 281 ++++++++++++++---------------\n src/pkg/runtime/signal_freebsd_arm.c |  20 ++-\n src/pkg/runtime/thread_freebsd.c     |   6 +-\n 6 files changed, 477 insertions(+), 489 deletions(-)

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f02cf1997d84107cbdd53967748c1d8f3a2a8577

元コミット内容

このコミットの元の内容は、FreeBSD向けのGoランタイム定義ファイル群を再生成することです。これは、Goのビルドシステムとツールチェーンの進化に伴い、OSとのインターフェースを定義するメカニズムが変更された結果として行われました。具体的には、以前はgodefsという独立したツールで生成されていた定義ファイルが、cgoツールの一部である-cdefsオプションを使用して生成されるようになりました。これにより、生成されるファイルのフォーマットが統一され、GoとCの間の相互運用性定義の管理が簡素化されました。

変更の背景

Go言語は、そのランタイムが直接オペレーティングシステム(OS)のシステムコールを呼び出すことで、高いパフォーマンスと効率を実現しています。このOSとの低レベルな連携を可能にするために、Goランタイムは各OSおよびアーキテクチャ固有の定数、構造体、関数シグネチャなどの定義を必要とします。これらの定義は通常、C言語のヘッダーファイル(.h)とGo言語のソースファイル(.go)の形で存在します。

以前は、これらの定義ファイルを生成するためにgodefsという専用のツールが使用されていました。しかし、Goのツールチェーンが成熟するにつれて、C言語との相互運用を扱うcgoツールに、この定義ファイル生成の機能が統合されることになりました。cgo -cdefsは、GoのソースコードからCの定義を生成する機能を提供し、godefsの役割を引き継ぎました。

このコミットは、FreeBSD環境において、この新しいcgo -cdefsのワークフローに移行し、既存の定義ファイルを新しいツールで再生成した結果です。再生成により、ファイルの内容が最新のツールによって生成されたものに更新され、フォーマットの統一や、場合によってはOSのAPI変更への対応が行われます。

前提知識の解説

  • Goランタイム (Go Runtime): Goプログラムの実行を管理する中核部分です。ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、メモリ管理、そしてOSとの直接的なインターフェース(システムコール)の呼び出しなどを担当します。
  • システムコール (System Call): アプリケーションがOSのカーネルサービス(ファイルI/O、メモリ管理、プロセス管理など)を利用するためのインターフェースです。Goランタイムは、OSの機能を利用するために直接システムコールを呼び出します。
  • defs-files: Goランタイムが特定のOSやアーキテクチャのシステムコールやデータ構造を理解し、それらと連携するために必要な定義を含むファイル群です。これらは通常、C言語のヘッダーファイル(.h)とGo言語の型定義ファイル(.go)で構成されます。
  • godefs: Go言語の初期のツールチェーンに含まれていたユーティリティで、C言語の構造体や定数定義からGo言語の対応する定義を自動生成するために使用されていました。
  • cgo: Go言語とC言語(およびC++)のコードを相互に呼び出すためのGoツールです。Goプログラム内でCの関数を呼び出したり、CのコードからGoの関数を呼び出したりすることを可能にします。
  • cgo -cdefs: cgoツールに新たに追加されたオプションで、godefsの機能を置き換えるものです。Goのソースファイル(特に// #cgo CFLAGS: -D...のようなディレクティブを含むもの)から、C言語のヘッダーファイル形式で定義を生成します。これにより、GoとCの間の型定義の同期がより密接に行われるようになりました。
  • FreeBSD: オープンソースのUnix系オペレーティングシステムの一つです。Go言語は、Linux、Windows、macOSなどと同様にFreeBSDも公式にサポートしています。
  • アーキテクチャ (386, amd64, ARM): CPUの命令セットアーキテクチャを指します。
    • 386: Intel 80386互換の32ビットアーキテクチャ(i386とも呼ばれる)。
    • amd64: x86-64とも呼ばれる64ビットアーキテクチャ。現代のほとんどのデスクトップおよびサーバーCPUで採用されています。
    • ARM: モバイルデバイスや組み込みシステムで広く使用されているRISCベースのアーキテクチャ。

技術的詳細

このコミットの主要な技術的変更点は、定義ファイルの生成ツールがgodefsからcgo -cdefsに切り替わったことです。これにより、以下の具体的な変更が見られます。

  1. ヘッダーコメントの変更:

    • 旧: // godefs -f -m32 defs.c または // MACHINE GENERATED - DO NOT EDIT.
    • 新: // Created by cgo -cdefs - DO NOT EDIT または // cgo -cdefs defs_freebsd.go これは、ファイルがどのツールによって生成されたかを示す明確な変更点です。DO NOT EDITのコメントは、これらのファイルが手動で編集されるべきではなく、ツールによって管理されるべきであることを強調しています。
  2. 定数定義のフォーマット変更: enumブロック内の定数定義のフォーマットが変更されました。

    • 旧: PROT_NONE = 0,
    • 新: PROT_NONE = 0x0, 値が16進数表記に統一され、タブによるインデントが導入されています。これは、生成ツールの出力スタイルの違いによるものです。
  3. 構造体定義の変更: C言語の構造体定義において、typedef struct Name Name;という前方宣言が追加され、その後に実際の構造体定義が続く形式になりました。また、構造体メンバーのインデントがタブに統一されています。

    • 例:
      // 旧
      typedef struct Rtprio Rtprio;
      struct Rtprio {
      	uint16 type;
      	uint16 prio;
      };
      
      // 新
      typedef struct Rtprio Rtprio;
      struct Rtprio {
      	uint16	type;
      	uint16	prio;
      };
      

    これは、C言語の慣習に合わせたより標準的な記述方法であり、可読性の向上にも寄与します。

  4. Sigvalユニオンの削除: src/pkg/runtime/defs_freebsd.goおよび対応する.hファイルからSigvalユニオンの定義が削除されました。Sigvalはシグナルハンドリングにおいて追加の情報を渡すために使用されるユニオンですが、GoランタイムがFreeBSDのシグナルを扱う方法が変更されたか、あるいはこのユニオンがGoの内部表現で直接必要なくなったことを示唆しています。代わりに、Siginfo構造体内のsi_valueフィールドがbyte配列として定義されています(例: byte si_value[4];)。これは、Go側でSigvalの具体的な構造を意識せず、バイト列として扱うことで、より柔軟な対応を可能にするための変更と考えられます。

  5. Mcontext構造体の変更 (ARMアーキテクチャ): src/pkg/runtime/defs_freebsd_arm.hにおいて、Mcontext構造体の定義が大きく変更されました。以前は個々のレジスタ(r0, r1, ..., r15, cpsr)が直接メンバーとして定義されていましたが、新しい定義ではこれらが__gregsという配列にまとめられ、浮動小数点ユニット(FPU)の状態も__fpuという配列に抽象化されました。

    • 旧: uint32 r0; uint32 r1; ... uint32 cpsr;
    • 新: uint32 __gregs[17]; byte __fpu[140]; この変更は、異なるARMサブアーキテクチャやコンパイラバージョン間での互換性を高めるため、またはGoランタイムがレジスタ状態をより汎用的な方法で扱うためと考えられます。
  6. signal_freebsd_arm.cにおけるレジスタアクセスの調整: Mcontext構造体の変更に伴い、src/pkg/runtime/signal_freebsd_arm.cでは、既存のCコードが引き続きレジスタにアクセスできるように、新しい__gregs配列のインデックスに対応する#defineマクロが追加されました。

    • 例: #define r0 __gregs[0] これにより、ソースコードの変更を最小限に抑えつつ、新しい構造体定義に適応しています。これは、APIの互換性を維持しつつ、内部実装を変更する一般的な手法です。
  7. ポインタ型のキャスト変更: src/pkg/runtime/signal_freebsd_arm.csrc/pkg/runtime/thread_freebsd.cにおいて、いくつかのポインタ型がint8*からuint8*void*byte*にキャストされるように変更されました。

    • 例: st.ss_sp = (int8*)p; から st.ss_sp = (uint8*)p;
    • 例: param.arg = m; から param.arg = (byte*)m;
    • 例: param.stack_base = (int8*)g->stackbase; から param.stack_base = (void*)g->stackbase;
    • 例: param.tls_base = (int8*)&m->tls[0]; から param.tls_base = (void*)&m->tls[0]; これらの変更は、ThrParam構造体のメンバーに値を割り当てる際のポインタ型のキャストを調整しています。byteはGoにおけるバイト型であり、Cのunsigned charに相当します。void*はC言語において任意の型のポインタを指すことができるため、より柔軟なポインタ操作が可能になります。これらのキャスト変更は、GoとCの間のインターフェースにおける型安全性を高め、またはGoの内部的なポインタ表現とCのポインタ表現との間の整合性を確保するためのものです。
  8. パディングバイト名の変更: 構造体内のパディングバイトのメンバー名がpad_godefs_0からPad_cgo_0に変更されました。これは、生成ツールがgodefsからcgoに変わったことを示すもう一つの痕跡です。

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

このコミットのコアとなる変更は、主に以下のファイル群に集中しています。

  • src/pkg/runtime/defs_freebsd.go: Go言語側のFreeBSD定義ファイル。Sigval型の削除が行われました。
  • src/pkg/runtime/defs_freebsd_386.h: FreeBSD/386アーキテクチャ向けのCヘッダー定義ファイル。
  • src/pkg/runtime/defs_freebsd_amd64.h: FreeBSD/amd64アーキテクチャ向けのCヘッダー定義ファイル。
  • src/pkg/runtime/defs_freebsd_arm.h: FreeBSD/ARMアーキテクチャ向けのCヘッダー定義ファイル。特にMcontext構造体の変更が顕著です。
  • src/pkg/runtime/signal_freebsd_arm.c: FreeBSD/ARMにおけるシグナルハンドリング関連のCソースファイル。Mcontextの変更に対応するためのレジスタマクロが追加されました。
  • src/pkg/runtime/thread_freebsd.c: FreeBSDにおけるスレッド関連のCソースファイル。ポインタ型のキャストが調整されました。

これらのファイルは、GoランタイムがFreeBSDの低レベルな機能(メモリ管理、シグナル処理、スレッド管理など)と直接やり取りするためのインターフェースを定義しています。

コアとなるコードの解説

src/pkg/runtime/defs_freebsd.go

-type Sigval C.union_sigval

この行の削除は、GoランタイムがFreeBSDのunion sigvalを直接Goの型としてマッピングする必要がなくなったことを示しています。これは、cgo -cdefsによる生成プロセスが、このユニオンの扱いをより抽象化された方法(例えば、バイト配列として)で処理するようになったためと考えられます。

src/pkg/runtime/defs_freebsd_arm.h (Mcontext構造体の変更)

// 旧
 struct Mcontext {
 	uint32 r0;
 	uint32 r1;
 	uint32 r2;
 	uint32 r3;
 	uint32 r4;
 	uint32 r5;
 	uint32 r6;
 	uint32 r7;
 	uint32 r8;
 	uint32 r9;
 	uint32 r10;
 	uint32 r11;
 	uint32 r12;
 	uint32 r13;
 	uint32 r14;
 	uint32 r15;
 	uint32 cpsr;
 	uint32 _pad[1+33+1]; // union __fpu
 };

// 新
 struct Mcontext {
 	uint32	__gregs[17];
 	byte	__fpu[140];
 };

この変更は、ARMアーキテクチャにおけるCPUレジスタの状態を保持するMcontext構造体の内部表現を根本的に変更しています。以前は各レジスタが個別のフィールドとして定義されていましたが、新しいバージョンでは__gregsという配列にまとめられています。これにより、レジスタの追加や削除があった場合でも、Mcontext構造体自体の定義を変更することなく、配列のサイズやインデックスを調整するだけで対応できるようになり、保守性が向上します。__fpuは浮動小数点ユニットのコンテキストを保持するためのバイト配列です。

src/pkg/runtime/signal_freebsd_arm.c (レジスタマクロの追加)

+#define r0	__gregs[0]
+#define r1	__gregs[1]
+#define r2	__gregs[2]
+// ... (r3-r15, cpsrまで同様)
+#define cpsr	__gregs[16]

// ...

 void
 runtime·dumpregs(Mcontext *r)
 {
 	// r->r0, r->r1 など、既存のコードが変更なく動作するように
 	// 上記の#defineマクロが機能する
 }

Mcontext構造体の変更により、Cコード内で直接r->r0のようにレジスタにアクセスしていた箇所がコンパイルエラーになるのを防ぐため、これらの#defineマクロが導入されました。これにより、r->r0という記述はプリプロセッサによってr->__gregs[0]に展開され、既存のコードを修正することなく新しい構造体定義に対応できます。これは、APIの互換性を維持しつつ、内部実装を変更する一般的な手法です。

src/pkg/runtime/thread_freebsd.c (ポインタ型のキャスト変更)

// 旧
 	param.arg = m;
 	param.stack_base = (int8*)g->stackbase;
 	param.tls_base = (int8*)&m->tls[0];

// 新
 	param.arg = (byte*)m;
 	param.stack_base = (void*)g->stackbase;
 	param.tls_base = (void*)&m->tls[0];

これらの変更は、ThrParam構造体のメンバーに値を割り当てる際のポインタ型のキャストを調整しています。

  • param.arg = (byte*)m;: m(GoのM構造体へのポインタ)をCのbyte*unsigned char*に相当)にキャストしています。これは、Goのランタイム内部でM構造体がバイト列として扱われることを示唆しています。
  • param.stack_base = (void*)g->stackbase;: スタックベースポインタをint8*からより汎用的なvoid*にキャストしています。void*はC言語において任意の型のポインタを指すことができるため、より柔軟なポインタ操作が可能になります。
  • param.tls_base = (void*)&m->tls[0];: TLS(Thread Local Storage)ベースポインタも同様にvoid*にキャストされています。

これらのキャスト変更は、GoとCの間のインターフェースにおける型安全性を高め、またはGoの内部的なポインタ表現とCのポインタ表現との間の整合性を確保するためのものです。

関連リンク

  • Go言語の公式ドキュメント: https://golang.org/doc/
  • Goのランタイムに関する情報: Goのソースコードリポジトリ内のsrc/runtimeディレクトリを参照。
  • cgoに関する公式ドキュメント: https://golang.org/cmd/cgo/

参考にした情報源リンク

  • Go Gerrit Change-ID 6855080: https://golang.org/cl/6855080
  • Go言語のgodefsツールの歴史とcgo -cdefsへの移行に関する議論(一般的な情報源、特定のURLは変動する可能性があるため、検索クエリを推奨): "Go godefs vs cgo -cdefs"