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

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

このコミットは、GoランタイムにDragonFly BSDオペレーティングシステムとAMD64アーキテクチャのサポートを追加するものです。具体的には、DragonFly BSD固有のシステムコール、メモリ管理、シグナルハンドリング、およびその他のOSレベルの機能に対応するための新しいファイルが多数追加され、既存のランタイムファイルにはDragonFly BSD向けのビルドタグが追加されています。

コミット

commit ac00524beb0a7c5069651a51682694144f1ed688
Author: Joel Sing <jsing@google.com>
Date:   Sat Aug 24 01:50:24 2013 +1000

    runtime: add dragonfly/amd64 port
    
    Go runtime support for dragonfly/amd64, largely based of the existing
    FreeBSD runtime (with some clues from the varialus/godfly work).
    
    R=bradfitz
    CC=golang-dev
    https://golang.org/cl/13088044

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

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

元コミット内容

runtime: add dragonfly/amd64 port

Go runtime support for dragonfly/amd64, largely based of the existing
FreeBSD runtime (with some clues from the varialus/godfly work).

R=bradfitz
CC=golang-dev
https://golang.org/cl/13088044

変更の背景

Go言語は、その設計思想として高い移植性を持っています。異なるオペレーティングシステム(OS)やCPUアーキテクチャ(GOOS/GOARCH)上でGoプログラムが動作するためには、Goランタイムがその特定のプラットフォームの低レベルな機能(システムコール、メモリ管理、スレッドスケジューリング、シグナルハンドリングなど)と適切に連携する必要があります。

このコミットが行われた2013年当時、Goは既にLinux、FreeBSD、Darwin(macOS)、Windowsなどの主要なOSをサポートしていましたが、DragonFly BSDは公式にはサポートされていませんでした。DragonFly BSDはFreeBSD 4.8からフォークしたOSであり、特にマルチプロセッシング環境でのパフォーマンスと安定性を向上させるための独自のカーネル設計(Lightweight Kernel Threads (LWKT) やHAMMERファイルシステムなど)を持っています。

GoプログラムがDragonFly BSD/amd64上でネイティブに動作するためには、GoランタイムがDragonFly BSDのシステムコールインターフェースやメモリ管理メカニズム、シグナル処理の特性を理解し、それらに合わせて実装される必要がありました。このコミットは、GoをDragonFly BSD/amd64環境に移植するための基盤を構築することを目的としています。コミットメッセージにある「largely based of the existing FreeBSD runtime (with some clues from the varialus/godfly work)」という記述から、既存のFreeBSDランタイムの実装を参考にしつつ、DragonFly BSD固有の差異に対応したことが伺えます。

前提知識の解説

DragonFly BSD

DragonFly BSDは、2003年にFreeBSD 4.8からフォークして開発が始まったUnix系オペレーティングシステムです。FreeBSDとは異なるアプローチでスレッドと対称型マルチプロセッシング(SMP)を追求しており、特に以下の特徴があります。

  • HAMMER/HAMMER2 ファイルシステム: スナップショット、チェックサム、データ重複排除などの機能を持つ独自のファイルシステム。
  • Lightweight Kernel Threads (LWKT): カーネル内の軽量なメッセージパッシングシステムで、マルチプロセッサシステムでのロックフリーなスケーラビリティを目指しています。各CPUが独自のスケジューラを持ちます。
  • Virtual Kernel (vkernel): 完全なDragonFlyカーネルをユーザー空間プロセスとして実行できる機能で、カーネルのテストと開発を簡素化します。
  • Swapcache: SSDの利用に最適化された機能で、ファイルシステムデータとメタデータをスワップ領域にキャッシュしてパフォーマンスを向上させます。

Goの移植においては、これらのOS固有の特性、特にシステムコール、メモリ管理、スレッドモデル、シグナル処理の差異を理解し、Goランタイムがそれらに適切に対応する必要があります。

Goランタイムの移植

