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

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

このコミットは、Go言語のランタイムがFreeBSDオペレーティングシステム上でARMアーキテクチャをサポートするための変更を導入するものです。具体的には、FreeBSD/ARM環境に特化したシステム定義、起動ルーチン、シグナルハンドリング、およびシステムコールラッパーが追加されています。

コミット

commit 366268aa7951b81d55c4c8e69383758556917577
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Fri Oct 12 23:19:39 2012 +0800

    runtime: FreeBSD/ARM support
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/6625071
---
 src/pkg/runtime/defs_freebsd_arm.h   | 183 ++++++++++++++++++++++++
 src/pkg/runtime/rt0_freebsd_arm.s    |   8 ++
 src/pkg/runtime/signal_freebsd_arm.c | 156 +++++++++++++++++++++
 src/pkg/runtime/sys_freebsd_arm.s    | 262 +++++++++++++++++++++++++++++++++++
 4 files changed, 609 insertions(+)

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

https://github.com/golang/go/commit/366268aa7951b81d55c4c8e69383758556917577

元コミット内容

このコミットは、GoランタイムにFreeBSD/ARMのサポートを追加します。これには、FreeBSD/ARM固有のシステム定義、ランタイムの初期化コード、シグナル処理、およびシステムコールインターフェースの実装が含まれます。

変更の背景

Go言語は、その設計思想として、様々なプラットフォーム(OSとアーキテクチャの組み合わせ)での動作をサポートすることを目指しています。このコミットが作成された2012年当時、Goは既にLinuxやWindows、macOSなどの主要なOSと、x86/x64アーキテクチャをサポートしていましたが、組み込みシステムや特定のサーバー環境で利用されるARMアーキテクチャとFreeBSDの組み合わせに対するサポートは限定的でした。

FreeBSDは、堅牢性と高性能で知られるUNIX系OSであり、ARMアーキテクチャは低消費電力と高いコストパフォーマンスから、モバイルデバイス、組み込みシステム、そして近年ではデータセンターのサーバーなど、幅広い分野で採用が拡大していました。Go言語がこれらの環境で動作できるようにすることは、Goの適用範囲を広げ、より多くの開発者がGoを利用できるようにするために不可欠でした。

このコミットは、GoランタイムがFreeBSD/ARM環境で正しく動作するために必要な、低レベルのOSおよびハードウェアとのインタラクション層を実装することを目的としています。これにより、GoプログラムがFreeBSD/ARM上でコンパイルされ、実行できるようになります。

前提知識の解説

