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

[インデックス 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_Semacquirenetpoll.goc に配置したが、NetBSDがまだ netpoll.goc を使用していないため、ビルドが壊れるという問題が説明されています。

変更の背景

Goランタイムは、様々なオペレーティングシステム(OS)とアーキテクチャをサポートするように設計されています。各OSには、ネットワークI/Oや同期プリミティブなど、特定の機能を実現するための独自の実装が必要となる場合があります。

このコミットが行われた2013年当時、Goランタイムのネットワークポーリング(netpoll)の仕組みは進化の途中にありました。netpoll.goc は、ネットワークイベントの効率的な監視と処理を担当するコードが含まれるファイルです。しかし、NetBSDのような一部のOSでは、この新しい netpoll.goc のインフラストラクチャがまだ完全に統合されていませんでした。

runtime_Semacquireruntime_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.gonetpoll_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_Semacquirenet.runtime_Semreleasenetpoll.goc から sema.goc へ移動しました。sema.goc は、セマフォの基本的な実装を含むファイルであり、Goランタイムのコア部分として、すべてのOSで常にコンパイルされ、リンクされることが期待されます。これにより、NetBSDを含むすべてのOSでこれらのセマフォ関数が確実に利用できるようになり、ビルドエラーが解消されました。

移動された関数は、net·runtime_Semacquirenet·runtime_Semrelease という名前で sema.goc に追加されています。ここで net· というプレフィックスが付いているのは、これらの関数が元々ネットワーク関連のコンテキストで使用されていたことを示唆しています。また、// TODO(dvyukov): move to netpoll.goc once it's used by all OSes. というコメントは、この変更が一時的な回避策であり、将来的には netpoll.goc がすべてのOSで利用されるようになった時点で、これらの関数を元の場所に戻す意図があったことを明確に示しています。これは、コードの論理的な配置と、OS間の互換性のバランスを取るための典型的なアプローチです。

コアとなるコードの変更箇所

このコミットでは、以下の2つのファイルが変更されています。

  1. src/pkg/runtime/netpoll.goc
  2. 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_Semacquireruntime_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_Semacquirenet·runtime_Semrelease の定義が sema.goc に追加されています。これらの関数は、既存の runtime·semacquire および runtime·semrelease を呼び出しています。

コアとなるコードの解説

このコミットの核心は、Goランタイムのセマフォ操作関数である runtime_Semacquireruntime_Semrelease の定義を、netpoll.goc から sema.goc へ移動した点にあります。

  • netpoll.goc からの削除: netpoll.goc はネットワークポーリングに関連するコードを扱うファイルです。元々ここに runtime_Semacquireruntime_Semrelease が定義されていたのは、ネットワークI/Oの待機や完了通知の際にセマフォが利用されていたためと考えられます。しかし、NetBSDのような一部のOSでは、この netpoll.goc がビルドプロセスで適切に扱われない、あるいは完全に利用されていない状況がありました。そのため、これらの関数が netpoll.goc にあると、NetBSDのビルドが失敗する原因となっていました。

  • sema.goc への追加: sema.goc は、Goランタイムのセマフォ実装のコア部分を担うファイルです。ここに net·runtime_Semacquirenet·runtime_Semrelease が追加されたことで、これらのセマフォ操作関数は、Goランタイムのより基本的な、OSに依存しない部分に配置されることになります。これにより、NetBSDを含むすべてのOSでこれらの関数が確実にコンパイルされ、リンクされるようになり、ビルドの問題が解決されました。

    追加された関数 net·runtime_Semacquirenet·runtime_Semrelease は、それぞれ内部的に runtime·semacquireruntime·semrelease を呼び出しています。これは、セマフォの実際のP/V操作は runtime·semacquireruntime·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.gogo tool compile のドキュメントを参照すると、その役割を推測できます。
  • Goのクロスプラットフォーム対応に関する情報: https://go.dev/doc/install/source (Goのソースからのビルドに関する情報)
  • Goのランタイム内部に関するブログ記事やカンファレンストーク: Goのランタイムは複雑なため、公式ドキュメント以外にも、Go開発者によるブログ記事やカンファレンストークが理解を深めるのに役立ちます。例えば、Dmitriy Vyukov氏のGoランタイムに関する発表など。