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

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

このコミットは、Go言語のmisc/cgo/testsoディレクトリにあるテストコードcgoso_c.ccgoso_unix.goに対する変更です。具体的には、Darwin (macOS) および OpenBSD 環境において、スレッドローカルストレージ (TLS) 変数の使用を避けるように修正されています。これにより、これらのプラットフォームでのビルドエラーが解消されました。

コミット

commit bcf3d55ed99b7b7e689e05a8333ba89d337c0cad
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Sun Feb 23 20:37:43 2014 -0500

    misc/cgo/testso: don't use TLS variables on Darwin and OpenBSD.
    Fix build for 10.6 Darwin builders and OpenBSD builers.
    
    LGTM=jsing
    R=golang-codereviews, dave, jsing
    CC=golang-codereviews
    https://golang.org/cl/67710043

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

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

元コミット内容

misc/cgo/testso: don't use TLS variables on Darwin and OpenBSD.
Fix build for 10.6 Darwin builders and OpenBSD builers.

LGTM=jsing
R=golang-codereviews, dave, jsing
CC=golang-codereviews
https://golang.org/cl/67710043

変更の背景

このコミットの背景には、Go言語のCgoテストスイートが特定のオペレーティングシステム(特にDarwin 10.6 (Snow Leopard) および OpenBSD)でビルドに失敗するという問題がありました。失敗の原因は、テストコード内で使用されていたスレッドローカルストレージ(TLS)変数が、これらの環境の特定のバージョンで適切にサポートされていなかったことにあります。

Go言語は、Cgoを通じてC言語のコードと連携することができます。Cgoは、GoプログラムからCライブラリを呼び出したり、CライブラリからGo関数を呼び出したりする機能を提供します。この機能のテストには、共有ライブラリ(.soファイル)をCgo経由でロードし、その中の関数を呼び出すテストケースが含まれていました。

問題のmisc/cgo/testsoは、共有ライブラリ(cgoso_c.c)とGoコード(cgoso_unix.go)を連携させるテストです。cgoso_c.c内で__threadキーワードを用いてTLS変数が宣言されていましたが、Darwin 10.6やOpenBSDの古いバージョンでは、コンパイラやリンカがこのTLS機能を完全にサポートしていなかったり、異なる実装を持っていたりすることが原因で、ビルドエラーが発生していました。

Goプロジェクトは、様々なプラットフォームでの互換性を維持することを重視しており、特定の環境でのビルド失敗は許容されません。そのため、これらの環境でのビルドを修正するために、TLS変数の使用を条件付きで無効にする変更が必要となりました。

前提知識の解説

Cgo

Cgoは、GoプログラムがC言語のコードを呼び出したり、その逆を行ったりするためのGoの機能です。Goのビルドシステムに統合されており、GoとCの間のデータ変換や関数呼び出しのメカニズムを提供します。Cgoを使用することで、既存のCライブラリをGoプロジェクトに組み込んだり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。

スレッドローカルストレージ (TLS)

スレッドローカルストレージ(Thread-Local Storage, TLS)は、マルチスレッドプログラミングにおいて、各スレッドが自分専用のデータコピーを持つことを可能にするメカニズムです。通常、グローバル変数や静的変数はプロセス内のすべてのスレッドで共有されますが、TLS変数を使用すると、同じ変数名であっても各スレッドが独立した値を保持できます。

C/C++では、__thread (GCC/Clang) や __declspec(thread) (MSVC) といったキーワードを用いてTLS変数を宣言します。これにより、コンパイラとリンカは、その変数がスレッドごとに異なるメモリ領域に配置されるように処理します。

TLSは、以下のようなシナリオで有用です。

  • スレッドセーフティの向上: 共有データへのアクセス競合を避けるために、各スレッドが独自のデータを持つことでロックの必要性を減らします。
  • コンテキスト情報の保持: 各スレッドが独自のコンテキスト情報(例: エラーコード、ユーザーセッション情報)を保持するのに便利です。

TLSの実装とOS依存性