このコミットの変更内容を理解するためには、以下の技術的な概念についての知識が役立ちます。

  • Goランタイム (Go Runtime): Goプログラムは、OSが提供する機能(システムコール、メモリ管理、スレッド管理など)を直接利用するのではなく、Goランタイムと呼ばれる独自の実行環境を介してこれらの機能にアクセスします。ランタイムは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、チャネル通信、メモリ割り当てなど、Go言語の並行処理モデルとメモリ管理を支える重要な役割を担っています。各OS/アーキテクチャの組み合わせに対して、ランタイムはそれぞれのプラットフォームの特性に合わせて実装されます。
  • FreeBSD: UNIX系オペレーティングシステムの一つで、高性能、安定性、セキュリティに優れています。カーネルとユーザーランドが一体となって開発されており、システムコールインターフェースを通じてアプリケーションにサービスを提供します。
  • ARMアーキテクチャ (Advanced RISC Machine): RISC(Reduced Instruction Set Computer)ベースのプロセッサアーキテクチャです。低消費電力と高い性能効率が特徴で、スマートフォン、タブレット、組み込みシステム、IoTデバイス、そして近年ではサーバーやデスクトップPCにも広く採用されています。ARMプロセッサは、レジスタセット、命令セット、メモリモデルなどがx86とは異なります。
  • システムコール (System Call): アプリケーションがOSのカーネル機能(ファイルI/O、メモリ管理、プロセス管理、ネットワーク通信など)にアクセスするためのインターフェースです。アプリケーションは直接カーネルにアクセスすることはできず、システムコールを通じて間接的に要求を伝えます。各OSは独自のシステムコールセットと呼び出し規約を持っています。ARMアーキテクチャでは、通常、SWI (Software Interrupt) 命令やSVC (Supervisor Call) 命令を使用してシステムコールをトリガーします。
  • シグナルハンドリング (Signal Handling): OSがプロセスに対して非同期イベント(エラー、外部からの割り込みなど)を通知するメカニズムです。例えば、プログラムの不正なメモリアクセス(SIGSEGV)、割り込み(SIGINT)、タイマーイベント(SIGALRM)などがあります。プログラムはシグナルを受信した際に、事前に登録されたシグナルハンドラ関数を実行することで、これらのイベントに対応できます。
  • メモリ管理 (Memory Management): プログラムがメモリを効率的に利用するための仕組みです。mmap (memory map) は、ファイルや匿名メモリ領域をプロセスの仮想アドレス空間にマッピングするシステムコールで、メモリ割り当てやファイルI/Oに利用されます。munmap はマッピングを解除します。
  • スレッド管理 (Thread Management): プロセス内で複数の実行パスを管理する仕組みです。Goランタイムは、OSスレッドの上にゴルーチンを多重化して実行します。thr_newthr_start は、FreeBSDにおけるスレッド作成に関連するシステムコールやランタイム関数です。
  • アセンブリ言語 (Assembly Language): 特定のCPUアーキテクチャの命令セットに直接対応する低レベルのプログラミング言語です。Goランタイムの低レベルな部分(起動ルーチン、システムコールラッパー、コンテキストスイッチなど)は、パフォーマンスやOSとの密接な連携のためにアセンブリ言語で記述されることがあります。
  • godefs ツール: Goのソースコード内でC言語の構造体や定数をGoの型定義に変換するために使用されるツールです。これにより、C言語で定義されたOSの構造体や定数をGoプログラムから安全に利用できるようになります。

技術的詳細

