[インデックス 17129] ファイルの概要
このコミットは、GoランタイムにおけるNetBSDビルドの問題を修正するためのものです。具体的には、runtime_Semacquire
および runtime_Semrelease
というセマフォ操作に関連する関数が、netpoll.goc
から sema.goc
へ移動されています。この変更は、NetBSDが当時まだ netpoll.goc
を使用していなかったという状況に対応するための暫定的な措置として行われました。
コミット
commit cc0a005c9d68c314fbf7eab92f0c04623df8a770
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Fri Aug 9 22:17:12 2013 +0400
runtime: fix netbsd build
I've placed net.runtime_Semacquire into netpoll.goc,
but netbsd does not yet use netpoll.goc.
R=golang-dev, bradfitz, iant
CC=golang-dev
https://golang.org/cl/12699045
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cc0a005c9d68c314fbf7eab92f0c04623df8a770
元コミット内容
このコミットの元の内容は、runtime: fix netbsd build
という簡潔なものです。コミットメッセージには、net.runtime_Semacquire
を netpoll.goc
に配置したが、NetBSDがまだ netpoll.goc
を使用していないため、ビルドが壊れるという問題が説明されています。
変更の背景
Goランタイムは、様々なオペレーティングシステム(OS)とアーキテクチャをサポートするように設計されています。各OSには、ネットワークI/Oや同期プリミティブなど、特定の機能を実現するための独自の実装が必要となる場合があります。
このコミットが行われた2013年当時、Goランタイムのネットワークポーリング(netpoll
)の仕組みは進化の途中にありました。netpoll.goc
は、ネットワークイベントの効率的な監視と処理を担当するコードが含まれるファイルです。しかし、NetBSDのような一部のOSでは、この新しい netpoll.goc
のインフラストラクチャがまだ完全に統合されていませんでした。
runtime_Semacquire
と runtime_Semrelease
は、Goランタイム内部で使用されるセマフォ操作関数であり、ゴルーチン間の同期やリソースの排他制御に不可欠です。これらの関数が netpoll.goc
に配置されていた場合、NetBSDのビルドプロセスでは netpoll.goc
がコンパイル対象外となるか、あるいは必要なシンボルが解決できないためにリンクエラーが発生する可能性がありました。
この問題を解決するため、これらのセマフォ操作関数を、より汎用的な同期プリミティブを扱う sema.goc
に移動するという判断が下されました。これにより、NetBSDを含むすべてのOSでこれらの関数が利用可能となり、ビルドが成功するようになります。コミットメッセージにある // TODO(dvyukov): move to netpoll.goc once it's used by all OSes.
というコメントは、この変更が一時的なものであり、将来的には netpoll.goc
がすべてのOSで利用されるようになった時点で元の場所に戻す意図があったことを示唆しています。
前提知識の解説
Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理する低レベルのシステムです。これには、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、メモリ管理、同期プリミティブ、システムコールインターフェースなどが含まれます。Goプログラムは、OSのネイティブスレッド上で実行されますが、ゴルーチンのスケジューリングやメモリ管理といった多くの複雑なタスクは、Goランタイムによって抽象化され、効率的に処理されます。
netpoll.goc
netpoll.goc
は、Goランタイムにおけるネットワークポーリングのメカニズムを実装するファイルです。ネットワークポーリングは、複数のネットワーク接続からのI/Oイベント(データの読み書き準備完了など)を効率的に監視し、イベントが発生した際に適切なゴルーチンを起動するために使用されます。これは、ノンブロッキングI/Oとイベント駆動型プログラミングの基盤となります。OSごとに異なるネットワークI/O多重化メカニズム(例: Linuxのepoll、macOS/FreeBSDのkqueue、WindowsのIOCP)を利用するため、このファイルにはOS固有のコードが含まれることがあります。
sema.goc
sema.goc
は、Goランタイムにおけるセマフォ(semaphore)の実装を含むファイルです。セマフォは、複数のゴルーチンが共有リソースにアクセスする際の同期を制御するためのプリミティブです。runtime_Semacquire
はセマフォの取得(P操作、待機)、runtime_Semrelease
はセマフォの解放(V操作、通知)に対応します。これらの関数は、ミューテックス、条件変数、チャネルなどの高レベルな同期プリミティブの基盤として、ランタイム内部で広く利用されます。
セマフォ (Semaphore)
セマフォは、並行プログラミングにおける同期メカニズムの一つです。カウンタ変数と2つの原子操作(P操作とV操作)から構成されます。
- P操作 (Proberen/Test): セマフォのカウンタをデクリメントします。カウンタが0の場合、操作はブロックされ、カウンタが正になるまで待機します。
- V操作 (Verhogen/Increment): セマフォのカウンタをインクリメントします。待機しているプロセスやスレッドがある場合、そのうちの一つを再開させます。 セマフォは、リソースの利用可能数を管理したり、特定の処理の順序を強制したりするために使用されます。
技術的詳細
このコミットの技術的詳細は、Goランタイムのビルドシステムと、OS固有のコードパスの管理方法に深く関連しています。
Goランタイムは、src/pkg/runtime
ディレクトリ以下に、様々なOSやアーキテクチャに特化したコードを配置しています。例えば、netpoll_linux.go
や netpoll_darwin.go
のように、ファイル名にOS名が含まれることで、特定のOSでのみコンパイルされるようになっています。しかし、netpoll.goc
のような .goc
ファイルは、GoのソースコードからCコードを生成し、それをコンパイルしてランタイムにリンクする特殊なビルドプロセスの一部です。
コミットメッセージによると、net.runtime_Semacquire
は当初 netpoll.goc
に配置されていました。これは、ネットワークポーリングのコンテキストでセマフォが必要とされたためと考えられます。しかし、NetBSDのビルドでは、netpoll.goc
がまだ完全に統合されていなかったか、あるいは特定のビルドフラグや条件によってコンパイル対象から外されていた可能性があります。その結果、NetBSD上でGoをビルドしようとすると、net.runtime_Semacquire
のシンボルが見つからず、リンクエラーが発生していました。
この問題を解決するために、Dmitriy Vyukovは net.runtime_Semacquire
と net.runtime_Semrelease
を netpoll.goc
から sema.goc
へ移動しました。sema.goc
は、セマフォの基本的な実装を含むファイルであり、Goランタイムのコア部分として、すべてのOSで常にコンパイルされ、リンクされることが期待されます。これにより、NetBSDを含むすべてのOSでこれらのセマフォ関数が確実に利用できるようになり、ビルドエラーが解消されました。
移動された関数は、net·runtime_Semacquire
と net·runtime_Semrelease
という名前で sema.goc
に追加されています。ここで net·
というプレフィックスが付いているのは、これらの関数が元々ネットワーク関連のコンテキストで使用されていたことを示唆しています。また、// TODO(dvyukov): move to netpoll.goc once it's used by all OSes.
というコメントは、この変更が一時的な回避策であり、将来的には netpoll.goc
がすべてのOSで利用されるようになった時点で、これらの関数を元の場所に戻す意図があったことを明確に示しています。これは、コードの論理的な配置と、OS間の互換性のバランスを取るための典型的なアプローチです。
コアとなるコードの変更箇所
このコミットでは、以下の2つのファイルが変更されています。
src/pkg/runtime/netpoll.goc
src/pkg/runtime/sema.goc
具体的な変更内容は以下の通りです。
src/pkg/runtime/netpoll.goc
からの削除:
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/runtime/netpoll.goc
@@ -206,14 +206,6 @@ func runtime_pollUnblock(pd *PollDesc) {
runtime·ready(wg);
}
-func runtime_Semacquire(addr *uint32) {
- runtime·semacquire(addr, true);
-}
-
-func runtime_Semrelease(addr *uint32) {
- runtime·semrelease(addr);
-}
-
uintptr
runtime·netpollfd(PollDesc *pd)
{
runtime_Semacquire
と runtime_Semrelease
の定義が netpoll.goc
から削除されています。
src/pkg/runtime/sema.goc
への追加:
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -182,6 +182,17 @@ runtime·semrelease(uint32 volatile *addr)
}
}
+// TODO(dvyukov): move to netpoll.goc once it's used by all OSes.
+void net·runtime_Semacquire(uint32 *addr)
+{
+ runtime·semacquire(addr, true);
+}
+
+void net·runtime_Semrelease(uint32 *addr)
+{
+ runtime·semrelease(addr);
+}
+
func runtime_Semacquire(addr *uint32) {
runtime·semacquire(addr, true);
}
net·runtime_Semacquire
と net·runtime_Semrelease
の定義が sema.goc
に追加されています。これらの関数は、既存の runtime·semacquire
および runtime·semrelease
を呼び出しています。
コアとなるコードの解説
このコミットの核心は、Goランタイムのセマフォ操作関数である runtime_Semacquire
と runtime_Semrelease
の定義を、netpoll.goc
から sema.goc
へ移動した点にあります。
-
netpoll.goc
からの削除:netpoll.goc
はネットワークポーリングに関連するコードを扱うファイルです。元々ここにruntime_Semacquire
とruntime_Semrelease
が定義されていたのは、ネットワークI/Oの待機や完了通知の際にセマフォが利用されていたためと考えられます。しかし、NetBSDのような一部のOSでは、このnetpoll.goc
がビルドプロセスで適切に扱われない、あるいは完全に利用されていない状況がありました。そのため、これらの関数がnetpoll.goc
にあると、NetBSDのビルドが失敗する原因となっていました。 -
sema.goc
への追加:sema.goc
は、Goランタイムのセマフォ実装のコア部分を担うファイルです。ここにnet·runtime_Semacquire
とnet·runtime_Semrelease
が追加されたことで、これらのセマフォ操作関数は、Goランタイムのより基本的な、OSに依存しない部分に配置されることになります。これにより、NetBSDを含むすべてのOSでこれらの関数が確実にコンパイルされ、リンクされるようになり、ビルドの問題が解決されました。追加された関数
net·runtime_Semacquire
とnet·runtime_Semrelease
は、それぞれ内部的にruntime·semacquire
とruntime·semrelease
を呼び出しています。これは、セマフォの実際のP/V操作はruntime·semacquire
とruntime·semrelease
が担当し、net·
プレフィックスの付いた関数は、特定のコンテキスト(この場合はネットワーク関連)から呼び出されるラッパー関数としての役割を果たすことを意味します。また、
// TODO(dvyukov): move to netpoll.goc once it's used by all OSes.
というコメントは非常に重要です。これは、この変更が永続的なものではなく、NetBSDを含むすべてのOSがnetpoll.goc
の新しいインフラストラクチャを完全に採用した時点で、これらの関数を再びnetpoll.goc
に戻す意図があったことを示しています。これは、コードの論理的な構造と、特定のOSの互換性要件との間でバランスを取るための、現実的なエンジニアリング判断を示しています。
このコミットは、Goランタイムが多様なOS環境で安定して動作するための、継続的な努力と適応性を示す良い例と言えます。
関連リンク
- Go issue tracker (Go CL 12699045): https://golang.org/cl/12699045 (これはコミットメッセージに記載されているGo Code Reviewのリンクであり、詳細な議論や変更履歴が確認できます。)
参考にした情報源リンク
- Go言語の公式ドキュメント (Go Runtimeに関する一般的な情報): https://go.dev/doc/
- Go言語のソースコード (特に
src/runtime
ディレクトリ): https://github.com/golang/go/tree/master/src/runtime - セマフォに関する一般的な情報 (Wikipediaなど): https://ja.wikipedia.org/wiki/%E3%82%BB%E3%83%9E%E3%83%95%E3%82%A9
- Goのビルドシステムに関する情報 (Goのドキュメントやブログ記事): https://go.dev/doc/code
- Goのネットワークポーリングに関する情報 (Goのソースコードや関連する設計ドキュメント): https://go.dev/src/runtime/netpoll.go (これはGoのソースコードへの直接リンクであり、
netpoll
の実装を理解するのに役立ちます。) - Goの同期プリミティブに関する情報 (GoのドキュメントやGo Concurrency Patternsなど): https://go.dev/blog/concurrency-patterns
- Goの
goc
ファイルに関する情報 (Goのソースコードや関連するビルドシステムの説明):goc
ファイルはGoの内部的なビルドプロセスで使用されるもので、GoのソースコードからCコードを生成するために使われます。これに関する公式ドキュメントは少ないですが、Goのソースコードリポジトリ内でmkruntime.go
やgo tool compile
のドキュメントを参照すると、その役割を推測できます。 - Goのクロスプラットフォーム対応に関する情報: https://go.dev/doc/install/source (Goのソースからのビルドに関する情報)
- Goのランタイム内部に関するブログ記事やカンファレンストーク: Goのランタイムは複雑なため、公式ドキュメント以外にも、Go開発者によるブログ記事やカンファレンストークが理解を深めるのに役立ちます。例えば、Dmitriy Vyukov氏のGoランタイムに関する発表など。