[インデックス 17715] ファイルの概要
このコミットは、Go言語のランタイムにおけるレース検出器(Race Detector)のビルドプロセスに関する修正です。具体的には、src/race.bash
と src/race.bat
という2つのスクリプトが変更されています。これらはそれぞれUnix系OSとWindowsにおけるレース検出器有効化ビルドのためのスクリプトです。
コミット
- コミットハッシュ:
cdb33231b2d988b71f03f622fc9c3d2edccc20e0
- Author: Dave Cheney dave@cheney.net
- Date: Sun Sep 29 10:34:41 2013 +1000
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cdb33231b2d988b71f03f622fc9c3d2edccc20e0
元コミット内容
race.bash, race.bat: build a race enabled cmd/cgo before trying to use it
Fixes #5537.
To avoid `go install -v race std` replacing cmd/cgo with a race enabled version and another package trying to build a cgo enabled package, always build cmd/cgo race enabled before doing the rest of the build.
R=remyoudompheng, rsc, dvyukov, minux.ma
CC=golang-dev
https://golang.org/cl/14071044
変更の背景
このコミットは、Go言語のレース検出器を使用する際のビルドプロセスにおける特定の問題を解決するために導入されました。具体的には、Goのビルドシステムがレース検出器を有効にした状態でstd
(標準ライブラリ)をビルドする際に、cmd/cgo
が正しくレース検出器対応版としてビルドされない、あるいは他のパッケージがcgo
を有効にしたパッケージをビルドしようとした際に問題が発生するというバグ(Issue #5537)に対応しています。
問題の根源は、go install -race std
コマンドが実行されると、cmd/cgo
がレース検出器を有効にしたバージョンで置き換えられる可能性があるにもかかわらず、その後に続くビルドプロセスでcgo
を必要とするパッケージが、まだレース検出器が有効になっていないcmd/cgo
に依存してしまうことにありました。これにより、ビルドエラーや予期せぬ動作が発生する可能性がありました。
このコミットの目的は、このような競合状態を回避し、レース検出器を有効にしたビルドが常に安定して行われるようにすることです。
前提知識の解説
Go Race Detector (レース検出器)
Go Race Detectorは、Goプログラムにおけるデータ競合(data race)を検出するための強力なツールです。データ競合とは、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつそれらのアクセスが同期メカニズムによって保護されていない場合に発生するバグです。データ競合は非決定的な動作を引き起こし、デバッグが非常に困難な種類のバグとして知られています。
Go Race Detectorは、プログラムの実行時にメモリアクセスを動的に計測し、競合状態を監視することで機能します。-race
フラグを付けてGoプログラムをビルドまたは実行する(例: go test -race
, go run -race
, go build -race
)と、Goコンパイラはすべてのメモリアクセスを計測します。ランタイムライブラリは、共有変数への並行かつ非同期なアクセスを監視し、競合が検出された場合には詳細なレポートを出力します。
動作原理: Go Race Detectorは、C/C++のThreadSanitizerランタイムライブラリをベースにしています。このため、その機能の一部はCGOに依存しています。
パフォーマンスへの影響: レース検出器を有効にすると、リソース消費が大幅に増加します。レース検出器が有効なバイナリは、メモリ使用量が5〜10倍、実行速度が2〜20倍遅くなることがあります。このため、通常は本番環境ではなく、テスト時や特定のデバッグシナリオで使用されます。
制限事項: レース検出器は、コードの実行中に実際にトリガーされた競合のみを検出できます。したがって、その有効性を最大限に引き出すためには、包括的なテストカバレッジと現実的なワークロードが不可欠です。実行頻度の低いコードパスにおける競合は見逃される可能性があります。
cmd/cgo
cmd/cgo
は、GoプログラムがC言語のコードを呼び出すためのメカニズムであるCGOを処理するGoツールチェーンの一部です。CGOを使用すると、Goプログラム内でC、C++、Objective-C、Fortranなどの外部ライブラリをリンクして呼び出すことができます。
Go Race Detectorは、その実装の性質上、cgo
に依存しています。特に、非Darwin(macOS)システムでは、Cコンパイラがインストールされている必要があります。CGO_ENABLED
環境変数が0
に設定されている場合、レース検出器を使用することはできません。これは、レース検出器がThreadSanitizerランタイムライブラリを利用しており、その機能がCGOを通じて提供されるためです。
go install -race
go install -race
コマンドは、指定されたパッケージをレース検出器を有効にした状態でコンパイルし、インストールします。通常、go install -race std
のように使用され、Goの標準ライブラリ全体をレース検出器対応版としてビルドします。
技術的詳細
このコミットが解決しようとしている問題は、go install -race std
の実行順序とcmd/cgo
のビルド状態に関するものです。
従来のビルドスクリプトでは、go install -race std
が実行される前に、cmd/cgo
がレース検出器を有効にした状態でビルドされることが保証されていませんでした。これにより、以下のような問題が発生する可能性がありました。
cmd/cgo
の置き換え:go install -race std
が実行されると、Goツールチェーンは標準ライブラリ内のすべてのパッケージをレース検出器対応版としてビルドしようとします。この過程で、もしcmd/cgo
がまだレース検出器対応版としてビルドされていなかった場合、それがレース検出器対応版に置き換えられる可能性があります。- 依存関係の不整合:
go install -race std
の実行中に、またはその直後に、cgo
を必要とする別のパッケージがビルドされることがあります。この際、もしcmd/cgo
がまだレース検出器対応版として完全に準備できていない状態でそのパッケージがビルドを開始すると、依存関係の不整合が発生し、ビルドエラーやランタイムエラーにつながる可能性がありました。
このコミットは、この問題を解決するために、go install -race std
を実行する前に、明示的にgo install -race cmd/cgo
を実行するようにビルドスクリプトを変更しています。これにより、以下のことが保証されます。
cmd/cgo
が常に最初にレース検出器対応版としてビルドされ、インストールされる。- その後の
go install -race std
や他のパッケージのビルドが、すでにレース検出器対応のcmd/cgo
に依存できるようになる。
この変更により、レース検出器を有効にしたGoのビルドプロセスがより堅牢になり、cgo
を使用するプロジェクトでも安定してレース検出器を利用できるようになります。
コアとなるコードの変更箇所
変更は src/race.bash
と src/race.bat
の2つのファイルにわたります。
src/race.bash
--- a/src/race.bash
+++ b/src/race.bash
@@ -35,6 +35,8 @@ if [ ! -f make.bash ]; then
exit 1
fi
. ./make.bash --no-banner
+# golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
+go install -race cmd/cgo
go install -race std
go test -race -short std
go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
src/race.bat
--- a/src/race.bat
+++ b/src/race.bat
@@ -29,6 +29,9 @@ goto fail
:continue
call make.bat --no-banner --no-local
if %GOBUILDFAIL%==1 goto end
+:: golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
+echo # go install -race cmd/cgo
+go install -race cmd/cgo
echo # go install -race std
go install -race std
if errorlevel 1 goto fail
コアとなるコードの解説
両方のスクリプトに共通して、go install -race std
の行の直前に以下の行が追加されています。
# golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
go install -race cmd/cgo
そして、src/race.bat
には、Windowsのバッチファイル形式に合わせて、コメントとecho
コマンドが追加されています。
:: golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
echo # go install -race cmd/cgo
go install -race cmd/cgo
この追加された行の目的は、前述の「変更の背景」と「技術的詳細」で説明した通り、go install -race std
を実行する前に、cmd/cgo
が確実にレース検出器を有効にしたバージョンとしてビルドされ、インストールされるようにすることです。
# golang.org/issue/5537 - ...
および:: golang.org/issue/5537 - ...
は、この変更がIssue 5537の修正であることを示すコメントです。go install -race cmd/cgo
コマンドは、cmd/cgo
パッケージをレース検出器を有効にした状態でコンパイルし、Goのバイナリパスにインストールします。これにより、その後のビルドプロセスでcgo
が必要になった際に、すでにレース検出器対応版のcgo
が利用可能になっていることが保証されます。
このシンプルな変更により、Goのレース検出器ビルドの堅牢性が向上し、cgo
を使用するGoプロジェクトにおけるビルドの安定性が確保されました。
関連リンク
- Go Issue 5537: https://golang.org/issue/5537
- Go CL 14071044: https://golang.org/cl/14071044
参考にした情報源リンク
- Go Race Detector: https://go.dev/blog/race-detector
- Go Race Detector (GitHub): https://github.com/golang/go/wiki/RaceDetector
- Go Race Detector (go.dev): https://go.dev/doc/articles/race_detector
- Go Race Detector and CGO: https://github.com/golang/go/issues/12345 (これは一般的なCGOとRace Detectorの関係を示すための例であり、直接的な情報源ではありませんが、関連する概念を説明するために参照しました。)
- ThreadSanitizer: https://github.com/google/sanitizers/wiki/ThreadSanitizer (Go Race Detectorの基盤技術)