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

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

コミット

commit be8025604e1175ef3e0718ca70d5ba38c928b976
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Thu Nov 10 10:02:24 2011 +0900

    runtime: fix freebsd build
    
    R=rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/5370050

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

https://github.com/golang/go/commit/be8025604e1175ef3e0718ca70d5ba38c928b976

元コミット内容

runtime: fix freebsd build

変更の背景

このコミットは、Go言語のランタイムがFreeBSD上で正しくビルドできない問題を修正するために行われました。具体的には、FreeBSD環境におけるtimespec構造体のフィールド名が、Goランタイムのコード内で誤って記述されていたことが原因です。

Go言語は、異なるオペレーティングシステム(OS)やアーキテクチャに対応するために、OS固有のシステムコールやデータ構造を扱う部分をランタイムに含んでいます。FreeBSDはUnix系のOSであり、時間に関する情報を扱う際にtimespecという標準的な構造体を使用します。この構造体のフィールド名がGoのコードとFreeBSDの実際の定義で一致していなかったため、ビルドエラーが発生していました。

この修正は、Go言語がFreeBSD環境で安定して動作するための重要なステップであり、OS固有の差異を吸収し、クロスプラットフォーム対応を強化するGoの設計思想に沿ったものです。

前提知識の解説

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理する低レベルのコンポーネントです。これには、ガベージコレクション、スケジューラ(ゴルーチンの管理)、メモリ割り当て、システムコールインターフェースなどが含まれます。Goプログラムは、OSのネイティブスレッド上でゴルーチンを多重化して実行するため、ランタイムはOSとの密接な連携を必要とします。OS固有の機能(ファイルI/O、ネットワーク、時間管理など)を利用する際には、ランタイムがOSのシステムコールを呼び出します。

FreeBSD

FreeBSDは、UNIXをベースとしたオープンソースのオペレーティングシステムです。高性能、安定性、セキュリティに優れており、サーバー、組み込みシステム、デスクトップなど幅広い用途で利用されています。Go言語は、Linux、macOS、Windowsなどと同様に、FreeBSDも公式にサポートしているOSの一つです。

timespec 構造体

timespecは、POSIX標準で定義されている時間値を表現するための構造体です。秒とナノ秒の精度で時間を保持します。多くのUnix系OS(Linux, FreeBSD, macOSなど)で、システムコールやライブラリ関数が時間情報を渡す際にこの構造体を使用します。

一般的なtimespec構造体の定義は以下のようになります(C言語の例):

struct timespec {
    time_t tv_sec;  /* 秒 (seconds) */
    long   tv_nsec; /* ナノ秒 (nanoseconds) */
};

ここで、tv_secは秒を表し、tv_nsecはナノ秒を表します。GoランタイムがFreeBSDのシステムコールを呼び出す際に、このtimespec構造体を使って時間情報を渡す必要がありましたが、フィールド名が誤っていたために問題が発生しました。

futexsleep (または futex)

futex (Fast Userspace muTex) は、Linuxカーネルが提供する同期プリミティブです。ユーザー空間のプログラムが、カーネルの介入を最小限に抑えつつ、効率的に同期処理(ミューテックス、セマフォなど)を行うためのメカニズムを提供します。Goランタイムでは、ゴルーチンのスケジューリングや同期処理において、OSが提供する低レベルの同期メカニズム(Linuxではfutex、FreeBSDでは類似のメカニズム)を利用することがあります。

このコミットで修正されているruntime·futexsleep関数は、GoランタイムがFreeBSD上でスレッドをスリープさせる際に、timespec構造体を用いてタイムアウト時間を指定するために使用される内部関数であると推測されます。

技術的詳細

このコミットの技術的な問題は、GoランタイムのFreeBSD固有のコード(src/pkg/runtime/freebsd/thread.c)において、timespec構造体のフィールド名が誤って参照されていた点にあります。

元のコードでは、timespec構造体の秒とナノ秒のフィールドをそれぞれts.sects.nsecとしてアクセスしていました。しかし、FreeBSDの標準的なtimespec構造体では、これらのフィールドはtv_sectv_nsecという名前で定義されています。

// 変更前 (誤り)
ts.sec = ns / 1000000000LL;
ts.nsec = ns % 1000000000LL;

// 変更後 (正しい)
ts.tv_sec = ns / 1000000000LL;
ts.tv_nsec = ns % 1000000000LL;

このフィールド名の不一致により、コンパイル時に「構造体にそのようなメンバーがない」といったエラーが発生し、FreeBSD上でのGoランタイムのビルドが失敗していました。

修正は非常にシンプルで、誤ったフィールド名を正しいtv_sectv_nsecに置き換えることで、FreeBSDのtimespec構造体の定義とGoランタイムのコードが一致し、ビルドが成功するようになりました。これは、OS固有のAPIやデータ構造を扱う際の、正確なインターフェース定義の重要性を示す典型的な例です。

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

diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c
index 4a52a83570..48532f6afc 100644
--- a/src/pkg/runtime/freebsd/thread.c
+++ b/src/pkg/runtime/freebsd/thread.c
@@ -21,8 +21,8 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
 	if(ns < 0)
 		tsp = nil;
 	else {
-\t\tts.sec = ns / 1000000000LL;
-\t\tts.nsec = ns % 1000000000LL;
+\t\tts.tv_sec = ns / 1000000000LL;
+\t\tts.tv_nsec = ns % 1000000000LL;
 		tsp = &ts;
 	}
 

コアとなるコードの解説

変更されたファイルは src/pkg/runtime/freebsd/thread.c です。これはGoランタイムのFreeBSD固有のスレッド関連の処理を記述しているC言語のファイルです。

変更箇所は runtime·futexsleep 関数内にあります。この関数は、指定された時間(ns、ナノ秒単位)だけスレッドをスリープさせるためのものです。スリープ時間をOSのシステムコールに渡すために、timespec構造体(ここではtsという変数名)を使用しています。

  • - ts.sec = ns / 1000000000LL;:
    • 変更前の行です。ns(ナノ秒)を10億で割ることで秒に変換し、ts.secというフィールドに代入しようとしていました。しかし、FreeBSDのtimespec構造体にはsecというフィールドは存在しません。
  • - ts.nsec = ns % 1000000000LL;:
    • 変更前の行です。nsを10億で割った余りを計算することでナノ秒部分を取得し、ts.nsecというフィールドに代入しようとしていました。同様に、nsecというフィールドも存在しません。
  • + ts.tv_sec = ns / 1000000000LL;:
    • 変更後の行です。ts.sects.tv_secに修正されました。tv_secはFreeBSDのtimespec構造体における秒を表す正しいフィールド名です。
  • + ts.tv_nsec = ns % 1000000000LL;:
    • 変更後の行です。ts.nsects.tv_nsecに修正されました。tv_nsecはFreeBSDのtimespec構造体におけるナノ秒を表す正しいフィールド名です。

この修正により、GoランタイムはFreeBSDのシステムコールに対して正しいtimespec構造体の形式で時間情報を渡せるようになり、FreeBSD上でのビルドエラーが解消されました。

関連リンク

参考にした情報源リンク