このコミットは、GoランタイムがFreeBSD/ARM上で動作するために必要な、以下の主要なコンポーネントを追加・変更しています。

  1. src/pkg/runtime/defs_freebsd_arm.h:

    • このファイルは、godefsツールによって生成されたヘッダファイルであり、FreeBSD/ARM環境におけるシステムコールに関連する定数(PROT_NONE, MAP_ANON, SA_SIGINFOなど)や、OSが使用する主要なデータ構造(Rtprio, ThrParam, Sigaltstack, Sigset, Siginfo, Mcontext, Ucontext, Timespec, Timeval, Itimervalなど)のGo言語での定義を含んでいます。
    • Mcontext構造体は、シグナルハンドラが呼び出された時点のCPUレジスタの状態(R0-R15, CPSRなど)を保持しており、シグナル発生時のプログラムの状態を分析するために重要です。
    • Ucontext構造体は、シグナルマスク、マシンコンテキスト(Mcontext)、代替スタック情報など、シグナルハンドラが実行されるコンテキスト全体をカプセル化します。
    • これらの定義は、GoランタイムがFreeBSDカーネルと正しくインタラクトし、システムコールやシグナル処理を行う上で不可欠です。
  2. src/pkg/runtime/rt0_freebsd_arm.s:

    • このファイルは、GoプログラムのFreeBSD/ARM上でのエントリポイントとなる低レベルのアセンブリコードを含んでいます。
    • _rt0_arm_freebsdというシンボルは、プログラムが起動した際に最初に実行されるコードであり、Goランタイムの初期化ルーチンである_rt0_armにジャンプします。
    • これは、GoプログラムがOSによってロードされた後、Goランタイムが制御を引き継ぎ、Goの実行環境をセットアップするための最初のステップです。
  3. src/pkg/runtime/signal_freebsd_arm.c:

    • このファイルは、FreeBSD/ARM環境におけるGoランタイムのシグナルハンドリングロジックをC言語で実装しています。
    • runtime·dumpregs関数は、Mcontext構造体からCPUレジスタの値を抽出し、デバッグ目的で出力します。これは、クラッシュやパニック発生時にレジスタの状態を把握するために非常に有用です。
    • runtime·sighandler関数は、Goランタイムの主要なシグナルハンドラです。OSからシグナルを受信すると、この関数が呼び出され、シグナルの種類(SIGPROFSIGSEGVなど)に応じて適切な処理(プロファイリング、パニックの開始、シグナルの転送など)を行います。特に、SIGPROF(プロファイリングシグナル)や、SIGSEGV(セグメンテーション違反)のような致命的なシグナルに対するGoランタイムのパニック処理が実装されています。
    • runtime·signalstackは、代替シグナルスタックを設定するための関数です。これにより、通常のスタックが破損した場合でも、シグナルハンドラが安全に実行できるようになります。
    • runtime·setsigは、特定のシグナルに対するハンドラを設定するための関数です。SA_SIGINFOフラグは、シグナルハンドラに追加のコンテキスト情報(SiginfoUcontext)を渡すことを指定します。SA_ONSTACKは、代替シグナルスタックを使用することを指定します。
    • runtime·cputicksは、CPUのティック数を返す関数で、プロファイリングや乱数生成のシードとして利用されます。FreeBSD/ARMでは、runtime·nanotime()gettimeofdayシステムコールに基づく)が使用されています。
  4. src/pkg/runtime/sys_freebsd_arm.s:

    • このファイルは、FreeBSD/ARM環境におけるGoランタイムのシステムコールラッパーをアセンブリ言語で実装しています。
    • Goランタイムは、OSのシステムコールを直接呼び出すのではなく、このファイルで定義されたラッパー関数を介して呼び出します。これにより、Goの呼び出し規約とOSのシステムコール呼び出し規約の間の変換が行われます。
    • TEXT runtime·<syscall_name>(SB)ブロックは、特定のシステムコール(例: runtime·sys_umtx_op, runtime·thr_new, runtime·exit, runtime·write, runtime·mmap, runtime·munmap, runtime·sigaction, runtime·nanotime, runtime·sigprocmaskなど)に対応しています。
    • SWI命令(Software Interrupt)は、ARMアーキテクチャでシステムコールをトリガーするために使用されます。SWI命令のオペランドは、呼び出すシステムコールの番号を示します(例: $454umtx_op$1exit$4writeなど)。
    • レジスタ(R0-R7)は、システムコールへの引数を渡すために使用され、戻り値もレジスタを介して返されます。スタックも引数渡しに使用されることがあります。
    • runtime·sigtrampは、OSのシグナルディスパッチャからGoランタイムのシグナルハンドラ(runtime·sighandler)への橋渡しをするアセンブリルーチンです。これは、シグナル発生時のCPUコンテキストを保存し、Goランタイムのコンテキスト(gmポインタ)を適切に設定してから、C言語で記述されたruntime·sighandlerを呼び出します。
    • runtime·casおよびruntime·caspは、アトミックな比較交換(Compare-And-Swap)操作を実装しています。これは、並行処理におけるロックフリーなデータ構造や同期プリミティブを実装するために不可欠な低レベル操作です。

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

このコミットで追加された主要なファイルは以下の4つです。

  1. src/pkg/runtime/defs_freebsd_arm.h: FreeBSD/ARM固有の定数と構造体定義。
  2. src/pkg/runtime/rt0_freebsd_arm.s: FreeBSD/ARM用のランタイム初期化アセンブリコード。
  3. src/pkg/runtime/signal_freebsd_arm.c: FreeBSD/ARM用のシグナルハンドリングCコード。
  4. src/pkg/runtime/sys_freebsd_arm.s: FreeBSD/ARM用のシステムコールラッパーアセンブリコード。

これらのファイルはすべて新規追加されており、GoランタイムがFreeBSD/ARM環境で動作するために必要な、OSおよびアーキテクチャ固有の低レベルなインタラクション層を構成しています。

コアとなるコードの解説

src/pkg/runtime/defs_freebsd_arm.h