TLSの実装は、オペレーティングシステム(OS)とコンパイラに大きく依存します。

  • Linux: 通常、ELF (Executable and Linkable Format) のTLSセクションと、__threadキーワードをサポートするGCC/Clangコンパイラによって実現されます。
  • Windows: __declspec(thread)キーワードと、PE (Portable Executable) フォーマットのTLSディレクトリによって実現されます。
  • macOS (Darwin): macOSのTLSサポートは、バージョンによって異なります。古いバージョン(特に10.6 Snow Leopard以前)では、__threadキーワードのサポートが不完全であったり、リンカがTLSセクションを適切に処理できなかったりする場合があります。macOSでは、通常、pthread_getspecific/pthread_setspecificのようなPOSIXスレッドAPIを用いたTLSが推奨されます。__threadはGCC拡張であり、macOSのシステムライブラリやリンカが常に期待通りに動作するとは限りません。
  • OpenBSD: OpenBSDもまた、TLSの実装が他のUnix系OSと異なる場合があります。特に古いバージョンでは、__threadキーワードのサポートが限定的であったり、特定のリンカの挙動が原因で問題が発生することがあります。

このコミットの時点(2014年)では、Darwin 10.6やOpenBSDの特定の環境において、__threadキーワードによるTLS変数の使用がビルドエラーを引き起こす可能性がありました。これは、これらのOSのリンカやランタイムローダーが、TLS変数を適切に解決または初期化できないことに起因します。

Goのビルドタグ (+build ディレクティブ)

Goのソースファイルには、+buildディレクティブという特別なコメント行を含めることができます。これは、そのファイルが特定のビルド条件(OS、アーキテクチャ、カスタムタグなど)が満たされた場合にのみコンパイルされるように指定するものです。

例:

  • // +build linux:Linuxでのみコンパイル
  • // +build darwin,amd64:macOSかつAMD64アーキテクチャでのみコンパイル
  • // +build !windows:Windows以外でコンパイル

このコミットでは、+buildディレクティブがTLS変数の使用を制御するために利用されています。

技術的詳細

このコミットは、Darwin 10.6およびOpenBSD環境でのビルド問題を解決するために、条件付きコンパイルを利用してTLS変数の宣言を無効化しています。

具体的には、Cgoテスト用のCソースファイルmisc/cgo/testso/cgoso_c.cにおいて、__thread int tlsvar = 12345;というTLS変数の宣言が、#if !defined(__OpenBSD__) && !defined(__APPLE__)というプリプロセッサディレクティブで囲まれました。

  • __OpenBSD__:OpenBSD環境で定義されるマクロ。
  • __APPLE__:Apple(macOS/iOSなど)環境で定義されるマクロ。

この条件は、「OpenBSDでもApple環境でもない場合」にtlsvarを宣言するという意味になります。つまり、OpenBSDとmacOSではtlsvarが宣言されなくなり、TLS変数の使用に起因するビルドエラーが回避されます。

また、Goソースファイルmisc/cgo/testso/cgoso_unix.goのビルドタグも変更されました。 変更前: // +build darwin dragonfly freebsd linux netbsd 変更後: // +build dragonfly freebsd linux netbsd

これにより、cgoso_unix.goはDarwin環境ではコンパイルされなくなりました。これは、cgoso_c.cの変更と合わせて、Darwin環境でのTLS関連の問題を完全に回避するための措置と考えられます。cgoso_unix.goがTLS変数に依存するCgo呼び出しを含んでいた場合、この変更によってその依存関係が解消されます。

この修正は、Goのビルドシステムが、特定のプラットフォームの特性(この場合はTLSサポートの有無や実装の違い)に合わせてコードのコンパイルを調整する能力を示しています。

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

misc/cgo/testso/cgoso_c.c

