[インデックス 13052] ファイルの概要
このコミットは、Go言語のランタイムにおけるNetBSDシステムコールsigaction
構造体の定義に関する修正です。具体的には、sigaction
構造体内の共用体メンバー名と、シグナルマスクsa_mask
の型定義がNetBSDの実際の定義と一致するように変更されています。これにより、NetBSD上でのGoプログラムのシグナルハンドリングが正しく機能するようになります。
コミット
commit 38445ca08915c0fb755f9f15f99a3226ed7f45f4
Author: Joel Sing <jsing@google.com>
Date: Fri May 11 03:48:16 2012 +1000
runtime: fix netbsd sigaction struct
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6198063
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/38445ca08915c0fb755f9f15f99a3226ed7f45f4
元コミット内容
runtime: fix netbsd sigaction struct
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6198063
変更の背景
Go言語のランタイムは、様々なオペレーティングシステム(OS)上で動作するように設計されています。OSごとにシステムコールやデータ構造の定義が異なるため、Goランタイムは各OSの特性に合わせて調整される必要があります。
このコミットの背景には、NetBSDにおけるsigaction
システムコールの構造体定義が、Goランタイム内で誤って実装されていたという問題があります。sigaction
は、プロセスがシグナル(例えば、Ctrl+Cによる割り込みや、不正なメモリアクセスなど)を受け取った際の挙動を定義するために使用される重要なシステムコールです。Goランタイムは、ガーベージコレクションやスケジューリング、デバッグなどの内部処理のためにシグナルハンドリングを多用します。
NetBSDのsigaction
構造体は、シグナルハンドラを指す共用体メンバーの名前(__sigaction_u
ではなく_sa_u
)と、シグナルマスクsa_mask
の型(単一のuint32
ではなくuint32
の配列)が、Goランタイム内の定義と異なっていました。この不一致が原因で、NetBSD上でGoプログラムがシグナルを正しく処理できず、予期せぬクラッシュや誤動作を引き起こす可能性がありました。このコミットは、このNetBSD固有の構造体の不一致を修正し、GoランタイムがNetBSD上で安定して動作するようにすることを目的としています。
前提知識の解説
シグナルとシグナルハンドリング
- シグナル: オペレーティングシステムがプロセスに送信する非同期の通知です。プログラムの異常終了(例: セグメンテーション違反)、外部からの割り込み(例: Ctrl+C)、タイマーの満了など、様々なイベントをプロセスに伝えます。
- シグナルハンドリング: プロセスがシグナルを受け取った際に、どのように応答するかを定義するメカニズムです。デフォルトの動作(プロセス終了など)を変更し、特定の関数(シグナルハンドラ)を実行させることができます。
sigaction
システムコール
sigaction
はPOSIX標準で定義されているシステムコールで、特定のシグナルに対するアクション(挙動)を検査または変更するために使用されます。signal
システムコールよりも柔軟で、シグナルハンドラの登録、シグナルマスクの設定、シグナルハンドラ実行中の動作(例: シグナルハンドラ実行中にブロックするシグナル)などを細かく制御できます。
sigaction
システムコールは、以下のような構造体(struct sigaction
)を引数として取ります。
struct sigaction {
union {
void (*sa_handler)(int); /* シグナルハンドラ関数 */
void (*sa_sigaction)(int, siginfo_t *, void *); /* 拡張シグナルハンドラ関数 */
} sa_sigaction_u; // または他の名前
sigset_t sa_mask; /* シグナルハンドラ実行中にブロックするシグナルマスク */
int sa_flags; /* シグナルの動作を制御するフラグ */
};
sa_sigaction_u
(または類似の共用体): シグナルハンドラ関数を指すポインタを格納します。sa_handler
はシンプルなハンドラ、sa_sigaction
はより詳細な情報(siginfo_t
)を受け取るハンドラです。sa_mask
: シグナルハンドラが実行されている間、追加でブロックされるシグナルのセットを指定します。これにより、シグナルハンドラが再入可能でない場合に、同じシグナルが再度発生して問題を引き起こすのを防ぎます。sa_flags
: シグナルの動作を制御する様々なフラグ(例:SA_SIGINFO
でsa_sigaction
を使用、SA_RESTART
でシステムコールを再開など)を設定します。
sigset_t
とシグナルマスク
sigset_t
は、シグナルの集合を表すデータ型です。通常、ビットマスクとして実装され、各ビットが特定のシグナルに対応します。sa_mask
はこのsigset_t
型であり、シグナルハンドラが実行されている間にブロックされるシグナルを指定します。
GoランタイムとOS固有のコード
Go言語のランタイムは、OSのカーネルと直接やり取りする低レベルな部分を含んでいます。これには、メモリ管理、ゴルーチン(軽量スレッド)のスケジューリング、ネットワークI/O、そしてシグナルハンドリングなどが含まれます。これらの機能はOSのシステムコールに依存するため、Goのソースコードにはruntime/signal_netbsd_386.c
やruntime/signal_netbsd_amd64.c
のように、特定のOSやアーキテクチャに特化したファイルが存在します。これらのファイルは、GoランタイムがそのOS上で正しく動作するために必要な、OS固有のシステムコールラッパーやデータ構造の定義を含んでいます。
技術的詳細
このコミットは、NetBSDのsigaction
構造体のGoランタイム内でのC言語定義を、NetBSDカーネルの実際の定義と一致させることに焦点を当てています。
具体的には、以下の2つの主要な変更が行われています。
-
共用体メンバー名の変更:
- 変更前:
__sigaction_u
- 変更後:
_sa_u
NetBSDのsigaction
構造体では、シグナルハンドラを格納する共用体の名前が_sa_u
となっています。GoランタイムのCコードがこの名前と一致しない場合、コンパイルエラーや、より深刻な場合は実行時の未定義動作(メモリレイアウトの不一致による誤った値の読み書き)が発生する可能性があります。
- 変更前:
-
sa_mask
の型変更:- 変更前:
uint32 sa_mask;
(またはuint64
for amd64) - 変更後:
uint32 sa_mask[4];
NetBSDでは、sigset_t
型が単一のuint32
(またはuint64
)ではなく、uint32
の配列(通常は4要素)として定義されています。これは、より多くのシグナルをサポートするために、シグナルマスクが複数のワードにまたがることを意味します。Goランタイムがこれを単一のuint32
として扱っていた場合、シグナルマスクのビットが正しく設定されず、特定のシグナルがブロックされない、あるいは意図しないシグナルがブロックされるといった問題が発生します。
- 変更前:
これらの変更は、GoランタイムがNetBSDのシグナルハンドリングメカニズムと正しくインターフェースするためのものです。特に、sa_mask
が配列になったことで、シグナルマスクを設定する際に各配列要素に~0U
(全ビットを1にする)を代入する必要があります。これは、すべてのシグナルをブロックするという一般的な操作に対応します。
この修正により、GoプログラムはNetBSD上でシグナルを期待通りに処理できるようになり、より堅牢で安定した動作が保証されます。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
src/pkg/runtime/signal_netbsd_386.c
(32ビットNetBSDアーキテクチャ用)src/pkg/runtime/signal_netbsd_amd64.c
(64ビットNetBSDアーキテクチャ用)
両ファイルで同様の変更が行われています。
src/pkg/runtime/signal_netbsd_386.c
の変更点
--- a/src/pkg/runtime/signal_netbsd_386.c
+++ b/src/pkg/runtime/signal_netbsd_386.c
@@ -11,10 +11,10 @@ extern void runtime·sigtramp(void);\
typedef struct sigaction {
union {
- void (*__sa_handler)(int32);\
- void (*__sa_sigaction)(int32, Siginfo*, void *);\
- } __sigaction_u;\t\t/* signal handler */\
- uint32 sa_mask;\t\t/* signal mask to apply */
+ void (*_sa_handler)(int32);\
+ void (*_sa_sigaction)(int32, Siginfo*, void *);\
+ } _sa_u;\t\t\t/* signal handler */
+ uint32 sa_mask[4];\t\t/* signal mask to apply */
int32 sa_flags;\t\t/* see signal options below */
} Sigaction;\
@@ -124,9 +124,12 @@ runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)\
sa.sa_flags = SA_SIGINFO|SA_ONSTACK;\
if(restart)\
sa.sa_flags |= SA_RESTART;\
- sa.sa_mask = ~0ULL;\
+ sa.sa_mask[0] = ~0U;\
+ sa.sa_mask[1] = ~0U;\
+ sa.sa_mask[2] = ~0U;\
+ sa.sa_mask[3] = ~0U;\
if (fn == runtime·sighandler)\
fn = (void*)runtime·sigtramp;\
- sa.__sigaction_u.__sa_sigaction = (void*)fn;\
+ sa._sa_u._sa_sigaction = (void*)fn;\
runtime·sigaction(i, &sa, nil);\
}
src/pkg/runtime/signal_netbsd_amd64.c
の変更点
--- a/src/pkg/runtime/signal_netbsd_amd64.c
+++ b/src/pkg/runtime/signal_netbsd_amd64.c
@@ -11,10 +11,10 @@ extern void runtime·sigtramp(void);\
typedef struct sigaction {\
union {\
- void (*__sa_handler)(int32);\
- void (*__sa_sigaction)(int32, Siginfo*, void *);\
- } __sigaction_u;\t\t/* signal handler */\
- uint32 sa_mask;\t\t/* signal mask to apply */
+ void (*_sa_handler)(int32);\
+ void (*_sa_sigaction)(int32, Siginfo*, void *);\
+ } _sa_u;\t\t\t/* signal handler */
+ uint32 sa_mask[4];\t\t/* signal mask to apply */
int32 sa_flags;\t\t/* see signal options below */
} Sigaction;\
@@ -133,9 +133,12 @@ runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)\
sa.sa_flags = SA_SIGINFO|SA_ONSTACK;\
if(restart)\
sa.sa_flags |= SA_RESTART;\
- sa.sa_mask = ~0ULL;\
+ sa.sa_mask[0] = ~0U;\
+ sa.sa_mask[1] = ~0U;\
+ sa.sa_mask[2] = ~0U;\
+ sa.sa_mask[3] = ~0U;\
if (fn == runtime·sighandler)\
fn = (void*)runtime·sigtramp;\
- sa.__sigaction_u.__sa_sigaction = (void*)fn;\
+ sa._sa_u._sa_sigaction = (void*)fn;\
runtime·sigaction(i, &sa, nil);\
}
コアとなるコードの解説
Sigaction
構造体の定義変更
両ファイルにおいて、Sigaction
構造体の定義が変更されています。
-
共用体メンバー名の変更:
__sigaction_u
から_sa_u
へ変更。- これにより、NetBSDのシステムヘッダファイルで定義されている実際の
sigaction
構造体の共用体メンバー名と一致させます。GoランタイムのCコードがOSのAPIと正しく連携するために不可欠な変更です。
-
sa_mask
の型変更:uint32 sa_mask;
(32ビット版) またはuint64 sa_mask;
(64ビット版) からuint32 sa_mask[4];
へ変更。- NetBSDでは、シグナルマスク
sigset_t
がuint32
の配列として定義されているため、Goランタイムもそれに合わせて配列として扱う必要があります。これにより、より多くのシグナルを正確に表現できるようになります。
runtime·setsig
関数内の sa_mask
設定変更
runtime·setsig
関数は、特定のシグナルに対するハンドラを設定するGoランタイム内部の関数です。この関数内で、Sigaction
構造体のsa_mask
フィールドを設定する部分が変更されています。
-
変更前:
sa.sa_mask = ~0ULL;
(64ビット版では~0ULL
、32ビット版では~0U
または類似)- これは、単一の
uint32
またはuint64
変数に対して全ビットを1に設定し、すべてのシグナルをブロックしようとしていました。
- これは、単一の
-
変更後:
sa.sa_mask[0] = ~0U; sa.sa_mask[1] = ~0U; sa.sa_mask[2] = ~0U; sa.sa_mask[3] = ~0U;
sa_mask
がuint32
の配列になったため、配列の各要素に対して~0U
(符号なし32ビット整数の全ビットを1にする)を代入しています。これにより、シグナルマスクのすべてのビットがセットされ、シグナルハンドラが実行されている間、すべてのシグナルがブロックされるようになります。これは、シグナルハンドラの実行中に他のシグナルによる割り込みを防ぎ、ハンドラの処理を安全に行うための一般的なプラクティスです。
runtime·setsig
関数内のシグナルハンドラ設定変更
- 変更前:
sa.__sigaction_u.__sa_sigaction = (void*)fn;
- 変更後:
sa._sa_u._sa_sigaction = (void*)fn;
Sigaction
構造体内の共用体メンバー名が__sigaction_u
から_sa_u
に変更されたことに伴い、シグナルハンドラ関数ポインタfn
を代入する際のパスも変更されています。これにより、正しいメモリ位置にハンドラが設定されるようになります。
これらの変更は、NetBSDのシステムコールインターフェースとの互換性を確保し、GoランタイムがNetBSD上でシグナルを正しく処理できるようにするために不可欠です。
関連リンク
- Go言語の公式ドキュメント: https://golang.org/
- Go言語のソースコードリポジトリ(GitHub): https://github.com/golang/go
- NetBSDプロジェクトの公式ウェブサイト: https://www.netbsd.org/
- POSIX
sigaction
に関するmanページ(一般的な情報):man 2 sigaction
(Linux/Unixシステムで実行)
参考にした情報源リンク
- Go CL 6198063: https://golang.org/cl/6198063 (コミットメッセージに記載されているGoのコードレビューシステムへのリンク)
- NetBSDの
sigaction
構造体に関する情報(NetBSDのソースコードやドキュメントを参照)- 例: NetBSDの
sys/signal.h
ヘッダファイル内のstruct sigaction
定義 - NetBSDのmanページ:
man 2 sigaction
(NetBSDシステムで実行)
- 例: NetBSDの
- 一般的なシグナルハンドリングに関する情報源(例: UNIXプログラミングに関する書籍やオンラインリソース)