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

[インデックス 17715] ファイルの概要

このコミットは、Go言語のランタイムにおけるレース検出器(Race Detector)のビルドプロセスに関する修正です。具体的には、src/race.bashsrc/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がレース検出器を有効にした状態でビルドされることが保証されていませんでした。これにより、以下のような問題が発生する可能性がありました。

  1. cmd/cgoの置き換え: go install -race stdが実行されると、Goツールチェーンは標準ライブラリ内のすべてのパッケージをレース検出器対応版としてビルドしようとします。この過程で、もしcmd/cgoがまだレース検出器対応版としてビルドされていなかった場合、それがレース検出器対応版に置き換えられる可能性があります。
  2. 依存関係の不整合: 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.bashsrc/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プロジェクトにおけるビルドの安定性が確保されました。

関連リンク

参考にした情報源リンク