[インデックス 15292] ファイルの概要
このコミットは、Go言語のランタイムにおけるFreeBSD環境でのシグナルハンドリングに関するバグ修正を扱っています。具体的には、sigaction
構造体内のsa_mask
メンバーの定義がFreeBSDのシステムコールと一致していなかった問題を解決し、FreeBSD上でのGoのビルドが正常に行われるようにします。
コミット
commit 556dd0bfbd52876933ef0454ca86f492c618f342
Author: Joel Sing <jsing@google.com>
Date: Mon Feb 18 03:23:29 2013 +1100
runtime: fix sigaction struct on freebsd
Fix the sa_mask member of the sigaction struct - on FreeBSD this is
declared as a sigset_t, which is an array of four unsigned ints.
Replace the current int64 with Sigset from defs_freebsd_GOARCH, which
has the correct definition.
Unbreaks the FreeBSD builds.
R=golang-dev, dave, minux.ma
CC=golang-dev
https://golang.org/cl/7333047
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/556dd0bfbd52876933ef0454ca86f492c618f342
元コミット内容
Goランタイムにおいて、FreeBSD環境でのsigaction
構造体のsa_mask
メンバーの定義が誤っていたため、FreeBSDでのビルドが失敗していました。このコミットは、sa_mask
の型をint64
から、FreeBSDのsigset_t
に対応するSigset
型(4つのunsigned int
の配列)に修正することで、この問題を解決し、FreeBSDでのビルドを正常化します。
変更の背景
Go言語は、様々なオペレーティングシステム(OS)やアーキテクチャをサポートするように設計されています。そのため、各OS固有のシステムコールやデータ構造とのインターフェースを正確に定義する必要があります。このコミットが行われた当時、GoのランタイムがFreeBSD上でシグナルを処理する際に使用するsigaction
構造体の定義が、FreeBSDの実際の定義と異なっていました。
具体的には、sigaction
構造体内のsa_mask
フィールドが、Goのランタイムコードではint64
として定義されていましたが、FreeBSDのシステムヘッダではsigset_t
として定義されていました。sigset_t
は通常、複数のシグナルをビットマスクとして表現するために使用されるデータ型であり、FreeBSDでは4つのunsigned int
の配列として実装されていました。この型不一致が原因で、GoのランタイムがFreeBSDのシグナル処理APIを呼び出す際に、不正なメモリアクセスや予期せぬ動作を引き起こし、結果としてFreeBSD上でのGoのビルドが失敗する、あるいは実行時に問題が発生する可能性がありました。
このコミットは、このようなOS固有のインターフェースの不一致を解消し、GoがFreeBSD環境で安定して動作するための重要な修正です。
前提知識の解説
シグナル (Signal)
シグナルは、Unix系OSにおいてプロセス間通信やイベント通知のために使用されるソフトウェア割り込みの一種です。例えば、Ctrl+Cを押すとSIGINT
シグナルがプロセスに送られ、プロセスは通常終了します。プログラムはシグナルを受信した際に、デフォルトの動作を実行するか、カスタムのシグナルハンドラ関数を呼び出すかを設定できます。
sigaction
構造体
sigaction
構造体は、シグナルハンドリングの動作を定義するために使用されるデータ構造です。sigaction
システムコールを通じて、特定のシグナルに対するハンドラ関数、シグナルハンドラ実行中のシグナルマスク、およびその他のフラグを設定します。主要なメンバーは以下の通りです。
sa_handler
またはsa_sigaction
: シグナルを受信した際に呼び出されるハンドラ関数へのポインタ。sa_mask
: シグナルハンドラが実行されている間にブロックされる(一時的に無視される)シグナルのセットを指定するシグナルマスク。sa_flags
: シグナルハンドリングの動作を制御するフラグ(例:SA_SIGINFO
で追加情報を受け取る、SA_RESTART
でシステムコールを再開するなど)。
sigset_t
sigset_t
は、シグナルのセット(集合)を表すデータ型です。通常、ビットマスクとして実装され、各ビットが特定のシグナルに対応します。sa_mask
メンバーはこのsigset_t
型であり、シグナルハンドラ実行中にブロックしたいシグナルを指定するために使用されます。OSやアーキテクチャによってその具体的なサイズや内部構造は異なりますが、複数のシグナルを効率的に管理するためのものです。FreeBSDでは、これが4つのunsigned int
の配列として定義されていました。
~0ULL
と ~(uint32)0
これらはビット演算子と型キャストを組み合わせた表現です。
~
(ビット反転): オペランドのすべてのビットを反転させます(0を1に、1を0に)。0ULL
:unsigned long long
型の0を意味します。すべてのビットが0の64ビット整数です。~0ULL
は、すべてのビットが1の64ビット整数(つまり、64ビットの最大値)を生成します。(uint32)0
:unsigned int
型の0を意味します。すべてのビットが0の32ビット整数です。~(uint32)0
は、すべてのビットが1の32ビット整数(つまり、32ビットの最大値)を生成します。
これらの値は、シグナルマスクを「すべてのシグナルをブロックする」状態に設定するためによく使用されます。
技術的詳細
このコミットの核心は、GoランタイムがFreeBSDのsigaction
システムコールと正しくインターフェースするための型定義の修正です。
Goのランタイムは、C言語で書かれた部分(src/pkg/runtime/
以下の.c
ファイル群)とGo言語で書かれた部分が混在しており、OS固有のシステムコールを呼び出す際には、C言語の構造体定義をGoのランタイムコード内で模倣する必要があります。
FreeBSDのsigaction
構造体は、sa_mask
メンバーをsigset_t
型として定義しています。FreeBSDのsigset_t
は、内部的には__bits[4]
という4つのunsigned int
の配列として実装されています。これは、32ビットシステムでは4 * 32 = 128ビット、64ビットシステムでも同様に128ビットのシグナルマスクを表現できることを意味します。
しかし、Goのランタイムコードでは、このsa_mask
が誤ってint64
(64ビット整数)として定義されていました。この不一致により、Goのランタイムがsigaction
システムコールを呼び出す際に、sa_mask
に設定しようとしたデータがFreeBSDカーネルによって正しく解釈されませんでした。具体的には、int64
として~0ULL
(すべてのビットが1の64ビット値)を設定しても、FreeBSDが期待する128ビットのsigset_t
の構造とは合致せず、シグナルマスクが意図通りに設定されない、あるいはメモリアライメントの問題を引き起こす可能性がありました。
この修正では、Goランタイム内のSigaction
構造体のsa_mask
メンバーの型をint64
からSigset
に変更しています。このSigset
型は、defs_freebsd_GOARCH
(FreeBSDの特定のアーキテクチャ向けの定義ファイル)で、FreeBSDのsigset_t
に対応するように、4つのuint32
の配列として定義されています。
さらに、シグナルマスクを初期化する部分も変更されています。以前はsa.sa_mask = ~0ULL;
としていましたが、これはint64
型にすべてのビットを1に設定するものでした。新しいSigset
型は配列であるため、各要素を個別に初期化する必要があります。したがって、sa.sa_mask.__bits[0] = ~(uint32)0;
からsa.sa_mask.__bits[3] = ~(uint32)0;
まで、4つのuint32
要素それぞれにすべてのビットを1に設定する値が代入されるようになりました。これにより、FreeBSDが期待する128ビットのシグナルマスクが正しく設定され、すべてのシグナルがブロックされる状態が実現されます。
この修正により、GoのランタイムがFreeBSDのシグナル処理APIと正しく連携できるようになり、FreeBSD上でのGoのビルドおよび実行時の安定性が向上しました。
コアとなるコードの変更箇所
このコミットは、以下の3つのファイルに同様の変更を加えています。これらはそれぞれFreeBSDの異なるアーキテクチャ(386, amd64, arm)に対応するシグナル処理のC言語ソースファイルです。
src/pkg/runtime/signal_freebsd_386.c
src/pkg/runtime/signal_freebsd_amd64.c
src/pkg/runtime/signal_freebsd_arm.c
各ファイルでの変更は以下の通りです(src/pkg/runtime/signal_freebsd_386.c
を例に示します)。
--- a/src/pkg/runtime/signal_freebsd_386.c
+++ b/src/pkg/runtime/signal_freebsd_386.c
@@ -15,7 +15,7 @@ typedef struct sigaction {
void (*__sa_sigaction)(int32, Siginfo*, void *);
} __sigaction_u; /* signal handler */
int32 sa_flags; /* see signal options below */
- int64 sa_mask; /* signal mask to apply */
+ Sigset sa_mask; /* signal mask to apply */
} Sigaction;
void
@@ -141,7 +141,10 @@ runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
sa.sa_flags = SA_SIGINFO|SA_ONSTACK;\n \tif(restart)\n \t\tsa.sa_flags |= SA_RESTART;\n-\tsa.sa_mask = ~0ULL;\n+\tsa.sa_mask.__bits[0] = ~(uint32)0;\n+\tsa.sa_mask.__bits[1] = ~(uint32)0;\n+\tsa.sa_mask.__bits[2] = ~(uint32)0;\n+\tsa.sa_mask.__bits[3] = ~(uint32)0;\n \tif (fn == runtime·sighandler)\n \tfn = (void*)runtime·sigtramp;\n \tsa.__sigaction_u.__sa_sigaction = (void*)fn;
コアとなるコードの解説
上記の差分から、以下の2つの主要な変更点が見て取れます。
-
Sigaction
構造体のsa_mask
メンバーの型変更:- int64 sa_mask; /* signal mask to apply */ + Sigset sa_mask; /* signal mask to apply */
これは、Goランタイムが内部的に使用する
Sigaction
構造体定義において、sa_mask
フィールドの型をint64
からSigset
に変更したものです。このSigset
型は、FreeBSDのsigset_t
の実際の構造(4つのunsigned int
の配列)を正確に反映するように、defs_freebsd_GOARCH
ファイルで定義されています。これにより、Goランタイムがsigaction
システムコールに渡すデータ構造が、FreeBSDカーネルが期待する形式と一致するようになります。 -
sa_mask
の初期化方法の変更:-\tsa.sa_mask = ~0ULL; +\tsa.sa_mask.__bits[0] = ~(uint32)0; +\tsa.sa_mask.__bits[1] = ~(uint32)0; +\tsa.sa_mask.__bits[2] = ~(uint32)0; +\tsa.sa_mask.__bits[3] = ~(uint32)0;
以前は、
sa_mask
がint64
型であったため、~0ULL
という64ビットの全ビットを1にする値で初期化していました。しかし、sa_mask
がSigset
型(内部的に__bits[4]
というuint32
の配列を持つ)に変更されたため、各uint32
要素を個別に初期化する必要があります。~(uint32)0
は、32ビットのunsigned int
の全ビットを1にする値です。これを__bits
配列の各要素に代入することで、合計128ビットのシグナルマスクがすべて1に設定されます。これは、シグナルハンドラが実行されている間、すべてのシグナルをブロックするという意図を正確にFreeBSDカーネルに伝えるための変更です。
これらの変更により、GoランタイムはFreeBSDのシグナル処理メカニズムと完全に互換性を持つようになり、FreeBSD上でのGoのビルドと実行に関する問題が解消されました。
関連リンク
- Go言語の公式リポジトリ: https://github.com/golang/go
- Go言語のコードレビューシステム (Gerrit): https://go.dev/cl/7333047 (コミットメッセージに記載されているCLリンク)
- FreeBSDの
sigaction
マニュアルページ (例): https://www.freebsd.org/cgi/man.cgi?query=sigaction&sektion=2
参考にした情報源リンク
- Go言語のソースコード (特に
src/pkg/runtime/
ディレクトリ内のOS固有のファイル) - FreeBSDのシステムヘッダファイル (特に
sys/signal.h
など、sigaction
やsigset_t
の定義が含まれるもの) - Unix/Linuxプログラミングに関する一般的なドキュメントや書籍(シグナル処理について)
- Go言語のIssueトラッカーやメーリングリスト(過去の議論や関連するバグ報告)
- https://go.dev/doc/ (Go言語公式ドキュメント)
- https://en.wikipedia.org/wiki/Signal_(IPC) (Wikipedia: シグナル)
- https://man7.org/linux/man-pages/man2/sigaction.2.html (Linux
sigaction
manページ - FreeBSDとは異なるが概念は共通) - https://www.freebsd.org/ (FreeBSD公式ウェブサイト)
- https://www.freebsd.org/cgi/man.cgi?query=sigsetops&sektion=3 (FreeBSD
sigsetops
manページ -sigset_t
の操作について) - https://www.freebsd.org/cgi/man.cgi?query=types&sektion=5 (FreeBSD
types
manページ - 基本データ型について)