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

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

このコミットは、Go言語のランタイムにおけるNetBSD固有のコードの修正に関するものです。具体的には、runtime·lwp_tramp関数のextern宣言が誤ってCソースファイル(.c)に配置されていた問題を修正し、正しいヘッダーファイル(.h)に移動させることで、ランタイムの再編成(reorg)後に発生したNetBSD関連のビルドまたはリンクエラーを解決しています。

コミット

commit 214c1784934ec6584a5039a757f1c892d0faded6
Author: Russ Cox <rsc@golang.org>
Date:   Thu Mar 14 17:53:01 2013 -0400

    runtime: fix netbsd again after reorg
    
    This time for sure.
    That C file sure looked like a header file to me. :-)
    
    R=golang-dev
    CC=golang-dev
    https://golang.org/cl/7830043

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/214c1784934ec6584a5039a757f1c892d0faded6

元コミット内容

このコミットは、GoランタイムにおけるNetBSD関連のバグを修正するものです。以前のランタイムの再編成(reorg)後に問題が発生しており、今回の修正で確実に解決することを目指しています。コミットメッセージの「That C file sure looked like a header file to me. :-)」という記述は、os_netbsd.cというCソースファイルが誤ってヘッダーファイルのように扱われ、本来ヘッダーファイルに記述すべきextern宣言がそこに置かれていたことを示唆しています。

変更の背景

Go言語のランタイムは、様々なオペレーティングシステム(OS)やアーキテクチャに対応するために、OS固有のコードを含んでいます。NetBSDもその一つです。コミットメッセージにある「reorg」とは、Goランタイムの内部構造やファイル配置の大規模な再編成を指していると考えられます。このような再編成は、コードベースの整理、保守性の向上、新しい機能の追加などを目的として行われますが、その過程で既存のコードの依存関係が変更され、予期せぬバグやビルドエラーが発生することがあります。

このコミットは、以前の「reorg」によってNetBSDのランタイムコードに問題が生じ、runtime·lwp_tramp関数の宣言が不適切な場所に配置されてしまったことが原因で発生した問題を修正するために行われました。開発者は、os_netbsd.cファイルがヘッダーファイルのように見えてしまったため、誤ってextern宣言をそこに記述してしまったと述べています。これは、C言語のコンパイルとリンクの仕組みを理解していれば、ビルドエラーやリンクエラーの原因となる典型的な間違いです。

前提知識の解説

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理する低レベルのシステムです。これには、ガベージコレクション、スケジューラ(ゴルーチンの管理)、メモリ管理、システムコールインターフェースなどが含まれます。Goプログラムは、OSのネイティブスレッド上で動作しますが、Goランタイムがその上でゴルーチンをスケジューリングし、効率的な並行処理を実現します。ランタイムの一部はGoで書かれていますが、OSとの直接的なやり取りやパフォーマンスが重要な部分はCやアセンブリ言語で書かれています。

NetBSD

NetBSDは、BSD系UNIXライクなオープンソースのオペレーティングシステムです。非常に移植性が高く、多くの異なるハードウェアアーキテクチャで動作することで知られています。Go言語は、NetBSDを含む様々なOSをサポートしており、それぞれのOSの特性に合わせたランタイムコードを持っています。

軽量プロセス (Lightweight Process, LWP)

LWPは、一部のUNIX系OS(Solaris、NetBSDなど)で採用されているスレッド実装の概念です。LWPは、ユーザーレベルスレッドとカーネルスレッドの中間に位置し、カーネルによってスケジューリングされる実行単位です。Goランタイムは、OSのLWPやスレッドを利用してゴルーチンをOSレベルで実行します。lwp_tramplwp_mcontext_initlwp_parklwp_unparklwp_selfといった関数は、NetBSDにおけるLWPの操作に関連するGoランタイムの内部関数であると推測されます。これらは、ゴルーチンのスケジューリングやコンテキストスイッチ、スレッドの待機・再開などに利用される低レベルのプリミティブです。

extern キーワード (C言語)

C言語におけるexternキーワードは、変数や関数の宣言が、現在のファイルではなく、別のファイルで定義されていることをコンパイラに伝えます。これにより、複数のソースファイルにまたがるプログラムで、シンボル(変数名や関数名)を共有することができます。

  • 宣言 (Declaration): 変数や関数の名前と型をコンパイラに知らせること。メモリを割り当てたり、コードを生成したりはしない。
  • 定義 (Definition): 変数にメモリを割り当てたり、関数の実際のコードを記述すること。

通常、関数のextern宣言はヘッダーファイル(.h)に記述され、そのヘッダーファイルをインクルードするすべてのソースファイルでその関数が利用可能になります。関数の実際の定義は、対応するCソースファイル(.c)に記述されます。

