[インデックス 18277] ファイルの概要
このコミットは、GoランタイムがSolarisオペレーティングシステムをサポートするための変更を導入しています。具体的には、GOOS=solaris
環境でのビルドと実行を可能にするための、システムコール、メモリ管理、シグナルハンドリング、スレッドローカルストレージ(TLS)などの低レベルなOS固有の実装が追加されています。
コミット
commit a46b43493154bf3c59ce634ee9557a0b273de5ce
Author: Aram Hăvărneanu <aram@mgk.ro>
Date: Fri Jan 17 17:58:10 2014 +1300
runtime: add support for GOOS=solaris
R=alex.brainman, dave, jsing, gobot, rsc
CC=golang-codereviews
https://golang.org/cl/35990043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a46b43493154bf3c59ce634ee9557a0b273de5ce
元コミット内容
runtime: add support for GOOS=solaris
変更の背景
このコミットの背景には、Go言語のクロスプラットフォーム対応の拡大があります。Goは設計当初から様々なオペレーティングシステム(OS)とアーキテクチャをサポートすることを目指しており、その一環としてSolarisへの対応が求められました。Solarisは、特にエンタープライズ環境で利用されるUNIX系のOSであり、Goアプリケーションがこれらの環境でネイティブに動作できるようにすることは、Goの採用を促進する上で重要でした。
Goランタイムは、OS固有の機能(システムコール、スレッド管理、メモリ割り当て、シグナル処理など)に深く依存しています。新しいOSをサポートするためには、これらの低レベルなインタラクションをそのOSのAPIに合わせて実装し直す必要があります。このコミットは、Solaris/AMD64環境でGoプログラムが正しく動作するために必要な、これらのランタイムレベルの変更を網羅的に導入しています。
前提知識の解説
1. Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理するGo言語の不可欠な部分です。これには、ガベージコレクタ、スケジューラ(ゴルーチンをOSスレッドにマッピング)、メモリ割り当て、チャネル操作、システムコールインターフェースなどが含まれます。Goプログラムは、OSと直接対話するのではなく、ランタイムを介してこれらの低レベルな操作を実行します。
2. GOOSとGOARCH
GOOS
とGOARCH
は、Goのビルドシステムで使用される環境変数です。
GOOS
: ターゲットとなるオペレーティングシステム(例:linux
,windows
,darwin
,solaris
)。GOARCH
: ターゲットとなるアーキテクチャ(例:amd64
,arm
,386
)。 これらの変数を設定することで、Goコンパイラは特定のOSとアーキテクチャ向けにバイナリを生成します。このコミットでは、GOOS=solaris
のサポートが追加されています。
3. システムコール (System Calls)
システムコールは、ユーザー空間のプログラムがOSカーネルのサービスを要求するためのメカニズムです。ファイルI/O、メモリ管理、プロセス制御、ネットワーク通信など、OSが提供するほとんどの機能はシステムコールを介してアクセスされます。OSごとにシステムコールのインターフェースや番号が異なるため、新しいOSをサポートするには、そのOSのシステムコールをGoランタイムから呼び出せるようにマッピングする必要があります。
4. スレッドローカルストレージ (TLS: Thread-Local Storage)
TLSは、各スレッドが独自のデータコピーを持つことを可能にするメカニズムです。Goランタイムでは、ゴルーチン(Goの軽量スレッド)のコンテキスト情報や、現在のM(OSスレッド)に関する情報などをTLSに格納することがあります。AMD64アーキテクチャでは、FS
またはGS
レジスタがTLSベースアドレスを指すために使用されることが一般的ですが、OSによってその具体的な利用方法が異なります。Solarisでは、FS
レジスタがTLSのアクセスに使用されます。
5. シグナルハンドリング (Signal Handling)
シグナルは、OSがプロセスに非同期イベントを通知するためのメカニズムです。例えば、プログラムのエラー(セグメンテーション違反、浮動小数点例外など)や、外部からの終了要求(Ctrl+Cなど)はシグナルとして通知されます。Goランタイムは、これらのシグナルを捕捉し、適切に処理することで、パニックの発生、プログラムの終了、またはデバッグ情報の出力などを行います。OSごとにシグナルの種類やハンドリングのAPIが異なるため、Solaris固有のシグナルハンドリングの実装が必要です。
6. mmap
とメモリ管理
mmap
は、ファイルやデバイスをプロセスの仮想アドレス空間にマッピングするためのシステムコールです。メモリ割り当てにも使用され、特に大きなメモリ領域を確保する際に利用されます。Goランタイムのガベージコレクタやヒープ管理は、OSからのメモリ割り当てにmmap
のようなシステムコールを依存しています。Solarisにおけるmmap
の挙動やフラグは他のUNIX系OSと異なる場合があるため、適切な調整が必要です。
7. sem_t
(Semaphore)
セマフォは、複数のスレッド間で共有リソースへのアクセスを同期するためのプリミティブです。Goランタイムでは、ゴルーチンのスケジューリングやロック機構の一部としてセマフォが利用されることがあります。Solarisのsem_init
, sem_post
, sem_wait
などのセマフォAPIをGoランタイムから利用できるようにするためのラッパーが必要です。
技術的詳細
このコミットは、GoランタイムにSolaris/AMD64のサポートを追加するために、多岐にわたる変更を加えています。
1. ビルドシステム (src/cmd/dist/buildruntime.c
)
src/cmd/dist/buildruntime.c
に、GOOS=solaris
およびGOARCH=amd64
の組み合わせに対するTLSアクセス定義が追加されました。Solaris/AMD64では、FS
レジスタをTLSベースとして使用し、g
(ゴルーチン構造体)とm
(OSスレッド構造体)へのオフセットを定義しています。WinCall
がLibCall
にリネームされ、より汎用的なライブラリ呼び出しメカニズムとして扱われるようになりました。これは、Windows固有の呼び出し規約だけでなく、Solarisのような他のOSでのライブラリ呼び出しにも対応するためです。
2. アーキテクチャ固有の定義 (src/pkg/runtime/arch_amd64.h
)
RuntimeGogoBytes
の定義がSolaris向けに調整されました。これは、Goのスタック切り替えに関連する内部的なサイズであり、OSやアーキテクチャによって異なる場合があります。
3. アセンブリコードの変更 (src/pkg/runtime/asm_amd64.s
, src/pkg/runtime/rt0_solaris_amd64.s
, src/pkg/runtime/sys_solaris_amd64.s
)
src/pkg/runtime/asm_amd64.s
では、TLSセットアップのスキップ条件にSolarisが追加されました。src/pkg/runtime/rt0_solaris_amd64.s
は、Solaris/AMD64向けのGoプログラムのエントリポイントとなるアセンブリファイルです。_rt0_amd64_solaris
関数が定義され、main
関数を呼び出す前に基本的な初期化(argc
,argv
のセットアップ)を行います。また、runtime·issolaris
というグローバル変数が定義され、GoランタイムがSolaris上で動作していることを示すフラグとして使用されます。src/pkg/runtime/sys_solaris_amd64.s
は、Solaris固有のシステムコールや低レベルな関数をGoランタイムから呼び出すためのアセンブリラッパーを提供します。runtime·settls
: Solaris/AMD64におけるTLSのセットアップ。runtime·miniterrno
:errno
変数のTLSへのポインタを設定します。これは、Cライブラリ関数が設定するエラーコードをGoランタイムが正しく取得するために重要です。runtime·nanotime1
:clock_gettime
システムコールを呼び出して高精度な時間を取得します。runtime·pipe1
:pipe
システムコールを呼び出してパイプを作成します。runtime·asmsysvicall6
: SysV ABI(Application Binary Interface)に準拠したCライブラリ関数を呼び出すための汎用的なラッパーです。最大6つの整数引数をサポートし、m->libcall
構造体を使用して引数と戻り値をやり取りします。runtime·tstart_sysvicall
: 新しいOSスレッドが開始される際のエントリポイントです。TLSのg
とm
ポインタを設定し、Goスケジューラのruntime·mstart
を呼び出します。runtime·sigtramp
: シグナルハンドラが呼び出される際のエントリポイントです。シグナルコンテキストを保存し、Goランタイムのシグナルハンドラruntime·sighandler
を呼び出します。
4. CGO定義ファイル (src/pkg/runtime/defs_solaris.go
, src/pkg/runtime/defs_solaris_amd64.go
, src/pkg/runtime/defs_solaris_amd64.h
)
src/pkg/runtime/defs_solaris.go
は、SolarisのCヘッダファイルからGoの定数と型定義を生成するためのCGO入力ファイルです。sys/types.h
,sys/mman.h
,sys/signal.h
など、Solarisの主要なシステムヘッダがインポートされ、EINTR
,PROT_READ
,MAP_ANON
,SA_SIGINFO
,SIGHUP
などの定数や、SemT
,Sigaltstack
,Ucontext
などの構造体がGoの型として定義されます。src/pkg/runtime/defs_solaris_amd64.go
は、AMD64アーキテクチャ固有のレジスタ定義(REG_RAX
,REG_RSP
など)をGoの定数として定義します。src/pkg/runtime/defs_solaris_amd64.h
は、上記の.go
ファイルからcgo -cdefs
ツールによって生成されるCヘッダファイルです。GoランタイムのCコードからSolarisの定数や構造体定義にアクセスするために使用されます。
5. 環境変数とビルドタグ (src/pkg/runtime/env_posix.c
, src/pkg/runtime/netpoll.goc
, src/pkg/runtime/lock_sema.c
, src/pkg/runtime/signal_amd664.c
, src/pkg/runtime/signal_unix.c
)
- 既存のファイルに
+build solaris
タグが追加され、Solaris環境でこれらのファイルがビルドされるように設定されました。これにより、Goランタイムの共通部分がSolarisでも利用できるようになります。
6. メモリ管理 (src/pkg/runtime/mem_solaris.c
)
src/pkg/runtime/mem_solaris.c
は、Solaris固有のメモリ管理関数を実装しています。runtime·SysAlloc
:mmap
を使用してメモリを割り当てます。runtime·SysFree
:munmap
を使用してメモリを解放します。runtime·SysReserve
: メモリ領域を予約します。64ビットシステムでは、mmap
のPROT_NONE
フラグを使用して予約を行います。runtime·SysMap
: 予約されたメモリ領域を読み書き可能にします。
7. OS固有のランタイム実装 (src/pkg/runtime/os_solaris.c
, src/pkg/runtime/os_solaris.h
)
src/pkg/runtime/os_solaris.c
は、Solaris上でGoランタイムが動作するために必要な主要なOS固有の関数を実装しています。libc·___errno
などのCライブラリ関数の動的インポート(#pragma dynimport
)が多数追加されています。これにより、GoランタイムはSolarisの標準Cライブラリ関数を呼び出すことができます。runtime·sysvicall6
: SysV ABIに準拠したCライブラリ関数を呼び出すためのGo側のラッパーです。runtime·osinit
: OS固有の初期化を行います。CPU数を取得するgetncpu
を呼び出します。runtime·newosproc
: 新しいOSスレッドを作成します。pthread_create
を使用してスレッドを生成し、そのスレッドでGoランタイムのruntime·tstart_sysvicall
が実行されるように設定します。runtime·get_random_data
:/dev/urandom
から乱数を取得します。runtime·mpreinit
,runtime·minit
,runtime·unminit
: M(OSスレッド)の初期化と終了に関連する関数です。特にminit
では、シグナルハンドリングの初期化が行われます。runtime·sigpanic
: シグナルによって発生したパニックを処理します。SIGBUS
,SIGSEGV
,SIGFPE
などのシグナルに対応するパニックメッセージを生成します。runtime·memlimit
: プロセスが利用できるメモリの上限を取得します。runtime·setsig
,runtime·getsig
,runtime·signalstack
: シグナルハンドラの設定、取得、および代替シグナルスタックの設定を行います。runtime·semacreate
,runtime·semasleep
,runtime·semawakeup
: セマフォの作成、待機、通知を実装します。これらはSolarisのsem_init
,sem_wait
,sem_post
を呼び出します。runtime·close
,runtime·exit
,runtime·getcontext
,runtime·getrlimit
,runtime·mmap
,runtime·munmap
,runtime·nanotime
,runtime·open
,runtime·pthread_attr_destroy
,runtime·pthread_attr_getstack
,runtime·pthread_attr_init
,runtime·pthread_attr_setdetachstate
,runtime·pthread_attr_setstack
,runtime·pthread_create
,runtime·raise
,runtime·read
,runtime·sem_init
,runtime·sem_post
,runtime·sem_reltimedwait_np
,runtime·sem_wait
,runtime·setitimer
,runtime·sigaction
,runtime·sigaltstack
,runtime·sigprocmask
,runtime·sysconf
,runtime·usleep
,runtime·write
,runtime·osyield
: これらは、Solarisの対応するシステムコールやCライブラリ関数をGoランタイムから呼び出すためのラッパー関数です。
src/pkg/runtime/os_solaris.h
は、Solaris固有の定数(SS_DISABLE
,SIG_BLOCK
など)や、Rlimit
構造体、runtime·sysvicall6
のプロトタイプ宣言などを含んでいます。
8. プロセスとスケジューリング (src/pkg/runtime/proc.c
)
runtime·allocm
関数で、Solaris環境でもpthread_create
がスタックを作成することが考慮され、mp->g0
の割り当てロジックが更新されました。
9. ランタイム共通定義 (src/pkg/runtime/runtime.c
, src/pkg/runtime/runtime.h
)
runtime.c
にint32 runtime·issolaris;
が追加され、Solaris環境であるかどうかのフラグが導入されました。runtime.h
では、WinCall
構造体がLibCall
にリネームされ、より汎用的なライブラリ呼び出しのコンテキストを保持するように変更されました。また、M
構造体にSolaris固有のフィールド(perrno
,libcall
,ts
,scratch
)が追加され、低レベルなOS呼び出しに必要なデータがMごとに保持されるようになりました。GOOS_solaris
が定義されている場合にSolaris = 1
となる列挙型が追加されました。runtime·netpollarmread
とruntime·netpollarmwrite
のプロトタイプが追加され、Solarisのネットワークポーリングメカニズムに対応するための関数が用意されました。
10. シグナル定義 (src/pkg/runtime/signal_solaris_amd64.h
, src/pkg/runtime/signals_solaris.h
)
src/pkg/runtime/signal_solaris_amd64.h
は、Solaris/AMD64のシグナルコンテキスト(Ucontext
)からレジスタ値を取得するためのマクロ(SIG_RAX
,SIG_RIP
など)を定義しています。src/pkg/runtime/signals_solaris.h
は、Solarisのシグナル番号とそれに対応するGoランタイムのシグナル処理フラグ(SigNotify
,SigKill
,SigThrow
,SigPanic
,SigDefault
)および説明を定義したSigTab
配列を含んでいます。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は、主に以下のファイル群に集約されます。これらはSolaris上でGoランタイムが動作するための基盤を提供します。
src/pkg/runtime/os_solaris.c
: Solaris固有のシステムコールラッパー、スレッド管理、シグナルハンドリング、メモリ管理など、GoランタイムとSolarisカーネル間の主要なインタフェースを実装しています。このファイルは、GoランタイムがSolaris環境で動作するために不可欠な、OS固有の低レベルな詳細をカプセル化しています。src/pkg/runtime/sys_solaris_amd64.s
: Solaris/AMD64アーキテクチャに特化したアセンブリコードが含まれており、TLSのセットアップ、errno
の処理、高精度タイマーの取得、そしてSysV ABIに準拠したCライブラリ関数の呼び出し規約の処理など、非常に低レベルな操作を扱います。GoランタイムがSolarisのCライブラリと効率的に連携するために重要です。src/pkg/runtime/defs_solaris.go
およびsrc/pkg/runtime/defs_solaris_amd64.go
: これらのファイルは、SolarisのCヘッダファイルからGoの定数と型定義を生成するためのCGO入力ファイルです。Solarisのシステムコールやデータ構造をGoランタイムが理解し、利用できるようにするための基盤となります。src/pkg/runtime/runtime.h
:M
構造体(OSスレッドを表すGoランタイムの内部構造体)にSolaris固有のフィールドが追加された点が重要です。これにより、各OSスレッドがSolaris環境で必要なコンテキスト情報(errno
ポインタ、ライブラリ呼び出しバッファなど)を保持できるようになります。
これらのファイルは連携して、GoランタイムがSolarisのシステムリソースを効率的かつ安全に利用できるようにするための、OSとアーキテクチャに特化した抽象化レイヤーを形成しています。
コアとなるコードの解説
src/pkg/runtime/os_solaris.c
の主要な機能
- システムコールラッパー:
runtime·sysvicall6
関数は、SolarisのCライブラリ関数を呼び出すための汎用的なメカニズムを提供します。これは、Goランタイムが直接システムコールを発行するのではなく、Solarisの標準Cライブラリを介してOSサービスにアクセスするアプローチを取っていることを示しています。これにより、GoランタイムはSolarisのシステムコールインターフェースの複雑さを直接扱う必要がなくなります。 - スレッド管理:
runtime·newosproc
関数は、pthread_create
を呼び出して新しいOSスレッドを作成します。GoのM(OSスレッド)とG(ゴルーチン)のモデルにおいて、MはOSスレッドにマッピングされるため、OSスレッドの作成と管理はランタイムの重要な役割です。 - シグナルハンドリング:
runtime·setsig
やruntime·sigpanic
などの関数は、Solarisのシグナルメカニズムと連携し、Goプログラムがシグナルを適切に処理できるようにします。特にsigpanic
は、セグメンテーション違反や浮動小数点例外などの致命的なシグナルが発生した際に、Goのパニックメカニズムに変換する役割を担います。 - メモリ管理:
runtime·SysAlloc
,runtime·SysFree
,runtime·SysReserve
,runtime·SysMap
は、Solarisのmmap
およびmunmap
システムコールをGoランタイムのメモリ管理層に統合します。これにより、GoのガベージコレクタやヒープがSolaris上で正しく動作するための基盤が提供されます。 - セマフォ:
runtime·semacreate
,runtime·semasleep
,runtime·semawakeup
は、SolarisのPOSIXセマフォAPI(sem_init
,sem_wait
,sem_post
)をGoランタイムの同期プリミティブとして利用できるようにします。これは、ゴルーチンのスケジューリングやロックの実装に不可欠です。
src/pkg/runtime/sys_solaris_amd64.s
の主要な機能
- TLSアクセス:
get_tls
マクロは、AMD64アーキテクチャのFS
レジスタを利用してTLSにアクセスします。SolarisではFS
がTLSベースとして使用されるため、このマクロはGoランタイムが現在のゴルーチン(g
)やOSスレッド(m
)のコンテキストに効率的にアクセスするために重要です。 runtime·asmsysvicall6
: このアセンブリ関数は、GoランタイムからCライブラリ関数を呼び出す際のSysV ABIに準拠した呼び出し規約を処理します。引数を適切なレジスタに配置し、C関数の戻り値をGoランタイムが解釈できる形式で取得します。これは、GoとCの相互運用性において非常に重要な役割を果たします。runtime·sigtramp
: シグナルが発生した際にOSによって呼び出されるアセンブリ関数です。シグナルコンテキスト(レジスタの状態など)を保存し、GoランタイムのC言語で書かれたシグナルハンドラ(runtime·sighandler
)を呼び出します。これにより、Goランタイムはシグナルを捕捉し、Goのランタイム環境内で処理することができます。
src/pkg/runtime/defs_solaris.go
および src/pkg/runtime/defs_solaris_amd64.go
これらのファイルは、SolarisのCヘッダファイルで定義されている定数や構造体のレイアウトをGoのコードに「翻訳」する役割を担います。例えば、EINTR
やSIGSEGV
のようなエラーコードやシグナル番号、Ucontext
やSiginfo
のようなシグナルコンテキスト構造体のフィールドオフセットなどが定義されます。これにより、GoランタイムのCコードがSolarisのシステムAPIと正しくインタラクトできるようになります。
src/pkg/runtime/runtime.h
の M
構造体への追加
M
構造体へのperrno
, libcall
, ts
, scratch
フィールドの追加は、各OSスレッドがSolaris固有の操作に必要な状態を保持できるようにするために重要です。
perrno
: Cライブラリ関数が設定するerrno
変数のポインタを保持し、GoランタイムがC関数のエラーコードを正確に取得できるようにします。libcall
:runtime·sysvicall6
のような汎用的なライブラリ呼び出し関数が、呼び出し先の関数ポインタ、引数の数、引数リスト、戻り値などを一時的に格納するために使用します。ts
(Timespec) とscratch
: 低レベルなシステムコールやライブラリ呼び出しの際に、一時的なデータ(タイムアウト値や引数バッファなど)をスタックではなくM構造体内に保持することで、スタックオーバーフローのリスクを軽減し、アセンブリコードからのアクセスを容易にします。
これらの変更は、GoランタイムがSolarisの低レベルなOSインターフェースとシームレスに連携し、GoプログラムがSolaris環境で安定して動作するための基盤を構築しています。
関連リンク
- Go言語公式ドキュメント: https://golang.org/doc/
- Goのクロスコンパイルに関するドキュメント: https://go.dev/doc/install/source#environment
- Solaris オペレーティングシステム: https://www.oracle.com/solaris/
参考にした情報源リンク
- Goのコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Goのコードレビューシステム (Gerrit): https://go-review.googlesource.com/
- AMD64 System V Application Binary Interface: https://refspecs.linuxfoundation.org/AMD64-ABI-0.99.pdf
- Solaris man pages (例:
mmap(2)
,sigaction(2)
,sem_init(3C)
): Oracle Solarisの公式ドキュメントやオンラインマニュアルページ - Go runtime source code: https://github.com/golang/go/tree/master/src/runtime
- Go issue tracker: https://github.com/golang/go/issues
- Go mailing lists (golang-nuts, golang-dev): https://groups.google.com/g/golang-nuts, https://groups.google.com/g/golang-dev
- Stack Overflowや技術ブログ記事 (Go runtime, Solaris internals, system programming)