[インデックス 19666] ファイルの概要
このコミットは、Go言語のランタイムの一部である src/pkg/runtime/cgo/gcc_linux_arm.c
ファイルに対する変更です。このファイルは、GoプログラムがC言語のコードを呼び出すためのメカニズムであるCGO(C-Go interoperability)に関連しており、特にLinux ARMアーキテクチャにおけるCGOの動作を定義しています。具体的には、CGOが新しいスレッドを作成する際のシステムコールやエラーハンドリングに関するロジックが含まれています。
コミット
- コミットハッシュ:
b2c75ae2be56f23fc6518f6d24a3fb95496f1e5f
- 作者: David Crawshaw david.crawshaw@zentus.com
- コミット日時: 2014年7月3日 木曜日 16:52:34 -0400
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b2c75ae2be56f23fc6518f6d24a3fb95496f1e5f
元コミット内容
runtime/cgo: revert use of undefined logging function
It snuck into cl/106380043. Too many active clients.
LGTM=ruiu
R=golang-codereviews, ruiu
CC=golang-codereviews
https://golang.org/cl/110830045
変更の背景
このコミットの背景には、GoランタイムのCGO部分で「未定義のロギング関数」である fatalf
が誤って使用されてしまった問題があります。コミットメッセージによると、この問題は以前のチェンジリスト cl/106380043
で紛れ込んでしまったようです。
fatalf
という関数は、Goの標準ライブラリ log
パッケージの log.Fatalf
とは異なり、Goランタイムの内部で使われる低レベルなエラー報告関数であると推測されます。しかし、この特定のコンテキスト(gcc_linux_arm.c
)では、その関数が適切に定義されていないか、あるいはリンク時に解決できない状態であったため、ビルドエラーや実行時エラーを引き起こす可能性がありました。
「Too many active clients.」という記述は、この問題が多くのユーザーや環境で影響を及ぼしていることを示唆しており、早急な修正が必要であったことを意味します。そのため、このコミットでは、問題のある fatalf
の使用を元に戻し、より標準的で確実に動作するC言語の関数 (fprintf
と abort
) に置き換えることで、安定性を確保しています。
前提知識の解説
-
CGO (C-Go interoperability): Go言語のプログラムからC言語の関数を呼び出したり、C言語のコードからGoの関数を呼び出したりするためのメカニズムです。これにより、既存のCライブラリをGoプロジェクトで利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。CGOは、GoのランタイムとCのランタイムの間で橋渡しをする役割を担っており、メモリ管理やスレッドの扱いなど、低レベルな部分で連携します。
-
pthread_create
: POSIXスレッドライブラリ(Pthreads)の一部であり、新しいスレッドを作成するために使用されるC言語の標準関数です。Goランタイムは、CGOを介してCコードがスレッドを作成する必要がある場合に、この関数を内部的に利用することがあります。 -
strerror(int errnum)
: C言語の標準ライブラリ関数で、エラー番号errnum
に対応するエラーメッセージ文字列へのポインタを返します。pthread_create
などのシステムコールが失敗した場合に返されるエラーコードを、人間が読める形式のメッセージに変換するために使用されます。 -
fprintf(FILE *stream, const char *format, ...)
: C言語の標準ライブラリ関数で、指定されたファイルストリーム(FILE *stream
)にフォーマットされた出力を書き込みます。このコミットでは、標準エラー出力ストリームを指すstderr
にエラーメッセージを書き出すために使用されています。 -
stderr
: C言語において、標準エラー出力ストリームを指すグローバルなファイルポインタです。通常、プログラムのエラーメッセージや診断情報を出力するために使用されます。 -
abort()
: C言語の標準ライブラリ関数で、現在のプログラムを異常終了させます。通常、回復不可能なエラーが発生した場合に呼び出され、プログラムの実行を即座に停止させます。abort()
が呼び出されると、通常はコアダンプが生成され、デバッグに役立つ情報が提供されます。 -
fatalf
(Goランタイム内部関数): このコミットで言及されているfatalf
は、Goの標準ライブラリlog
パッケージにあるlog.Fatalf
とは異なります。これはGoランタイムの非常に低レベルな部分で使用される、内部的なエラー報告関数であると推測されます。ランタイムの致命的なエラー(例: メモリ不足、内部的な不整合)が発生した場合に、プログラムを終了させるために使われることがあります。このコミットの文脈では、この関数が特定のビルド環境やコンテキストで「未定義」であったため、問題を引き起こしました。
技術的詳細
このコミットは、src/pkg/runtime/cgo/gcc_linux_arm.c
ファイル内の _cgo_sys_thread_start
関数におけるエラーハンドリングロジックの修正に焦点を当てています。この関数は、CGOが新しいシステムスレッドを起動する際に呼び出されるもので、内部で pthread_create
を使用しています。
元のコードでは、pthread_create
の呼び出しが失敗した場合(err != 0
)、fatalf
という関数を呼び出してエラーメッセージを出力し、プログラムを終了させていました。しかし、この fatalf
関数が、この特定のコンパイル環境やリンク設定において「未定義」であったため、問題が発生しました。これは、fatalf
がGoランタイムの非常に内部的な関数であり、すべてのCGOコンテキストで利用可能であるとは限らない、あるいは特定のプラットフォームやビルド構成で利用できない、または廃止された関数であった可能性を示唆しています。
この「未定義」の問題を解決するため、コミットでは fatalf
の呼び出しを、標準的なC言語の関数である fprintf
と abort()
に置き換えています。
-
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\\n", strerror(err));
: これにより、pthread_create
の失敗に関するエラーメッセージが標準エラー出力 (stderr
) に書き込まれます。メッセージには、runtime/cgo
というプレフィックスが付加され、strerror(err)
によってシステムエラーコードが人間が読める形式の文字列に変換されて表示されます。これは、エラーの原因を特定するための重要な情報を提供します。 -
abort();
: エラーメッセージの出力後、abort()
が呼び出され、プログラムが即座に異常終了します。これは、pthread_create
の失敗が回復不可能な致命的なエラーであると判断されたためです。abort()
は通常、コアダンプを生成し、デバッグ時に役立つメモリの状態を記録します。
この変更により、fatalf
のような内部的で定義が不安定な関数に依存することなく、標準的なCライブラリの機能を使って確実にエラーを報告し、プログラムを終了させることが可能になります。これにより、Goランタイムの安定性と移植性が向上します。
コアとなるコードの変更箇所
--- a/src/pkg/runtime/cgo/gcc_linux_arm.c
+++ b/src/pkg/runtime/cgo/gcc_linux_arm.c
@@ -36,7 +36,8 @@ _cgo_sys_thread_start(ThreadStart *ts)
pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
-\t\tfatalf("pthread_create failed: %s", strerror(err));
+\t\tfprintf(stderr, "runtime/cgo: pthread_create failed: %s\\n", strerror(err));
+\t\tabort();
}
}
コアとなるコードの解説
変更は _cgo_sys_thread_start
関数内の if (err != 0)
ブロックにあります。このブロックは、pthread_create
関数がスレッドの作成に失敗した場合に実行されます。
-
- fatalf("pthread_create failed: %s", strerror(err));
: 変更前のコードでは、fatalf
という関数が呼び出されていました。この関数は、pthread_create
の失敗を示すメッセージと、strerror(err)
によって取得されたエラーの詳細を出力し、プログラムを終了させることを意図していました。しかし、前述の通り、このfatalf
がこのコンテキストで「未定義」であったことが問題でした。 -
+ fprintf(stderr, "runtime/cgo: pthread_create failed: %s\\n", strerror(err));
: この行は、エラーメッセージを標準エラー出力 (stderr
) に書き込むように変更されました。メッセージのフォーマットは以前と似ていますが、runtime/cgo:
というプレフィックスが追加され、より明確な情報源を示すようになりました。fprintf
はC言語の標準関数であり、確実に利用できます。 -
+ abort();
: この行は新しく追加されました。fprintf
でエラーメッセージを出力した後、abort()
を呼び出すことで、プログラムを即座に異常終了させます。これにより、fatalf
が提供していたであろう「致命的なエラーによるプログラム終了」という動作が、標準的なC言語のメカニズムによって再現されます。
この変更により、GoランタイムのCGO部分におけるスレッド作成時のエラーハンドリングが、より堅牢で移植性の高いものになりました。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/b2c75ae2be56f23fc6518f6d24a3fb95496f1e5f
- Go Gerrit チェンジリスト: https://golang.org/cl/110830045
参考にした情報源リンク
- Go言語の
log.Fatalf
とpanic
の違いに関する情報: https://zerotohero.dev/go-log-fatalf-vs-panic/ (Goの標準ライブラリのlog.Fatalf
についての一般的な情報であり、本コミットのfatalf
とは直接関係ないが、Goにおける致命的エラー処理の文脈理解に役立つ) - C言語の
pthread_create
関数に関するドキュメント (例: manページ) - C言語の
fprintf
,strerror
,abort
関数に関するドキュメント (例: manページ) - Go言語のCGOに関する公式ドキュメント (Goのウェブサイトなど)
- Goランタイムのソースコード (特に
src/runtime
ディレクトリ)