[インデックス 1873] ファイルの概要
このコミットは、Goランタイムの初期段階における重要なリファクタリングを示しています。rt1.c
という単一のファイルに集約されていたシグナルハンドリングとスレッド関連のロジックが、signal.c
とthread.c
という2つの独立したファイルに分割されました。さらに、これらのファイルはアーキテクチャ固有のディレクトリ(amd64/
)からOS固有のディレクトリ(darwin/
やlinux/
)に移動され、より汎用的な配置になりました。また、不要になったsys_types.h
ファイルが削除されています。
コミット
commit 8ee041dc24f46047f6cff0d61bd634d1cacfc380
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 24 13:17:10 2009 -0700
split rt1.c into signal.c and thread.c.
move out of arch-specific directory: only os-specific.
rm sys_types.h (unused).
TBR=r
OCL=26681
CL=26681
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8ee041dc24f46047f6cff0d61bd634d1cacfc380
元コミット内容
split rt1.c into signal.c and thread.c.
move out of arch-specific directory: only os-specific.
rm sys_types.h (unused).
TBR=r
OCL=26681
CL=26681
変更の背景
このコミットが行われた2009年3月は、Go言語がまだ一般に公開される前の、活発な開発初期段階にあたります。Goランタイムは、異なるオペレーティングシステム(OS)やCPUアーキテクチャ上でGoプログラムが効率的に動作するための基盤を提供します。初期のランタイムコードは、機能が単一のファイルに集約されていることがよくありました。
rt1.c
というファイルは、Goランタイムの初期実装において、シグナルハンドリング(プログラムが外部イベントやエラーに応答するメカニズム)とスレッド管理(並行処理の基本単位)の両方を担当していました。しかし、これらの機能はそれぞれ独立した複雑なサブシステムであり、単一のファイルにまとまっていると、コードの可読性、保守性、および拡張性が低下します。
この変更の背景には、以下の目的があったと考えられます。
- コードのモジュール化と責務の分離: シグナル処理とスレッド処理は異なる関心事であり、それぞれを独立したファイルに分離することで、各ファイルの責務が明確になり、コードの理解が容易になります。
- 保守性の向上: 機能ごとにファイルが分かれることで、特定の機能にバグが見つかった場合や、新しい機能を追加する際に、影響範囲を限定しやすくなります。
- クロスプラットフォーム対応の改善: シグナルハンドリングやスレッド管理はOSに強く依存する部分です。
amd64/rt1.c
のようなアーキテクチャ固有のディレクトリから、darwin/
やlinux/
といったOS固有のディレクトリに移動することで、OSごとの実装の違いをより明確に管理できるようになります。これにより、新しいOSへの対応や既存OSの特定の挙動への対応が容易になります。 - 不要なコードの削除: 開発が進むにつれて、初期に作成されたファイルや定義が不要になることがあります。
sys_types.h
の削除は、コードベースのクリーンアップと効率化の一環です。
これらの変更は、Goランタイムがより堅牢で、スケーラブルで、将来の機能拡張に対応できるような基盤を築くための、初期の重要なステップでした。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
Goランタイム (Go Runtime): Goプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。Goランタイムは、ガベージコレクション、スケジューラ(goroutineの管理)、メモリ管理、システムコールインターフェース、シグナルハンドリングなど、Goプログラムの実行に必要な低レベルの機能を提供します。C言語で書かれた部分が多く、OSやアーキテクチャに依存する処理を抽象化しています。
-
シグナルハンドリング (Signal Handling): シグナルは、オペレーティングシステムがプロセスに送信する非同期通知です。これらは、プログラムの異常終了(例: セグメンテーション違反、ゼロ除算)、外部イベント(例: Ctrl+Cによる割り込み)、タイマーの期限切れなど、様々な状況で発生します。プログラムはシグナルを受信した際に、デフォルトの動作(プロセス終了など)を実行するか、カスタムのシグナルハンドラ関数を登録して特定の処理を行うことができます。Goランタイムは、Goプログラムがシグナルを適切に処理し、クラッシュを回避したり、デバッグ情報(スタックトレースなど)を出力したりするために、独自のシグナルハンドリングメカニズムを持っています。
-
スレッド (Threads): スレッドは、プロセス内で実行される独立した実行パスです。同じプロセス内のスレッドはメモリ空間を共有するため、効率的なデータ共有が可能です。Go言語のgoroutineは、OSスレッド上で多重化される軽量なスレッドであり、GoランタイムのスケジューラがgoroutineをOSスレッドにマッピングして実行を管理します。このコミットにおける「スレッド」は、Goランタイムが内部的に使用するOSスレッドの管理に関連する部分を指します。
-
Makefile
:Makefile
は、ソフトウェアプロジェクトのビルドプロセスを自動化するためのファイルです。make
コマンドによって解釈され、ソースファイルのコンパイル順序、依存関係、リンク方法などを定義します。このコミットでは、新しいファイルが追加されたため、ビルドプロセスにそれらを含めるようにMakefile
が更新されています。 -
amd64
、darwin
、linux
: これらはそれぞれ、CPUアーキテクチャとオペレーティングシステムを指します。amd64
: x86-64ビットアーキテクチャ。darwin
: AppleのmacOS(旧OS X)のカーネル。linux
: Linuxカーネル。 Goランタイムは、これらの異なる環境で動作するために、それぞれの環境に特化したコードを持つ必要があります。
-
rt1.c
: Goランタイムの初期段階で存在したC言語のソースファイルで、シグナルハンドリングやスレッド関連の低レベルな処理が含まれていました。このコミットで分割・リネームの対象となっています。 -
sys_types.h
: システムコールやデータ型定義など、システムレベルの型定義を含むヘッダーファイル。このコミットでは不要と判断され削除されました。
技術的詳細
このコミットの技術的な詳細は、主に以下の3つの側面から分析できます。
-
rt1.c
の分割: 元のrt1.c
ファイルは、シグナル処理とスレッド処理の両方のロジックを含んでいました。このコミットでは、これらの機能が明確に分離され、signal.c
とthread.c
という新しいファイルにそれぞれ移動されました。signal.c
: シグナルハンドラの登録、シグナル情報の取得、スタックトレースの出力など、シグナル関連の低レベルな処理が含まれるようになりました。DarwinとLinuxでそれぞれ異なる実装が提供されています。thread.c
: スレッドの作成、管理、同期プリミティブ(セマフォなど)の初期化といった、スレッド関連の処理が含まれるようになりました。
-
ディレクトリ構造の変更: 元の
rt1.c
は、src/runtime/darwin/amd64/rt1.c
やsrc/runtime/linux/amd64/rt1.c
のように、OSとアーキテクチャの両方に特化したディレクトリに配置されていました。この変更により、signal.c
とthread.c
はsrc/runtime/darwin/
やsrc/runtime/linux/
といったOS固有のディレクトリに移動されました。 これは、シグナルハンドリングやスレッド管理の多くの側面が、CPUアーキテクチャよりもOSのシステムコールインターフェースに強く依存するという認識に基づいています。例えば、sigaction
やsigaltstack
のようなシステムコールはOSによって提供され、そのAPIはOS間で大きく異なりますが、同じOS内であれば異なるアーキテクチャでも共通のインターフェースを持つことが多いです。この変更により、コードの再利用性が向上し、OSごとの差異をより効率的に管理できるようになります。 -
sys_types.h
の削除:src/runtime/sys_types.h
は、条件付きコンパイル(#ifdef amd64_linux
など)を使用して、特定のOS/アーキテクチャ固有のヘッダーファイル(amd64_linux.h
やamd64_darwin.h
)をインクルードしていました。このコミットでsys_types.h
が削除されたのは、おそらく、新しいsignal.c
やthread.c
が直接必要なヘッダーをインクルードするようになり、この抽象化レイヤーが不要になったためと考えられます。これは、依存関係をより明示的にし、不要な間接参照を排除するクリーンアップの一環です。
これらの変更は、Goランタイムの内部構造をより整理し、将来の拡張や異なるプラットフォームへの移植を容易にするための基盤を強化するものです。特に、シグナルとスレッドという並行処理の根幹をなす部分の分離は、Goの並行処理モデル(goroutineとチャネル)を支えるランタイムの安定性と効率性を高める上で不可欠なステップでした。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、以下のファイルに集中しています。
-
src/runtime/Makefile
:rt1.$O
のビルド対象からの削除。signal.$O
とthread.$O
のビルド対象への追加。 これにより、ビルドシステムが新しいファイル構成を認識し、正しくコンパイル・リンクされるようになります。
-
src/runtime/darwin/signal.c
(新規追加):- Darwin(macOS)環境におけるシグナルハンドリングのロジックが実装されています。
_STRUCT_X86_THREAD_STATE64
などのDarwin固有の構造体定義が含まれます。print_thread_state
関数(デバッグ目的でスレッドの状態レジスタを出力)が定義されています。sighandler
関数(実際のシグナル処理ロジック、スタックトレース出力など)が定義されています。initsig
関数(シグナルハンドラの初期設定)が定義されています。signalstack
関数(代替シグナルスタックの設定)が定義されています。
-
src/runtime/darwin/{amd64/rt1.c => thread.c}
(リネームと内容変更):- 元の
rt1.c
からシグナル関連のコードが削除され、スレッド関連のコードのみが残されました。 - ファイル名が
thread.c
に変更され、OS固有のディレクトリに移動されました。 initsema
(セマフォの初期化)やxadd
(アトミック加算)といった、スレッド同期に関連するヘルパー関数が含まれています。
- 元の
-
src/runtime/linux/signal.c
(新規追加):- Linux環境におけるシグナルハンドリングのロジックが実装されています。
_fpstate
,sigcontext
,ucontext
などのLinux固有の構造体定義が含まれます。print_sigcontext
関数(デバッグ目的でシグナルコンテキストを出力)が定義されています。sighandler
関数(実際のシグナル処理ロジック、スタックトレース出力など)が定義されています。initsig
関数(シグナルハンドラの初期設定)が定義されています。signalstack
関数(代替シグナルスタックの設定)が定義されています。
-
src/runtime/linux/{amd64/rt1.c => thread.c}
(リネームと内容変更):- 元の
rt1.c
からシグナル関連のコードが削除され、スレッド関連のコードのみが残されました。 - ファイル名が
thread.c
に変更され、OS固有のディレクトリに移動されました。 - Linuxのfutex(Fast Userspace muTEX)に関するコメントが残っており、スレッド同期の低レベルな実装に関連する部分であることが示唆されます。
- 元の
-
src/runtime/sys_types.h
(削除):- このヘッダーファイルは完全に削除されました。これにより、各OS/アーキテクチャ固有のヘッダーは、それらを必要とするファイルによって直接インクルードされるようになりました。
これらの変更により、Goランタイムのシグナルとスレッドに関するコードが、OSごとに整理され、よりモジュール化された構造になりました。
コアとなるコードの解説
このコミットの核心は、GoランタイムがOSからのシグナルをどのように処理し、また内部的なスレッドをどのように管理するかという、低レベルなメカニズムの再編成にあります。
シグナルハンドリング (signal.c
):
Goランタイムは、プログラムのクラッシュ(例: セグメンテーション違反)や外部からの割り込み(例: Ctrl+C)といったシグナルを捕捉し、適切に処理する必要があります。signal.c
ファイルは、このシグナル処理のOS固有の実装を含んでいます。
sighandler
関数: これは、OSがシグナルをプロセスに送信したときに呼び出されるGoランタイムの主要なシグナルハンドラです。panicking
フラグをチェックし、既にパニック状態であれば二重パニックを防ぎます。- シグナル番号と、シグナルが発生したアドレス(
info->si_addr
)やプログラムカウンタ(ss->__rip
またはsc->rip
)などの情報を出力します。 gotraceback()
が真の場合、traceback
関数を呼び出して現在のgoroutineのスタックトレースを出力します。これはデバッグ時に非常に役立ちます。- 最終的に
sys_Exit(2)
を呼び出してプロセスを終了させます。これは、Goランタイムが捕捉した致命的なシグナルに対するデフォルトの挙動です。
initsig
関数: Goプログラムの起動時に、Goランタイムが捕捉すべきシグナルに対してカスタムのシグナルハンドラ(sighandler
またはsigignore
)を登録します。sigaction
システムコール(またはrt_sigaction
)を使用して、シグナルハンドラ関数、シグナルマスク、およびフラグ(SA_SIGINFO
,SA_ONSTACK
,SA_RESTART
など)を設定します。SA_ONSTACK
フラグは、シグナルハンドラが通常のスタックではなく、代替シグナルスタック(signalstack
で設定)で実行されることを保証し、スタックオーバーフローによるシグナル処理の失敗を防ぎます。sigtramp
はアセンブリルーチンで、シグナルハンドラを呼び出す前にレジスタの状態を保存し、スタックを適切に設定する役割を担います。
スレッド管理 (thread.c
):
Goランタイムは、goroutineをOSスレッド上で実行するために、OSスレッドの作成、管理、および同期を行う必要があります。thread.c
ファイルは、これらのスレッド関連の低レベルな処理を含んでいます。
initsema
関数 (Darwin): Machカーネルのセマフォ(mach_semcreate
)を初期化します。これは、Goランタイムが内部的な同期プリミティブとして使用するものです。cas
(Compare-And-Swap) 操作を使用して、複数のスレッドが同時にセマフォを初期化しようとした場合の競合状態を防ぎます。xadd
関数 (Darwin): アトミックな加算操作を実装しています。これは、複数のスレッドから共有変数に安全にアクセスするために使用されます。- Linux版の
thread.c
には、futex(Fast Userspace muTEX)に関するコメントがあり、Linuxにおける低レベルなスレッド同期メカニズムへの言及が見られます。
Makefile
の変更:
Makefile
の変更は、これらの新しいファイルがGoランタイムのビルドプロセスに正しく組み込まれることを保証します。rt1.$O
が削除され、signal.$O
とthread.$O
が追加されることで、ビルドシステムは分割された新しいモジュールをコンパイルし、最終的なランタイムバイナリにリンクするようになります。
このコミットは、Goランタイムの初期設計において、シグナルとスレッドというOSに密接に関連する機能を、よりクリーンで保守性の高い方法で分離し、Goの並行処理モデルの基盤を強化した重要な一歩と言えます。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goランタイムのソースコード(現在のバージョン): https://github.com/golang/go/tree/master/src/runtime
- Goのシグナルハンドリングに関する議論(GoのIssueトラッカーなど): Goの初期のシグナルハンドリングに関する具体的なIssueは特定が難しいですが、
go.dev/issue
でsignal
やruntime
を検索すると関連する議論が見つかる可能性があります。
参考にした情報源リンク
- Go言語のソースコード(GitHub): https://github.com/golang/go
- Go言語のコミット履歴: https://github.com/golang/go/commits/master
- オペレーティングシステムのシグナルに関する一般的な情報(例: Linux man pages for
signal(7)
,sigaction(2)
,ucontext(3)
など) - Machカーネルのセマフォに関する情報(Darwin固有のシステムプログラミングドキュメントなど)
- futexに関する情報(Linuxカーネルのドキュメントなど)
- Go言語の初期開発に関するブログ記事やメーリングリストのアーカイブ(Goがオープンソース化される前の情報を見つけるのは難しい場合がありますが、GoのブログやGoogle Groupsのgolang-nutsアーカイブなどが参考になる可能性があります)。
[インデックス 1873] ファイルの概要
このコミットは、Goランタイムの初期段階における重要なリファクタリングを示しています。rt1.c
という単一のファイルに集約されていたシグナルハンドリングとスレッド関連のロジックが、signal.c
とthread.c
という2つの独立したファイルに分割されました。さらに、これらのファイルはアーキテクチャ固有のディレクトリ(amd64/
)からOS固有のディレクトリ(darwin/
やlinux/
)に移動され、より汎用的な配置になりました。また、不要になったsys_types.h
ファイルが削除されています。
コミット
commit 8ee041dc24f46047f6cff0d61bd634d1cacfc380
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 24 13:17:10 2009 -0700
split rt1.c into signal.c and thread.c.
move out of arch-specific directory: only os-specific.
rm sys_types.h (unused).
TBR=r
OCL=26681
CL=26681
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8ee041dc24f46047f6cff0d61bd634d1cacfc380
元コミット内容
split rt1.c into signal.c and thread.c.
move out of arch-specific directory: only os-specific.
rm sys_types.h (unused).
TBR=r
OCL=26681
CL=26681
変更の背景
このコミットが行われた2009年3月は、Go言語がまだ一般に公開される前の、活発な開発初期段階にあたります。Goランタイムは、異なるオペレーティングシステム(OS)やCPUアーキテクチャ上でGoプログラムが効率的に動作するための基盤を提供します。初期のランタイムコードは、機能が単一のファイルに集約されていることがよくありました。
rt1.c
というファイルは、Goランタイムの初期実装において、シグナルハンドリング(プログラムが外部イベントやエラーに応答するメカニズム)とスレッド管理(並行処理の基本単位)の両方を担当していました。しかし、これらの機能はそれぞれ独立した複雑なサブシステムであり、単一のファイルにまとまっていると、コードの可読性、保守性、および拡張性が低下します。
この変更の背景には、以下の目的があったと考えられます。
- コードのモジュール化と責務の分離: シグナル処理とスレッド処理は異なる関心事であり、それぞれを独立したファイルに分離することで、各ファイルの責務が明確になり、コードの理解が容易になります。
- 保守性の向上: 機能ごとにファイルが分かれることで、特定の機能にバグが見つかった場合や、新しい機能を追加する際に、影響範囲を限定しやすくなります。
- クロスプラットフォーム対応の改善: シグナルハンドリングやスレッド管理はOSに強く依存する部分です。
amd64/rt1.c
のようなアーキテクチャ固有のディレクトリから、darwin/
やlinux/
といったOS固有のディレクトリに移動することで、OSごとの実装の違いをより明確に管理できるようになります。これにより、新しいOSへの対応や既存OSの特定の挙動への対応が容易になります。 - 不要なコードの削除: 開発が進むにつれて、初期に作成されたファイルや定義が不要になることがあります。
sys_types.h
の削除は、コードベースのクリーンアップと効率化の一環です。
これらの変更は、Goランタイムがより堅牢で、スケーラブルで、将来の機能拡張に対応できるような基盤を築くための、初期の重要なステップでした。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
Goランタイム (Go Runtime): Goプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。Goランタイムは、ガベージコレクション、スケジューラ(goroutineの管理)、メモリ管理、システムコールインターフェース、シグナルハンドリングなど、Goプログラムの実行に必要な低レベルの機能を提供します。C言語で書かれた部分が多く、OSやアーキテクチャに依存する処理を抽象化しています。
-
シグナルハンドリング (Signal Handling): シグナルは、オペレーティングシステムがプロセスに送信する非同期通知です。これらは、プログラムの異常終了(例: セグメンテーション違反、ゼロ除算)、外部イベント(例: Ctrl+Cによる割り込み)、タイマーの期限切れなど、様々な状況で発生します。プログラムはシグナルを受信した際に、デフォルトの動作(プロセス終了など)を実行するか、カスタムのシグナルハンドラ関数を登録して特定の処理を行うことができます。Goランタイムは、Goプログラムがシグナルを適切に処理し、クラッシュを回避したり、デバッグ情報(スタックトレースなど)を出力したりするために、独自のシグナルハンドリングメカニズムを持っています。
-
スレッド (Threads): スレッドは、プロセス内で実行される独立した実行パスです。同じプロセス内のスレッドはメモリ空間を共有するため、効率的なデータ共有が可能です。Go言語のgoroutineは、OSスレッド上で多重化される軽量なスレッドであり、GoランタイムのスケジューラがgoroutineをOSスレッドにマッピングして実行を管理します。このコミットにおける「スレッド」は、Goランタイムが内部的に使用するOSスレッドの管理に関連する部分を指します。
-
Makefile
:Makefile
は、ソフトウェアプロジェクトのビルドプロセスを自動化するためのファイルです。make
コマンドによって解釈され、ソースファイルのコンパイル順序、依存関係、リンク方法などを定義します。このコミットでは、新しいファイルが追加されたため、ビルドプロセスにそれらを含めるようにMakefile
が更新されています。 -
amd64
、darwin
、linux
: これらはそれぞれ、CPUアーキテクチャとオペレーティングシステムを指します。amd64
: x86-64ビットアーキテクチャ。darwin
: AppleのmacOS(旧OS X)のカーネル。linux
: Linuxカーネル。 Goランタイムは、これらの異なる環境で動作するために、それぞれの環境に特化したコードを持つ必要があります。
-
rt1.c
: Goランタイムの初期段階で存在したC言語のソースファイルで、シグナルハンドリングやスレッド関連の低レベルな処理が含まれていました。このコミットで分割・リネームの対象となっています。 -
sys_types.h
: システムコールやデータ型定義など、システムレベルの型定義を含むヘッダーファイル。このコミットでは不要と判断され削除されました。
技術的詳細
このコミットの技術的な詳細は、主に以下の3つの側面から分析できます。
-
rt1.c
の分割: 元のrt1.c
ファイルは、シグナル処理とスレッド処理の両方のロジックを含んでいました。このコミットでは、これらの機能が明確に分離され、signal.c
とthread.c
という新しいファイルにそれぞれ移動されました。signal.c
: シグナルハンドラの登録、シグナル情報の取得、スタックトレースの出力など、シグナル関連の低レベルな処理が含まれるようになりました。DarwinとLinuxでそれぞれ異なる実装が提供されています。thread.c
: スレッドの作成、管理、同期プリミティブ(セマフォなど)の初期化といった、スレッド関連の処理が含まれるようになりました。
-
ディレクトリ構造の変更: 元の
rt1.c
は、src/runtime/darwin/amd64/rt1.c
やsrc/runtime/linux/amd64/rt1.c
のように、OSとアーキテクチャの両方に特化したディレクトリに配置されていました。この変更により、signal.c
とthread.c
はsrc/runtime/darwin/
やsrc/runtime/linux/
といったOS固有のディレクトリに移動されました。 これは、シグナルハンドリングやスレッド管理の多くの側面が、CPUアーキテクチャよりもOSのシステムコールインターフェースに強く依存するという認識に基づいています。例えば、sigaction
やsigaltstack
のようなシステムコールはOSによって提供され、そのAPIはOS間で大きく異なりますが、同じOS内であれば異なるアーキテクチャでも共通のインターフェースを持つことが多いです。この変更により、コードの再利用性が向上し、OSごとの差異をより効率的に管理できるようになります。 -
sys_types.h
の削除:src/runtime/sys_types.h
は、条件付きコンパイル(#ifdef amd64_linux
など)を使用して、特定のOS/アーキテクチャ固有のヘッダーファイル(amd64_linux.h
やamd64_darwin.h
)をインクルードしていました。このコミットでsys_types.h
が削除されたのは、おそらく、新しいsignal.c
やthread.c
が直接必要なヘッダーをインクルードするようになり、この抽象化レイヤーが不要になったためと考えられます。これは、依存関係をより明示的にし、不要な間接参照を排除するクリーンアップの一環です。
これらの変更は、Goランタイムの内部構造をより整理し、将来の拡張や異なるプラットフォームへの移植を容易にするための基盤を強化するものです。特に、シグナルとスレッドという並行処理の根幹をなす部分の分離は、Goの並行処理モデル(goroutineとチャネル)を支えるランタイムの安定性と効率性を高める上で不可欠なステップでした。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、以下のファイルに集中しています。
-
src/runtime/Makefile
:rt1.$O
のビルド対象からの削除。signal.$O
とthread.$O
のビルド対象への追加。 これにより、ビルドシステムが新しいファイル構成を認識し、正しくコンパイル・リンクされるようになります。
-
src/runtime/darwin/signal.c
(新規追加):- Darwin(macOS)環境におけるシグナルハンドリングのロジックが実装されています。
_STRUCT_X86_THREAD_STATE64
などのDarwin固有の構造体定義が含まれます。print_thread_state
関数(デバッグ目的でスレッドの状態レジスタを出力)が定義されています。sighandler
関数(実際のシグナル処理ロジック、スタックトレース出力など)が定義されています。initsig
関数(シグナルハンドラの初期設定)が定義されています。signalstack
関数(代替シグナルスタックの設定)が定義されています。
-
src/runtime/darwin/{amd64/rt1.c => thread.c}
(リネームと内容変更):- 元の
rt1.c
からシグナル関連のコードが削除され、スレッド関連のコードのみが残されました。 - ファイル名が
thread.c
に変更され、OS固有のディレクトリに移動されました。 initsema
(セマフォの初期化)やxadd
(アトミック加算)といった、スレッド同期に関連するヘルパー関数が含まれています。
- 元の
-
src/runtime/linux/signal.c
(新規追加):- Linux環境におけるシグナルハンドリングのロジックが実装されています。
_fpstate
,sigcontext
,ucontext
などのLinux固有の構造体定義が含まれます。print_sigcontext
関数(デバッグ目的でシグナルコンテキストを出力)が定義されています。sighandler
関数(実際のシグナル処理ロジック、スタックトレース出力など)が定義されています。initsig
関数(シグナルハンドラの初期設定)が定義されています。signalstack
関数(代替シグナルスタックの設定)が定義されています。
-
src/runtime/linux/{amd64/rt1.c => thread.c}
(リネームと内容変更):- 元の
rt1.c
からシグナル関連のコードが削除され、スレッド関連のコードのみが残されました。 - ファイル名が
thread.c
に変更され、OS固有のディレクトリに移動されました。 - Linuxのfutex(Fast Userspace muTEX)に関するコメントが残っており、スレッド同期の低レベルな実装に関連する部分であることが示唆されます。
- 元の
-
src/runtime/sys_types.h
(削除):- このヘッダーファイルは完全に削除されました。これにより、各OS/アーキテクチャ固有のヘッダーは、それらを必要とするファイルによって直接インクルードされるようになりました。
これらの変更により、Goランタイムのシグナルとスレッドに関するコードが、OSごとに整理され、よりモジュール化された構造になりました。
コアとなるコードの解説
このコミットの核心は、GoランタイムがOSからのシグナルをどのように処理し、また内部的なスレッドをどのように管理するかという、低レベルなメカニズムの再編成にあります。
シグナルハンドリング (signal.c
):
Goランタイムは、プログラムのクラッシュ(例: セグメンテーション違反)や外部からの割り込み(例: Ctrl+C)といったシグナルを捕捉し、適切に処理する必要があります。signal.c
ファイルは、このシグナル処理のOS固有の実装を含んでいます。
sighandler
関数: これは、OSがシグナルをプロセスに送信したときに呼び出されるGoランタイムの主要なシグナルハンドラです。panicking
フラグをチェックし、既にパニック状態であれば二重パニックを防ぎます。- シグナル番号と、シグナルが発生したアドレス(
info->si_addr
)やプログラムカウンタ(ss->__rip
またはsc->rip
)などの情報を出力します。 gotraceback()
が真の場合、traceback
関数を呼び出して現在のgoroutineのスタックトレースを出力します。これはデバッグ時に非常に役立ちます。- 最終的に
sys_Exit(2)
を呼び出してプロセスを終了させます。これは、Goランタイムが捕捉した致命的なシグナルに対するデフォルトの挙動です。
initsig
関数: Goプログラムの起動時に、Goランタイムが捕捉すべきシグナルに対してカスタムのシグナルハンドラ(sighandler
またはsigignore
)を登録します。sigaction
システムコール(またはrt_sigaction
)を使用して、シグナルハンドラ関数、シグナルマスク、およびフラグ(SA_SIGINFO
,SA_ONSTACK
,SA_RESTART
など)を設定します。SA_ONSTACK
フラグは、シグナルハンドラが通常のスタックではなく、代替シグナルスタック(signalstack
で設定)で実行されることを保証し、スタックオーバーフローによるシグナル処理の失敗を防ぎます。sigtramp
はアセンブリルーチンで、シグナルハンドラを呼び出す前にレジスタの状態を保存し、スタックを適切に設定する役割を担います。
スレッド管理 (thread.c
):
Goランタイムは、goroutineをOSスレッド上で実行するために、OSスレッドの作成、管理、および同期を行う必要があります。thread.c
ファイルは、これらのスレッド関連の低レベルな処理を含んでいます。
initsema
関数 (Darwin): Machカーネルのセマフォ(mach_semcreate
)を初期化します。これは、Goランタイムが内部的な同期プリミティブとして使用するものです。cas
(Compare-And-Swap) 操作を使用して、複数のスレッドが同時にセマフォを初期化しようとした場合の競合状態を防ぎます。xadd
関数 (Darwin): アトミックな加算操作を実装しています。これは、複数のスレッドから共有変数に安全にアクセスするために使用されます。- Linux版の
thread.c
には、futex(Fast Userspace muTEX)に関するコメントがあり、Linuxにおける低レベルなスレッド同期メカニズムへの言及が見られます。
Makefile
の変更:
Makefile
の変更は、これらの新しいファイルがGoランタイムのビルドプロセスに正しく組み込まれることを保証します。rt1.$O
が削除され、signal.$O
とthread.$O
が追加されることで、ビルドシステムは分割された新しいモジュールをコンパイルし、最終的なランタイムバイナリにリンクするようになります。
このコミットは、Goランタイムの初期設計において、シグナルとスレッドというOSに密接に関連する機能を、よりクリーンで保守性の高い方法で分離し、Goの並行処理モデルの基盤を強化した重要な一歩と言えます。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goランタイムのソースコード(現在のバージョン): https://github.com/golang/go/tree/master/src/runtime
- Goのシグナルハンドリングに関する議論(GoのIssueトラッカーなど): Goの初期のシグナルハンドリングに関する具体的なIssueは特定が難しいですが、
go.dev/issue
でsignal
やruntime
を検索すると関連する議論が見つかる可能性があります。
参考にした情報源リンク
- Go言語のソースコード(GitHub): https://github.com/golang/go
- Go言語のコミット履歴: https://github.com/golang/go/commits/master
- オペレーティングシステムのシグナルに関する一般的な情報(例: Linux man pages for
signal(7)
,sigaction(2)
,ucontext(3)
など) - Machカーネルのセマフォに関する情報(Darwin固有のシステムプログラミングドキュメントなど)
- futexに関する情報(Linuxカーネルのドキュメントなど)
- Go言語の初期開発に関するブログ記事やメーリングリストのアーカイブ(Goがオープンソース化される前の情報を見つけるのは難しい場合がありますが、GoのブログやGoogle Groupsのgolang-nutsアーカイブなどが参考になる可能性があります)。
- Web検索結果: "Go runtime early development signal handling threading rt1.c"