Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 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言語の関数 (fprintfabort) に置き換えることで、安定性を確保しています。

前提知識の解説

  • 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言語の関数である fprintfabort() に置き換えています。

  1. fprintf(stderr, "runtime/cgo: pthread_create failed: %s\\n", strerror(err));: これにより、pthread_create の失敗に関するエラーメッセージが標準エラー出力 (stderr) に書き込まれます。メッセージには、runtime/cgo というプレフィックスが付加され、strerror(err) によってシステムエラーコードが人間が読める形式の文字列に変換されて表示されます。これは、エラーの原因を特定するための重要な情報を提供します。

  2. 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部分におけるスレッド作成時のエラーハンドリングが、より堅牢で移植性の高いものになりました。

関連リンク

参考にした情報源リンク

  • Go言語の log.Fatalfpanic の違いに関する情報: 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 ディレクトリ)