Goランタイムの移植は、Goプログラムが特定のOSとアーキテクチャ上で動作するために、Goの内部動作とターゲットプラットフォームの深い理解を必要とする複雑な作業です。主な要素は以下の通りです。

  • ツールチェイン: コンパイラ、アセンブラ、リンカが新しいGOOS/GOARCHに対応する必要があります。
  • ランタイム (src/runtime): ゴルーチン、メモリ割り当て(ガベージコレクション)、OSとの相互作用を管理するGoの実行環境の中核です。
    • スケジューラ: ゴルーチンがOSスレッドにどのようにスケジューリングされるか。
    • メモリ管理: OSからメモリを要求し、管理する方法。
    • システムコール: 新しいGOOSに必要なシステムコールインターフェースの実装。
    • プラットフォーム固有のアセンブリ: コンテキストスイッチ、スタックアンワインド、シグナルハンドリングなどの重要な機能は、プラットフォーム固有のアセンブリで記述されることが多いです。
  • 標準ライブラリ: ossyscallnetなど、OSと直接対話する部分は、新しいGOOSに合わせた調整が必要です。

ビルドタグ (Build Tags)

Goのビルドタグ(またはビルド制約)は、特定の条件に基づいてファイルをビルドプロセスに含めるか除外するかを制御する強力な機能です。これにより、プラットフォーム固有のコードを管理したり、機能の有効/無効を切り替えたりすることができます。

  • 構文: Goソースファイルの先頭に//go:build(Go 1.17以降の新しい構文)または// +build(古い構文)の形式で記述します。
  • 使用例: //go:build linux && amd64 のように記述すると、LinuxかつAMD64アーキテクチャの場合にのみファイルがビルドに含まれます。
  • 本コミットでの利用: このコミットでは、DragonFly BSD固有のコードをGoランタイムに統合するために、+build dragonflyなどのビルドタグが既存のファイルに追加されたり、新しいファイルに付与されたりしています。

Futex (Fast User-space Mutex)

Futexは、LinuxやFreeBSDなどのOSで利用される低レベルの同期プリミティブです。ユーザー空間のスレッドがほとんどの同期操作をカーネルを介さずに行うことを可能にし、オーバーヘッドを削減します。スレッドがブロック(待機)またはウェイクアップする必要がある場合にのみカーネルが関与します。DragonFly BSDは独自の同期メカニズムを持っていますが、Goランタイムが効率的な同期を実現するためには、OSが提供する類似の機能を利用する必要があります。このコミットでは、umtx_sleepumtx_wakeupといったDragonFly BSDのユーザー空間ミューテックス(UMTX)関連のシステムコールが利用されています。

Kqueue

kqueueは、FreeBSD、NetBSD、OpenBSD、DragonFly BSDなどのBSD系OSでサポートされているスケーラブルなイベント通知インターフェースです。select()poll()といった古いポーリングシステムコールの限界を克服し、多数のファイルディスクリプタを効率的に監視できます。ファイル変更、シグナル、非同期I/O、子プロセスの状態変化、タイマーなど、幅広いイベントを扱えます。Goのネットワークポーリング(netpoll)は、OSが提供する効率的なI/O多重化メカニズムに依存するため、DragonFly BSDではkqueueがその役割を担います。

mmap (Memory Map)

mmapは、ファイルやデバイスをメモリにマッピングしたり、匿名メモリ領域を割り当てたりするためのシステムコールです。プロセスのアドレス空間とオブジェクト(ファイル、共有メモリ、匿名メモリ)の間にマッピングを確立し、メモリを直接アクセスすることで効率的なファイルアクセスやプロセス間通信を可能にします。Goランタイムのメモリ管理(ヒープの確保など)において、OSからメモリを要求する際にmmapが利用されます。

シグナルハンドリング (Signal Handling)

シグナルは、Unix系OSにおけるプロセス間通信やイベント管理の基本的なメカニズムです。プロセスに特定のイベント(エラー、外部からの割り込みなど)が発生したことを通知します。Goランタイムは、プログラムの異常終了(セグメンテーション違反、浮動小数点例外など)や、外部からの割り込み(Ctrl+Cなど)を適切に処理するために、OSのシグナルハンドリング機構と連携する必要があります。DragonFly BSDのシグナルハンドリングは、他のBSD系OSと多くの共通点がありますが、独自のLWKTとの統合など、特定の側面で差異があります。

技術的詳細