Cソースファイル (.c) とヘッダーファイル (.h)

  • Cソースファイル (.c): 実際のプログラムロジック、関数の定義、変数の定義などが記述されます。コンパイラによってオブジェクトファイル(.o)にコンパイルされます。
  • ヘッダーファイル (.h): 関数プロトタイプ(宣言)、マクロ定義、構造体定義、外部変数宣言などが記述されます。他のソースファイルから利用される共通の宣言をまとめるために使用されます。ソースファイルは、#includeプリプロセッサディレクティブを使ってヘッダーファイルを読み込みます。

このコミットの核心は、extern宣言が本来ヘッダーファイルに属するものであるにもかかわらず、誤ってCソースファイルに記述されていたという点にあります。

技術的詳細

このコミットの技術的な問題は、C言語のコンパイルとリンクの基本的な原則に違反していたことに起因します。

runtime·lwp_trampは、GoランタイムがNetBSD上でLWPを操作するために使用する内部関数であると推測されます。この関数は、おそらくアセンブリ言語で実装されており、その定義は別のファイル(例えば、runtime/asm_netbsd_amd64.sのようなアセンブリファイル)に存在します。

問題は、この関数のextern宣言がsrc/pkg/runtime/os_netbsd.cに記述されていたことです。 src/pkg/runtime/os_netbsd.cは、NetBSD固有のOSインターフェースを扱うCソースファイルであり、通常はOS固有のシステムコールラッパーやLWP関連のGoランタイム関数を定義します。しかし、runtime·lwp_trampがこのファイルで定義されているわけではなく、単に外部で定義されていることを宣言しているだけでした。

このextern宣言が.cファイルにあると、その.cファイルがコンパイルされる際には問題ないかもしれませんが、他のファイルがruntime·lwp_trampを利用しようとした際に、その宣言が見つからなかったり、あるいはリンカが複数の定義を見つけてしまう(もし他の場所でも誤って宣言されていた場合)といった問題を引き起こす可能性があります。

正しいアプローチは、runtime·lwp_trampextern宣言を、この関数を利用する可能性のあるすべてのソースファイルがインクルードする共通のヘッダーファイル、この場合はsrc/pkg/runtime/os_netbsd.hに配置することです。ヘッダーファイルに宣言を置くことで、コンパイラはruntime·lwp_trampが外部で定義されていることを認識し、リンク時にその定義を正しく解決できるようになります。

コミットメッセージの「That C file sure looked like a header file to me. :-)」というコメントは、開発者がos_netbsd.cの内容を見て、そこに多くのextern宣言や型定義が含まれていたため、誤ってヘッダーファイルであると認識してしまった可能性を示唆しています。これは、大規模なコードベースの再編成中に、ファイルの役割や依存関係が一時的に不明瞭になることがあるという、ソフトウェア開発における一般的な課題を浮き彫りにしています。

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

--- a/src/pkg/runtime/os_netbsd.c
+++ b/src/pkg/runtime/os_netbsd.c
@@ -30,7 +30,6 @@ extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void
 extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
 extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
 extern int32 runtime·lwp_self(void);
-extern void runtime·lwp_tramp(void);
 
 // From NetBSD\'s <sys/sysctl.h>
 #define	CTL_HW	6
diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h
index 84e0b241d1..c193ae0b4a 100644
--- a/src/pkg/runtime/os_netbsd.h
+++ b/src/pkg/runtime/os_netbsd.h
@@ -17,6 +17,7 @@ void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
 void	runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
 void	runtime·sigprocmask(int32, Sigset*, Sigset*);
 int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+extern void runtime·lwp_tramp(void);
 
 #define	NSIG 33
 #define	SI_USER	0

コアとなるコードの解説

このコミットは、以下の2つのファイルに対する変更を含んでいます。

  1. src/pkg/runtime/os_netbsd.c からの削除:

    -extern void runtime·lwp_tramp(void);
    

    この行は、runtime·lwp_tramp関数のextern宣言をos_netbsd.cファイルから削除しています。これは、この宣言が本来ここに属するものではないという認識に基づいています。os_netbsd.cは、NetBSD固有のランタイム機能の実装を含むCソースファイルであり、外部関数の宣言をグローバルに提供する役割はヘッダーファイルにあります。

  2. src/pkg/runtime/os_netbsd.h への追加:

    +extern void runtime·lwp_tramp(void);
    

    この行は、runtime·lwp_tramp関数のextern宣言をos_netbsd.hファイルに追加しています。os_netbsd.hは、NetBSD固有のランタイム機能に関連する共通の宣言や定義を含むヘッダーファイルです。このヘッダーファイルをインクルードするすべてのソースファイルは、runtime·lwp_tramp関数が外部で定義されていることを認識し、正しくコンパイルおよびリンクできるようになります。

この変更により、runtime·lwp_trampの宣言がC言語の慣習に従って適切なヘッダーファイルに移動され、GoランタイムのNetBSDビルドにおける潜在的なコンパイルまたはリンクエラーが解消されます。これは、コードの構造と依存関係を正しく保つための重要な修正です。

関連リンク

参考にした情報源リンク