--- a/misc/cgo/testso/cgoso_c.c
+++ b/misc/cgo/testso/cgoso_c.c
@@ -17,6 +17,10 @@ __declspec(dllexport) void sofunc(void);\n #else\n extern void goCallback(void);\n void setCallback(void *f) { (void)f; }\n+#endif\n+\n+// OpenBSD and older Darwin lack TLS support
+#if !defined(__OpenBSD__) && !defined(__APPLE__)\n __thread int tlsvar = 12345;\n #endif
 \n```

### `misc/cgo/testso/cgoso_unix.go`

```diff
--- a/misc/cgo/testso/cgoso_unix.go
+++ b/misc/cgo/testso/cgoso_unix.go
@@ -2,7 +2,7 @@\n // Use of this source code is governed by a BSD-style\n // license that can be found in the LICENSE file.\n \n-// +build darwin dragonfly freebsd linux netbsd\n+// +build dragonfly freebsd linux netbsd\n \n package cgosotest\n \n```

## コアとなるコードの解説

### `misc/cgo/testso/cgoso_c.c`の変更

このCファイルは、GoのCgoテストで使用される共有ライブラリの一部です。
元のコードでは、`__thread int tlsvar = 12345;`という行でスレッドローカル変数`tlsvar`が宣言され、`12345`で初期化されていました。
変更後、この宣言は以下のプリプロセッサディレクティブで囲まれました。

```c
// OpenBSD and older Darwin lack TLS support
#if !defined(__OpenBSD__) && !defined(__APPLE__)
__thread int tlsvar = 12345;
#endif

この#ifディレクティブは、コンパイル時に__OpenBSD__マクロと__APPLE__マクロのどちらも定義されていない場合にのみ、__thread int tlsvar = 12345;の行がコンパイルされるように指示します。

  • __OpenBSD__はOpenBSDシステムで定義されます。
  • __APPLE__はmacOS(旧称Darwin)システムで定義されます。

したがって、この変更により、OpenBSDおよびmacOS環境ではtlsvar変数が宣言されなくなり、これらのシステムでTLSサポートが不完全であることに起因するビルドエラーが回避されます。コメント// OpenBSD and older Darwin lack TLS supportは、この変更の理由を明確に示しています。

misc/cgo/testso/cgoso_unix.goの変更

このGoファイルは、Cgoテストの一部であり、特定のUnix系OS向けにビルドされることを意図していました。 元の+buildディレクティブは以下の通りでした。

// +build darwin dragonfly freebsd linux netbsd

これは、このGoファイルがDarwin、DragonFly BSD、FreeBSD、Linux、NetBSDの各OSでコンパイルされることを意味します。 変更後、darwinがリストから削除されました。

// +build dragonfly freebsd linux netbsd

これにより、このcgoso_unix.goファイルはDarwin環境ではコンパイルされなくなります。このGoファイルがcgoso_c.c内のTLS変数に依存するCgo呼び出しを含んでいた場合、この変更によってDarwin環境でのTLS関連の問題が完全に回避されます。これは、Cコード側の変更と連携して、特定のプラットフォームでのビルドの健全性を確保するための措置です。

これらの変更は、Goのクロスプラットフォーム対応において、各OSの特定の特性(この場合はTLSの実装状況)を考慮し、必要に応じてコードのコンパイルを条件付きで行うことの重要性を示しています。

関連リンク

参考にした情報源リンク

  • Go CL 67710043: https://golang.org/cl/67710043 (コミットメッセージに記載されているGoのコードレビューリンク)
  • GCC __thread keyword: https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html
  • Apple Developer Documentation (TLSに関する一般的な情報): https://developer.apple.com/documentation/ (具体的なTLSの制約に関する直接的なドキュメントは見つけにくいが、一般的な開発ガイドラインから推測可能)
  • OpenBSD man pages (TLSに関する一般的な情報): https://man.openbsd.org/ (具体的なTLSの制約に関する直接的なドキュメントは見つけにくいが、一般的な開発ガイドラインから推測可能)
  • Stack Overflowや技術ブログの議論(__threadとmacOS/OpenBSDの互換性に関する情報)
    • 例: "gcc __thread on mac os x" や "openbsd thread local storage" などの検索クエリで関連情報が見つかることがあります。
    • これらの情報は、特定のOSバージョンでのコンパイラやリンカの挙動に関するコミュニティの知見として参照しました。I have generated the detailed technical explanation in Markdown format, following all the specified instructions and chapter structure. The output is sent to standard output as requested.