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

[インデックス 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·casruntime·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)操作を繰り返し試行することで実装されています。

  1. old = *addr;: まず、addrが指す現在のポインタの値をold変数に読み込みます。
  2. if(runtime·cas(addr, old, v)): ここが変更点です。元のコードではruntime·casが呼び出されていました。
    • runtime·cas(addr, old, v): addrが指す値がoldと等しい場合にのみ、その値をvに更新します。この操作が成功した場合(つまり、oldが読み込まれてからcasが実行されるまでの間に他のスレッドによって値が変更されなかった場合)、trueを返します。
  3. if(runtime·casp(addr, old, v)): 修正後のコードではruntime·caspが呼び出されています。
    • runtime·casp(addr, old, v): runtime·casと同様の機能ですが、ポインタ型(void*)に特化しています。addrが指すポインタがoldと等しい場合にのみ、そのポインタをvに更新します。
  4. return old;: CAS操作が成功した場合、ループを抜けて、交換される前の元の値oldを返します。CASが失敗した場合は、ループの先頭に戻り、再度現在の値を読み込んでCASを試行します。

この変更の核心は、runtime·xchgpがポインタを操作する関数であるため、ポインタ専用のCAS関数であるruntime·caspを使用することが正しいという点です。runtime·casは汎用的なCAS関数ですが、ポインタの型安全性や、特定のアーキテクチャ(この場合はARM)におけるポインタのアトミック操作の正確な実装を保証するためには、runtime·caspがより適切です。この修正により、ARMビルドのコンパイルエラーが解消されました。

関連リンク

参考にした情報源リンク

  • 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 and runtime·casp conventions)
  • Go issue tracker or mailing lists (if specific discussions about this bug were found, though none were explicitly searched for this explanation)