このコミットは、GoランタイムがDragonFly BSD/amd64上で動作するために必要な低レベルなOSインターフェースの実装に焦点を当てています。

  1. システムコールインターフェースの定義:

    • src/pkg/runtime/defs_dragonfly.go および src/pkg/runtime/defs_dragonfly_amd64.h は、DragonFly BSDのシステムコールで使用される定数(エラーコード、メモリ保護フラグ、mmapフラグ、シグナル番号など)と、関連するC構造体(rtprio, lwpparams, sigaltstack, sigset, stack_t, siginfo_t, mcontext_t, ucontext_t, timespec, timeval, itimerval, keventなど)をGoとCの双方から利用できるように定義しています。これらはcgoツールによって生成されるヘッダファイルであり、GoランタイムがOSのAPIと連携するための基盤となります。
    • 特にucontext_tmcontext_tは、シグナルハンドリングにおいてプロセスのコンテキスト(レジスタの状態など)を保存・復元するために不可欠です。
  2. メモリ管理の実装:

    • src/pkg/runtime/mem_dragonfly.c は、Goランタイムのメモリ管理機能(runtime·SysAlloc, runtime·SysUnused, runtime·SysUsed, runtime·SysFree, runtime·SysReserve, runtime·SysMap)をDragonFly BSDのmmapおよびmunmapシステムコールを使用して実装しています。
    • runtime·SysAllocは、MAP_ANON|MAP_PRIVATEフラグを使用して匿名メモリを割り当てます。
    • runtime·SysUnusedは、MADV_FREEを使用してメモリをOSに解放可能としてマークします。
    • runtime·SysMapでは、64-bit環境でのMAP_FIXEDの使用に関する注意点がコメントされており、DragonFly BSDが要求されたアドレスとは異なるアドレスを返す可能性があるという、OS固有の挙動への対応が見られます。これは、Goランタイムがメモリ領域を厳密に管理する必要があるため、重要な考慮事項です。
  3. OS固有のランタイム機能:

    • src/pkg/runtime/os_dragonfly.c は、DragonFly BSD固有のOSレベルのランタイム機能を提供します。
    • getncpu(): sysctlシステムコールを使用してCPUの数を取得します。
    • runtime·futexsleepruntime·futexwakeup: DragonFly BSDのumtx_sleepumtx_wakeupシステムコールを使用して、Goランタイムのフューテックス(ミューテックス)同期プリミティブを実装します。これは、Goのスケジューラがゴルーチンを効率的にブロック・アンブロックするために使用されます。
    • runtime·newosproc: 新しいOSスレッド(LWP: Lightweight Process)を作成するためにlwp_createシステムコールを使用します。GoのM(Machine)構造体とG(Goroutine)構造体の関連付け、およびTLS(Thread Local Storage)の設定もここで行われます。
    • runtime·osinit: OSの初期化を行い、CPU数を設定します。
    • runtime·get_random_data: /dev/urandomから乱数を読み込みます。
    • runtime·mpreinit, runtime·minit, runtime·unminit: M(Machine)構造体の初期化とクリーンアップに関連する関数で、シグナルスタックの設定などを行います。
    • runtime·sigpanic: シグナル発生時のパニック処理を実装します。SIGBUSSIGSEGVSIGFPEなどのシグナルに対して、Goのパニックメッセージを生成します。特に、g->sigcode1 < 0x1000のチェックは、NULLポインタ参照や無効なメモリアドレスへのアクセスを検出するための一般的なパターンです。
    • runtime·memlimit: getrlimitシステムコールを使用して、プロセスの仮想メモリ制限を取得します。
    • runtime·setsig, runtime·getsig, runtime·signalstack: sigactionおよびsigaltstackシステムコールを使用して、シグナルハンドラの設定とシグナルスタックの管理を行います。
  4. アセンブリコード:

    • src/pkg/runtime/rt0_dragonfly_amd64.s は、Goプログラムのエントリポイントとなるアセンブリコードです。OSがプログラムをロードした際に最初に実行され、Goランタイムの初期化ルーチン(_rt0_go)にジャンプします。
    • src/pkg/runtime/sys_dragonfly_amd64.s は、DragonFly BSD/amd64固有のシステムコールラッパーを定義しています。umtx_sleep, umtx_wakeup, lwp_create, exit, open, close, read, write, getrlimit, raise, setitimer, time·now, runtime·nanotime, sigaction, mmap, munmap, madvise, sigaltstack, usleep, settls, sysctl, osyield, sigprocmask, kqueue, kevent, closeonexecといったシステムコールが、Goのアセンブリ規約に従って呼び出せるように実装されています。特にruntime·sigtrampは、シグナルハンドラが呼び出される際の中間層として機能し、Goのランタイムコンテキスト(MとG)を適切に設定します。
  5. ビルドタグの更新:

    • src/pkg/runtime/env_posix.c, src/pkg/runtime/export_futex_test.go, src/pkg/runtime/futex_test.go, src/pkg/runtime/lock_futex.c, src/pkg/runtime/netpoll.goc, src/pkg/runtime/netpoll_kqueue.c, src/pkg/runtime/signal_386.c, src/pkg/runtime/signal_amd64.c, src/pkg/runtime/signal_arm.c, src/pkg/runtime/signal_unix.c といった既存のファイルに、+build dragonflyタグが追加されています。これにより、これらのファイルがDragonFly BSD環境でもビルドされるようになります。例えば、futex_test.goは「Futex is only available on Dragonfly, FreeBSD and Linux.」というコメントに更新され、DragonFly BSDでのフューテックスのサポートが明示されています。

