[インデックス 18336] ファイルの概要
このコミットは、GoランタイムのARMアーキテクチャ向けコードにおけるタイプミスを修正するものです。具体的には、src/pkg/runtime/atomic_arm.c
ファイル内のruntime·xchgp
関数において、runtime·cas
の呼び出しがruntime·casp
に修正されています。このタイプミスは、以前のコミットによって導入され、ARMビルドがコンパイルできなくなる問題を引き起こしていました。
コミット
commit f7245c062668199fcb505de47d694ceaed512394
Author: Russ Cox <rsc@golang.org>
Date: Wed Jan 22 16:39:39 2014 -0500
runtime: fix typo in ARM code
The typo was introduced by one of Dmitriy's CLs this morning.
The fix makes the ARM build compile again; it still won't pass
its tests, but one thing at a time.
TBR=dvyukov
CC=golang-codereviews
https://golang.org/cl/55770044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f7245c062668199fcb505de47d694ceaed512394
元コミット内容
runtime: fix typo in ARM code
The typo was introduced by one of Dmitriy's CLs this morning.
The fix makes the ARM build compile again; it still won't pass
its tests, but one thing at a time.
TBR=dvyukov
CC=golang-codereviews
https://golang.org/cl/55770044
変更の背景
この変更は、GoランタイムのARMアーキテクチャ向けコードに存在するタイプミスを修正するために行われました。コミットメッセージによると、このタイプミスはDmitriy氏による以前の変更リスト(CL: Change List)によって同日中に導入されたものです。このタイプミスが原因で、GoのARMビルドがコンパイルに失敗する問題が発生していました。
Go言語はクロスプラットフォーム対応を重視しており、様々なアーキテクチャで動作するように設計されています。ARMアーキテクチャは、モバイルデバイスや組み込みシステム、最近ではサーバー分野でも広く利用されており、Goがこれらの環境で適切に動作することは非常に重要です。コンパイルエラーは、そのアーキテクチャでのGoの利用を妨げるため、迅速な修正が必要とされました。
コミットメッセージには「The fix makes the ARM build compile again; it still won't pass its tests, but one thing at a time.」とあり、この修正がコンパイルエラーを解消するものの、まだテストが通らない状態であることを示唆しています。これは、コンパイル可能にすることが最初のステップであり、その後のテストの修正は別の課題として認識されていることを意味します。
前提知識の解説
Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション、スケジューリング(ゴルーチンの管理)、メモリ割り当て、プリミティブな同期操作などが含まれます。Goプログラムは、コンパイル時にランタイムとリンクされ、自己完結型のバイナリを生成します。ランタイムはGo言語で書かれた部分と、Cやアセンブリ言語で書かれた低レベルな部分(特にアーキテクチャ固有のコード)から構成されます。
ARMアーキテクチャ (Advanced RISC Machine)
ARMは、モバイルデバイス(スマートフォン、タブレット)、組み込みシステム、IoTデバイス、そして最近ではサーバーやラップトップPCなど、幅広い分野で利用されているCPUアーキテクチャです。RISC(Reduced Instruction Set Computer)の原則に基づいて設計されており、電力効率と性能のバランスが特徴です。Go言語は、ARMを含む複数のアーキテクチャをサポートしており、それぞれのアーキテクチャに最適化されたランタイムコードを持っています。
アトミック操作 (Atomic Operations)
アトミック操作とは、複数のスレッドやゴルーチンから同時にアクセスされた場合でも、その操作全体が不可分(atomic)であることを保証する操作です。つまり、操作の途中で他のスレッドから割り込まれることがなく、常に一貫した状態を保ちます。マルチコアプロセッサ環境では、共有データへのアクセス競合を防ぐためにアトミック操作が不可欠です。Goランタイムでは、sync/atomic
パッケージを通じてアトミック操作が提供されており、またランタイム内部でも低レベルなアトミック操作が利用されています。
runtime·cas
と runtime·casp
Goランタイムの内部では、C言語で書かれた低レベルな関数が多数存在します。これらの関数は、Goのソースコードからは直接呼び出されず、Goコンパイラやランタイムによって内部的に利用されます。
runtime·cas
(Compare And Swap): 一般的なCAS操作を実装した関数です。これは、メモリ上の特定のアドレスにある値が期待する値と一致する場合にのみ、その値を新しい値に更新するという操作です。この操作はアトミックに行われます。cas
は通常、ポインタ以外の整数型などの値に対して使用されます。runtime·casp
(Compare And Swap Pointer):runtime·cas
と同様のCAS操作ですが、特にポインタ(void*
など)に対して使用されることを意図しています。ポインタの比較とスワップは、ガベージコレクタやメモリ管理において非常に重要です。ポインタのサイズやアライメントはアーキテクチャによって異なる場合があるため、ポインタ専用のCAS関数が存在することがあります。
runtime·xchgp
(Exchange Pointer)
runtime·xchgp
は、ポインタの値をアトミックに交換(exchange)する関数です。これは、指定されたメモリ位置にあるポインタの値を新しい値に設定し、そのメモリ位置にあった元の値を返します。この操作もアトミックに行われる必要があります。
この関数の内部実装では、通常、CASループが使用されます。つまり、現在の値を読み込み、新しい値と交換しようと試み、もしその間に他のスレッドによって値が変更されていなければ成功し、そうでなければ再試行するというループです。
技術的詳細
このコミットの技術的な詳細は、runtime·xchgp
関数がruntime·casp
ではなく誤ってruntime·cas
を呼び出していた点に集約されます。
runtime·xchgp
は、ポインタ(void* volatile* addr
)を操作する関数です。ポインタを操作するアトミックなCAS操作には、通常、ポインタ専用のruntime·casp
が使用されるべきです。これは、ポインタのサイズやアライメントが、一般的な整数型とは異なる場合があるためです。特に、32ビットアーキテクチャ(ARMなど)で64ビットポインタを扱う場合や、ポインタが特定のメモリ境界にアラインされている必要がある場合など、アーキテクチャ固有の考慮事項が存在します。
runtime·cas
は、汎用的なCAS操作を提供しますが、ポインタの型安全性やアーキテクチャ固有の最適化を考慮すると、ポインタにはruntime·casp
を使用するのが適切です。誤ってruntime·cas
を呼び出したことで、コンパイラが型ミスマッチを検出したり、あるいはより深刻な問題として、生成されるアセンブリコードが正しくないアトミック操作を実行しようとしたりする可能性がありました。コミットメッセージにある「The fix makes the ARM build compile again」という記述から、このタイプミスがコンパイルエラーに直結していたことがわかります。これは、コンパイラがruntime·cas
に渡された引数の型(void* volatile*
やvoid*
)と、runtime·cas
が期待する引数の型との間に不整合を見つけたためと考えられます。
この修正は、Goランタイムの低レベルな部分、特にアトミック操作の正確性が、マルチスレッド環境でのプログラムの安定性と正確性にいかに重要であるかを示しています。わずかなタイプミスでも、特定のアーキテクチャでのビルドを完全に停止させる可能性があります。
コアとなるコードの変更箇所
--- a/src/pkg/runtime/atomic_arm.c
+++ b/src/pkg/runtime/atomic_arm.c
@@ -49,7 +49,7 @@ runtime·xchgp(void* volatile* addr, void* v)
for(;;) {
old = *addr;
- if(runtime·cas(addr, old, v))
+ if(runtime·casp(addr, old, v))
return old;
}
}
コアとなるコードの解説
変更はsrc/pkg/runtime/atomic_arm.c
ファイル内のruntime·xchgp
関数にあります。
runtime·xchgp
関数は、addr
が指すメモリ位置にあるポインタの値を、アトミックにv
に交換し、元の値を返すことを目的としています。この関数は、無限ループfor(;;)
の中でCAS(Compare And Swap)操作を繰り返し試行することで実装されています。
old = *addr;
: まず、addr
が指す現在のポインタの値をold
変数に読み込みます。if(runtime·cas(addr, old, v))
: ここが変更点です。元のコードではruntime·cas
が呼び出されていました。runtime·cas(addr, old, v)
:addr
が指す値がold
と等しい場合にのみ、その値をv
に更新します。この操作が成功した場合(つまり、old
が読み込まれてからcas
が実行されるまでの間に他のスレッドによって値が変更されなかった場合)、true
を返します。
if(runtime·casp(addr, old, v))
: 修正後のコードではruntime·casp
が呼び出されています。runtime·casp(addr, old, v)
:runtime·cas
と同様の機能ですが、ポインタ型(void*
)に特化しています。addr
が指すポインタがold
と等しい場合にのみ、そのポインタをv
に更新します。
return old;
: CAS操作が成功した場合、ループを抜けて、交換される前の元の値old
を返します。CASが失敗した場合は、ループの先頭に戻り、再度現在の値を読み込んでCASを試行します。
この変更の核心は、runtime·xchgp
がポインタを操作する関数であるため、ポインタ専用のCAS関数であるruntime·casp
を使用することが正しいという点です。runtime·cas
は汎用的なCAS関数ですが、ポインタの型安全性や、特定のアーキテクチャ(この場合はARM)におけるポインタのアトミック操作の正確な実装を保証するためには、runtime·casp
がより適切です。この修正により、ARMビルドのコンパイルエラーが解消されました。
関連リンク
- Go CL 55770044: https://golang.org/cl/55770044
参考にした情報源リンク
- Go言語のソースコード(
src/pkg/runtime/atomic_arm.c
) - Go言語のドキュメント(Goランタイム、アトミック操作に関する一般的な情報)
- ARMアーキテクチャに関する一般的な情報
- Compare-and-swap - Wikipedia: https://en.wikipedia.org/wiki/Compare-and-swap
- Go runtime source code (for understanding
runtime·cas
andruntime·casp
conventions) - Go issue tracker or mailing lists (if specific discussions about this bug were found, though none were explicitly searched for this explanation)