このファイルは、GoランタイムがFreeBSD/ARMカーネルと連携するために必要な、C言語のシステムヘッダから抽出された定数と構造体のGo言語表現を提供します。

  • 定数: PROT_READ, MAP_ANON, SA_SIGINFOなどのメモリ保護フラグ、メモリマッピングフラグ、シグナルアクションフラグ、および様々なシグナル番号(SIGHUP, SIGINT, SIGSEGVなど)が定義されています。これらは、mmapsigactionなどのシステムコールを呼び出す際に引数として使用されます。
  • 構造体:
    • Siginfo: シグナルに関する詳細情報(シグナル番号、エラーコード、発生アドレスなど)を保持します。
    • Mcontext: シグナル発生時のCPUレジスタの状態(R0-R15, CPSRなど)を保持します。これは、スタックトレースの生成やデバッグに不可欠です。
    • Ucontext: シグナルハンドラが実行される際の完全なコンテキスト(シグナルマスク、マシンコンテキスト、スタック情報など)をカプセル化します。
    • Timespec, Timeval, Itimerval: 時間関連のシステムコールで使用される構造体です。FreeBSD/ARMでは、tv_secint64である点が注目されます。

これらの定義は、GoランタイムがFreeBSDカーネルのAPIを正しく呼び出し、その応答を解釈するために必要です。

src/pkg/runtime/rt0_freebsd_arm.s

これは、GoプログラムがFreeBSD/ARM上で起動する際のエントリポイントとなる非常に短いアセンブリファイルです。

TEXT _rt0_arm_freebsd(SB),7,$-4
	B	_rt0_arm(SB)
  • _rt0_arm_freebsd(SB): FreeBSD/ARM環境におけるGoプログラムの開始点となるシンボルです。
  • B _rt0_arm(SB): この命令は、Goランタイムの共通ARM初期化ルーチンである_rt0_armに無条件ジャンプします。 このファイルは、OSがプログラムをロードした直後にGoランタイムが制御を獲得し、Goの実行環境をセットアップするための最初のステップを提供します。

src/pkg/runtime/signal_freebsd_arm.c

このCファイルは、FreeBSD/ARM環境でのGoランタイムのシグナル処理ロジックを実装しています。

  • runtime·dumpregs(Mcontext *r): Mcontext構造体からARMレジスタの値を抽出し、runtime·printfで出力します。これは、プログラムがクラッシュした際に、CPUの状態をデバッグログに出力するために使用されます。
  • runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp):
    • Goランタイムの主要なシグナルハンドラです。OSからシグナルが配送されると、この関数が呼び出されます。
    • SIGPROF(プロファイリングシグナル)の場合、runtime·sigprofを呼び出してプロファイリングデータを収集します。
    • SigPanicフラグが設定されたシグナル(例: SIGSEGV, SIGBUS)の場合、Goのパニックメカニズムをトリガーします。gp->sig, gp->sigcode0, gp->sigcode1, gp->sigpcにシグナル情報を設定し、runtime·sigpanic関数を呼び出すようにレジスタ(特にr15 - プログラムカウンタ)を操作します。これにより、Goのパニック処理が開始され、スタックトレースが生成されます。
    • SigNotifyフラグが設定されたシグナルやSI_USER(ユーザーが生成したシグナル)の場合、runtime·sigsendを呼び出してGoのシグナル通知チャネルにシグナルを送信します。
    • SigKillフラグが設定されたシグナル(例: SIGKILL)の場合、runtime·exit(2)を呼び出してプログラムを終了します。
    • SigThrowフラグが設定されたシグナル(デフォルトの動作)の場合、runtime·startpanic()を呼び出し、シグナル情報とスタックトレースを出力してプログラムを終了します。
  • runtime·signalstack(byte *p, int32 n): sigaltstackシステムコールを呼び出して、代替シグナルスタックを設定します。これにより、通常のスタックが破損した場合でも、シグナルハンドラが安全に実行できる保証を提供します。
  • runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart): sigactionシステムコールを呼び出して、特定のシグナルiに対するハンドラ関数fnを設定します。SA_SIGINFOSA_ONSTACKフラグを設定し、必要に応じてSA_RESTARTフラグも設定します。runtime·sighandlerがハンドラとして設定される場合、実際にはアセンブリのruntime·sigtrampが登録されます。
  • runtime·cputicks(): CPUのティック数を返す関数で、runtime·nanotime()gettimeofdayシステムコールに基づく)の値を返します。