このコミットは、Goが新しいOSをサポートするために、OS固有の低レベルなインターフェースをGoランタイムに統合する典型的な例を示しています。既存のFreeBSDランタイムをベースにすることで開発コストを抑えつつ、DragonFly BSDの独自の特性(UMTX、LWKTなど)に対応するための調整が行われています。

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

このコミットでは、主に以下のファイルが新規追加または変更されています。

新規追加ファイル:

  • src/pkg/runtime/defs_dragonfly.go: DragonFly BSDのシステムコールで使用される定数や構造体のGo言語側での定義。
  • src/pkg/runtime/defs_dragonfly_amd64.h: defs_dragonfly.goからcgoによって生成される、DragonFly BSD/amd64固有のCヘッダファイル。
  • src/pkg/runtime/mem_dragonfly.c: DragonFly BSDにおけるGoランタイムのメモリ管理(mmap, munmap, madviseなど)の実装。
  • src/pkg/runtime/os_dragonfly.c: DragonFly BSD固有のOSレベルのランタイム機能(スレッド作成、シグナルハンドリング、フューテックスなど)の実装。
  • src/pkg/runtime/os_dragonfly.h: os_dragonfly.cで使用されるDragonFly BSD固有の定義や関数プロトタイプ。
  • src/pkg/runtime/rt0_dragonfly_amd64.s: DragonFly BSD/amd64におけるGoプログラムのエントリポイントとなるアセンブリコード。
  • src/pkg/runtime/signal_dragonfly_amd64.h: DragonFly BSD/amd64におけるシグナルハンドリング関連のレジスタマクロ定義。
  • src/pkg/runtime/signals_dragonfly.h: DragonFly BSDにおけるシグナル番号とそれに対応するGoランタイムのシグナル処理フラグの定義。
  • src/pkg/runtime/sys_dragonfly_amd64.s: DragonFly BSD/amd64固有のシステムコールを呼び出すためのアセンブリラッパー。

変更された既存ファイル:

  • src/pkg/runtime/env_posix.c: POSIX環境変数関連のビルドタグにdragonflyを追加。
  • src/pkg/runtime/export_futex_test.go: フューテックスのテストのビルドタグにdragonflyを追加。
  • src/pkg/runtime/futex_test.go: フューテックスのテストのビルドタグにdragonflyを追加し、コメントを更新。
  • src/pkg/runtime/lock_futex.c: フューテックスロックの実装のビルドタグにdragonflyを追加。
  • src/pkg/runtime/netpoll.goc: ネットワークポーリング関連のビルドタグにdragonflyを追加。
  • src/pkg/runtime/netpoll_kqueue.c: kqueueベースのネットワークポーリングのビルドタグにdragonflyを追加。
  • src/pkg/runtime/signal_386.c, src/pkg/runtime/signal_amd64.c, src/pkg/runtime/signal_arm.c: 各アーキテクチャのシグナル処理のビルドタグにdragonflyを追加。
  • src/pkg/runtime/signal_unix.c: Unixシグナル処理のビルドタグにdragonflyを追加。

合計で19ファイルが変更され、1176行が追加、11行が削除されています。これは、Goランタイムの移植が広範囲にわたる変更を伴うことを示しています。

コアとなるコードの解説

このコミットの核となるのは、GoランタイムがDragonFly BSDのカーネルと直接対話するためのインターフェースと実装です。

  1. src/pkg/runtime/defs_dragonfly.gosrc/pkg/runtime/defs_dragonfly_amd64.h:

    • これらのファイルは、GoとCの間の橋渡しをします。defs_dragonfly.goはGoのコードからCのヘッダファイルをインポートし、OS固有の定数(EINTR, PROT_READ, MAP_ANON, SIGHUPなど)や構造体(Rtprio, Siginfo, Ucontext, Keventなど)をGoの型として定義します。
    • defs_dragonfly_amd64.hは、defs_dragonfly.gocgo -cdefsで処理することで生成されます。これには、GoランタイムがCのシステムコールを呼び出す際に必要となる、これらの定数や構造体の具体的な値とレイアウトが含まれます。これにより、GoランタイムはDragonFly BSDのAPIとバイナリ互換性を持つことができます。
  2. src/pkg/runtime/mem_dragonfly.c:

    • Goのメモリ管理は、OSからメモリを要求し、解放する機能に依存します。このファイルは、Goランタイムのメモリ割り当て関数(runtime·SysAlloc, runtime·SysReserve, runtime·SysMapなど)をDragonFly BSDのmmapシステムコールを使って実装しています。
    • runtime·SysAllocは、新しいメモリ領域を匿名かつプライベートにマップします。
    • runtime·SysMapは、予約されたメモリ領域を読み書き可能にマップします。特に、64-bit環境でMAP_FIXEDを使用する際のDragonFly BSDの挙動(要求アドレスと異なるアドレスを返す可能性)に対応するためのロジックが含まれており、OSの細かな特性への対応が伺えます。
  3. src/pkg/runtime/os_dragonfly.c:

    • このファイルは、GoランタイムがDragonFly BSD上で動作するために必要な、OS固有の主要な機能を提供します。
    • フューテックスの実装: runtime·futexsleepruntime·futexwakeupは、DragonFly BSDのumtx_sleepumtx_wakeupシステムコールを呼び出します。これらは、Goのスケジューラがゴルーチンを効率的にブロック・アンブロックするために使用される低レベルの同期プリミティブです。
    • スレッド作成: runtime·newosprocは、lwp_createシステムコールを使用して新しいOSスレッド(Lightweight Process)を作成します。GoのM(Machine)とG(Goroutine)のコンテキストを新しいスレッドに設定し、GoランタイムのスケジューラがOSスレッドを管理できるようにします。
    • シグナルハンドリング: runtime·sigpanicは、OSからシグナルが送られてきた際にGoのパニックを発生させるためのロジックを含みます。SIGBUSSIGSEGVなどのシグナルに対して、Goのランタイムが適切なエラーメッセージを生成し、デバッグを支援します。また、runtime·setsigruntime·signalstackは、sigactionsigaltstackシステムコールを介してシグナルハンドラの設定やシグナルスタックの管理を行います。
  4. src/pkg/runtime/sys_dragonfly_amd64.s:

    • このアセンブリファイルは、GoランタイムがDragonFly BSDのシステムコールを直接呼び出すためのラッパー関数を提供します。Goの関数呼び出し規約とOSのシステムコール呼び出し規約(レジスタの使用方法など)の間の変換を行います。
    • 例えば、TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$0 のようなエントリは、Goのコードからruntime·sys_umtx_sleepが呼び出された際に、引数を適切なレジスタに配置し、umtx_sleepシステムコール(システムコール番号469)を実行します。
    • runtime·sigtrampは、シグナル発生時にOSから呼び出されるアセンブリルーチンです。これは、Goのシグナルハンドラ(runtime·sighandler)を呼び出す前に、Goのランタイムコンテキスト(現在のMとG)をシグナル処理用の特別なG(m->gsignal)に切り替える役割を担います。これにより、シグナルハンドラが安全に実行され、元のゴルーチンの状態を破壊しないようにします。

これらのファイル群は、GoランタイムがDragonFly BSDのカーネルと低レベルで連携し、メモリ管理、スレッドスケジューリング、シグナル処理といったOSの基本的な機能をGoプログラムから利用できるようにするための基盤を形成しています。既存のFreeBSDランタイムのコードを参考にしつつ、DragonFly BSD固有のシステムコールやデータ構造に合わせて調整が行われている点が特徴です。

関連リンク

参考にした情報源リンク