src/pkg/runtime/sys_freebsd_arm.s

このアセンブリファイルは、GoランタイムがFreeBSD/ARMカーネルのシステムコールを呼び出すためのラッパー関数を定義しています。

  • システムコール呼び出し規約:
    • ARMアーキテクチャでは、通常、システムコール番号はレジスタR7に設定されます(ただし、FreeBSDではSWI命令のオペランドとして直接指定されることが多い)。
    • 引数はR0R1R2R3などのレジスタに渡されます。引数がこれら4つのレジスタに収まらない場合、残りの引数はスタックにプッシュされます。
    • システムコールはSWI(Software Interrupt)命令を使用してトリガーされます。SWI命令のオペランドは、呼び出すシステムコールの番号です(例: SWI $454umtx_opシステムコール)。
    • システムコールの戻り値はR0レジスタに格納されます。エラーが発生した場合、R0にはエラーコードが設定され、Cフラグ(キャリーフラグ)がセットされます。
  • 主要なシステムコールラッパー:
    • runtime·sys_umtx_op: ユーザーランドミューテックス操作(umtx_opシステムコール)のラッパー。
    • runtime·thr_new: 新しいスレッドを作成する(thr_newシステムコール)のラッパー。
    • runtime·thr_start: 新しく作成されたスレッドの開始ルーチン。Goのmstart関数を呼び出して、Goスケジューラにスレッドを登録します。
    • runtime·exit, runtime·exit1: プログラムを終了する(exit, exit1システムコール)のラッパー。
    • runtime·write: ファイルディスクリプタにデータを書き込む(writeシステムコール)のラッパー。
    • runtime·getrlimit: リソース制限を取得する(getrlimitシステムコール)のラッパー。
    • runtime·setitimer: タイマーを設定する(setitimerシステムコール)のラッパー。
    • time·now, runtime·nanotime: 現在時刻を取得する(gettimeofdayシステムコール)のラッパー。nanotimeは秒とマイクロ秒からナノ秒を計算します。
    • runtime·sigaction: シグナルハンドラを設定する(sigactionシステムコール)のラッパー。
    • runtime·sigtramp: OSからシグナルハンドラが呼び出された際に、Goランタイムのコンテキスト(gmポインタ)を適切に設定し、C言語で記述されたruntime·sighandlerを呼び出すためのアセンブリルーチン。
    • runtime·mmap, runtime·munmap: メモリマッピングを行う/解除する(mmap, munmapシステムコール)のラッパー。
    • runtime·sigaltstack: 代替シグナルスタックを設定する(sigaltstackシステムコール)のラッパー。
    • runtime·usleep: 指定された時間だけスリープする(nanosleepシステムコール)のラッパー。
    • runtime·sysctl: カーネルパラメータを取得/設定する(sysctlシステムコール)のラッパー。
    • runtime·osyield: CPUを他のスレッドに譲る(sched_yieldシステムコール)のラッパー。
    • runtime·sigprocmask: シグナルマスクを変更する(sigprocmaskシステムコール)のラッパー。
    • runtime·cacheflush: キャッシュをフラッシュする(sysarchシステムコール)のラッパー。
    • runtime·casp, runtime·cas: アトミックな比較交換(Compare-And-Swap)操作を実装。これは、ARMv6以降のプロセッサで利用可能なアトミック命令(例: LDREX, STREX)を利用して実装されます。

これらのアセンブリラッパーは、GoランタイムがFreeBSD/ARMカーネルの機能に効率的かつ安全にアクセスするための基盤を提供します。

関連リンク

参考にした情報源リンク

  • Goのソースコード(特にsrc/runtimeディレクトリ)
  • FreeBSDのシステムコールに関するドキュメント(manページなど)
  • ARMアーキテクチャのリファレンスマニュアル
  • Goのランタイムに関する技術ブログや論文(一般的な情報源)