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

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

このコミットは、Go言語のビルドシステムにおいて、特定のビルド環境("thresher"と呼ばれる環境で、古いglibcを使用している)で発生していたビルドエラーを修正するものです。具体的には、Linuxカーネルには存在するものの、古いglibcのヘッダーファイルには定義されていなかったシステムコール関連の定数(WSTOPPEDPTRACE_SETOPTIONSなど)を、条件付きコンパイル(#ifndef)を用いて明示的に定義することで、ビルドが成功するようにしています。

コミット

commit 7fd04676adb915d58a78d5522691d736fedf04bb
Author: Russ Cox <rsc@golang.org>
Date:   Thu Feb 5 13:00:12 2009 -0800

    fix build on thresher - missing constants
    
    TBR=r
    OCL=24439
    CL=24439

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

https://github.com/golang/go/commit/7fd04676adb915d58a78d5522691d736fedf04bb

元コミット内容

fix build on thresher - missing constants

TBR=r
OCL=24439
CL=24439

変更の背景

このコミットの背景には、Go言語の初期開発段階における特定のビルド環境の制約があります。コミットメッセージに「fix build on thresher - missing constants」とあるように、「thresher」という名前のビルドマシンまたは環境でGoのビルドが失敗していました。

失敗の原因は、src/libmach_amd64/linux.cというファイルが依存する一部の定数(WSTOPPEDPTRACE_SETOPTIONSなど)が、その環境で使用されていたcrosstoolコンパイラがリンクする古いglibc(GNU C Library)のヘッダーファイルに定義されていなかったためです。

これらの定数は、Linuxカーネルのバージョン2.6.0以降では既に存在していましたが、glibcのバージョンによっては、その定義がヘッダーファイルに反映されていない場合がありました。Goのコードベースは、これらの定数が存在することを前提としていたため、古いglibc環境ではコンパイルエラーが発生していました。

このコミットは、特定のビルド環境における互換性の問題を解決し、Goのビルドプロセスがより広範な環境で安定して動作するようにするための修正です。

前提知識の解説

glibc (GNU C Library)

glibcは、GNUプロジェクトによって開発されたC標準ライブラリの実装です。Linuxシステムにおいて、アプリケーションがオペレーティングシステムの機能(ファイルI/O、メモリ管理、プロセス制御、ネットワーク通信など)を利用するための標準的なインターフェースを提供します。C言語で書かれたプログラムは、glibcが提供する関数を呼び出すことで、これらのシステム機能にアクセスします。

glibcは、Linuxカーネルが提供するシステムコールを抽象化し、より使いやすいAPIとして開発者に提供します。そのため、カーネルの新しい機能や定数が導入された場合、それに対応するglibcのバージョンがリリースされ、ヘッダーファイルに新しい定義が追加されるのが一般的です。古いglibcを使用している場合、新しいカーネル機能に対応する定数がヘッダーファイルに存在しないことがあります。

Linux Kernel

Linuxカーネルは、Linuxオペレーティングシステムの中心部分であり、ハードウェアとソフトウェアの間の仲介役を務めます。プロセスの管理、メモリの割り当て、デバイスの制御、ファイルシステムの操作など、システムの中核的な機能を提供します。

カーネルは、システムコールと呼ばれるインターフェースを通じて、ユーザー空間のプログラムにサービスを提供します。ptracewaitpidのようなシステムコールは、カーネルによって実装され、その動作を制御するための様々な定数(オプションやイベントタイプなど)がカーネル内部で定義されています。これらの定数は、通常、対応するglibcのヘッダーファイルを通じてユーザー空間のプログラムに公開されます。

PTRACE (Process Trace)

ptraceは、Linuxにおけるシステムコールの一つで、プロセスをトレース(追跡)するための機能を提供します。主にデバッガやシステムコールトレーサのようなツールが、他のプロセスの実行を監視したり、その状態を変更したりするために使用します。

ptraceシステムコールは、様々な「リクエスト」を受け付け、それに応じて異なる動作を実行します。例えば、プロセスのレジスタを読み書きしたり、メモリを検査したり、特定のイベント(子プロセスの生成、プログラムの実行、終了など)が発生したときにトレース対象プロセスを停止させたりすることができます。

このコミットで追加されたPTRACE_SETOPTIONSPTRACE_O_TRACE*PTRACE_EVENT_*といった定数は、ptraceの高度な機能、特に特定のシステムイベントのトレースを有効にするためのオプションや、発生したイベントの種類を示すコードに関連しています。

WSTOPPED, WCONTINUED, WIFCONTINUED

これらは、waitpidシステムコール(または関連するwait関数群)と組み合わせて使用されるマクロや定数です。waitpidは、子プロセスの状態変化(終了、停止、再開など)を待機し、その状態情報を取得するために使用されます。

  • WSTOPPED: 子プロセスがシグナルによって停止したことを示す定数です。
  • WCONTINUED: 停止していた子プロセスがSIGCONTシグナルによって再開されたことを示す定数です。
  • WIFCONTINUED(x): waitpidが返したステータス値xが、子プロセスが再開されたことを示している場合に真を返すマクロです。

これらの定数は、プロセス間通信やプロセス管理において、子プロセスのライフサイクルを正確に把握するために不可欠です。

Crosstool

crosstoolは、クロスコンパイル環境を構築するためのツールセットです。クロスコンパイルとは、あるアーキテクチャ(例: x86)上で動作するコンパイラを使って、別のアーキテクチャ(例: ARM)や異なるOS向けに実行可能ファイルを生成することです。

この文脈では、「thresher」環境でGoをビルドするために、おそらく特定のターゲットアーキテクチャ(amd64)とOS(linux)の組み合わせに対応するcrosstoolコンパイラが使用されていたことを示唆しています。古いcrosstoolは、古いバージョンのglibcとリンクされていた可能性があり、それが定数不足の原因となりました。

#ifndef ディレクティブ

C/C++言語におけるプリプロセッサディレクティブの一つで、「もし定義されていなければ」という意味を持ちます。これは、ヘッダーファイルが複数回インクルードされた場合に、同じマクロや定数が重複して定義されるのを防ぐためによく使用されます(インクルードガード)。

このコミットでは、#ifndefを使って、もし特定の定数(例: WSTOPPED)がまだ定義されていなければ、その定数を定義するという形で使用されています。これにより、新しいglibcが既にこれらの定数を定義している環境では、重複定義によるエラーを回避し、古いglibc環境では不足している定数を補うことができます。

技術的詳細

このコミットは、src/libmach_amd64/linux.cファイルに対して行われた修正であり、Go言語のランタイムやデバッグツールがLinuxのAMD64アーキテクチャ上で正しく動作するために必要な、低レベルなシステム定数を追加しています。

具体的に追加された定数は以下の通りです。

waitpid関連の定数

#ifndef WSTOPPED
#define WSTOPPED 2
#define WCONTINUED 8
#define WIFCONTINUED(x) ((x) == 0xffff)
#endif
  • WSTOPPED (値: 2): 子プロセスが停止したことを示すステータス値。
  • WCONTINUED (値: 8): 停止していた子プロセスが再開されたことを示すステータス値。
  • WIFCONTINUED(x): waitpidから返されるステータス値x0xffffと等しい場合に、子プロセスが再開されたことを示すマクロ。この0xffffという値は、LinuxカーネルがWCONTINUEDイベントを通知するために使用する特別な値です。

これらの定数は、waitpidシステムコールが返す子プロセスの状態を解釈するために不可欠です。古いglibcのヘッダーにはこれらの定義がなかったため、Goのコードが子プロセスの状態を正しく処理できませんでした。

ptrace関連の定数

#ifndef PTRACE_SETOPTIONS
#define PTRACE_SETOPTIONS 0x4200
#define PTRACE_GETEVENTMSG 0x4201
#define PTRACE_O_TRACEFORK 0x2
#define PTRACE_O_TRACEVFORK 0x4
#define PTRACE_O_TRACECLONE 0x8
#define PTRACE_O_TRACEEXEC 0x10
#define PTRACE_O_TRACEVFORKDONE 0x20
#define PTRACE_O_TRACEEXIT 0x40
#define PTRACE_EVENT_FORK 0x1
#define PTRACE_EVENT_VFORK 0x2
#define PTRACE_EVENT_CLONE 0x3
#define PTRACE_EVENT_EXEC 0x4
#define PTRACE_EVENT_VFORK_DONE 0x5
#define PTRACE_EVENT_EXIT 0x6
#endif
  • PTRACE_SETOPTIONS (値: 0x4200): ptraceシステムコールに渡すリクエストの一つで、トレースオプションを設定するために使用されます。これにより、トレーサーは特定のイベント(fork、execなど)が発生したときに通知を受け取ることができます。
  • PTRACE_GETEVENTMSG (値: 0x4201): ptraceイベントが発生した際に、そのイベントに関連する追加情報(例えば、新しいプロセスのPIDなど)を取得するために使用されるリクエストです。
  • PTRACE_O_TRACE* オプション: これらはPTRACE_SETOPTIONSと共に使用され、どの種類のイベントをトレースするかを指定します。
    • PTRACE_O_TRACEFORK (0x2): fork()システムコールによる子プロセスの生成をトレース。
    • PTRACE_O_TRACEVFORK (0x4): vfork()システムコールによる子プロセスの生成をトレース。
    • PTRACE_O_TRACECLONE (0x8): clone()システムコールによるスレッド/プロセスの生成をトレース。
    • PTRACE_O_TRACEEXEC (0x10): execve()などのexecファミリーシステムコールによる新しいプログラムの実行をトレース。
    • PTRACE_O_TRACEVFORKDONE (0x20): vfork()で生成された子プロセスがexecまたはexitを完了したことをトレース。
    • PTRACE_O_TRACEEXIT (0x40): プロセスが終了する際にトレース。
  • PTRACE_EVENT_* イベント: これらは、ptraceイベントが発生した際に、トレーサーに通知されるイベントの種類を示すコードです。
    • PTRACE_EVENT_FORK (0x1)
    • PTRACE_EVENT_VFORK (0x2)
    • PTRACE_EVENT_CLONE (0x3)
    • PTRACE_EVENT_EXEC (0x4)
    • PTRACE_EVENT_VFORK_DONE (0x5)
    • PTRACE_EVENT_EXIT (0x6)

これらのptrace関連の定数は、Goのデバッガやプロファイラ、あるいはランタイムがプロセスを管理・監視するためにptraceシステムコールを利用する際に必要となります。古いglibcではこれらの高度なptrace機能に対応する定数が不足していたため、Goのビルドが失敗していました。

この修正は、これらの定数を#ifndefガードで囲んで定義することで、古いglibc環境でもGoが正しくビルドされ、ptrace関連の機能が利用できるようにしています。同時に、新しいglibc環境では既存の定義と衝突しないように配慮されています。

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

--- a/src/libmach_amd64/linux.c
+++ b/src/libmach_amd64/linux.c
@@ -41,6 +41,31 @@
 #include <ureg_amd64.h>\n #undef waitpid\n \n+// The old glibc used with crosstool compilers on thresher\n+// doesn\'t know these numbers, but the Linux kernel\n+// had them as far back as 2.6.0.\n+#ifndef WSTOPPED\n+#define WSTOPPED 2\n+#define WCONTINUED 8\n+#define WIFCONTINUED(x) ((x) == 0xffff)\n+#endif\n+#ifndef PTRACE_SETOPTIONS\n+#define PTRACE_SETOPTIONS 0x4200\n+#define PTRACE_GETEVENTMSG 0x4201\n+#define PTRACE_O_TRACEFORK 0x2\n+#define PTRACE_O_TRACEVFORK 0x4\n+#define PTRACE_O_TRACECLONE 0x8\n+#define PTRACE_O_TRACEEXEC 0x10\n+#define PTRACE_O_TRACEVFORKDONE 0x20\n+#define PTRACE_O_TRACEEXIT 0x40\n+#define PTRACE_EVENT_FORK 0x1\n+#define PTRACE_EVENT_VFORK 0x2\n+#define PTRACE_EVENT_CLONE 0x3\n+#define PTRACE_EVENT_EXEC 0x4\n+#define PTRACE_EVENT_VFORK_DONE 0x5\n+#define PTRACE_EVENT_EXIT 0x6\n+#endif\n+\n typedef struct Ureg Ureg;\n \n static Maprw ptracesegrw;\n```

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

変更は`src/libmach_amd64/linux.c`ファイルに集中しており、主に2つの`#ifndef ... #endif`ブロックが追加されています。

1.  **`WSTOPPED`, `WCONTINUED`, `WIFCONTINUED` の定義**:
    最初のブロックでは、`waitpid`システムコールに関連する定数とマクロが定義されています。
    `#ifndef WSTOPPED` は、もし `WSTOPPED` がまだ定義されていなければ、以下の定義を行うという意味です。これは、古い`glibc`のヘッダーファイルにこれらの定数が含まれていない場合に備えたものです。
    *   `WSTOPPED` は、子プロセスが停止したことを示すステータスコードです。
    *   `WCONTINUED` は、停止していた子プロセスが再開されたことを示すステータスコードです。
    *   `WIFCONTINUED(x)` は、`waitpid`が返したステータス値`x`が子プロセスが再開されたことを示しているかを確認するためのマクロです。`0xffff`という値は、Linuxカーネルが`WCONTINUED`イベントを通知するために使用する特別な値です。

2.  **`PTRACE_SETOPTIONS` および関連する`ptrace`定数の定義**:
    2番目のブロックでは、`ptrace`システムコールに関連する多数の定数が定義されています。
    `#ifndef PTRACE_SETOPTIONS` は、もし `PTRACE_SETOPTIONS` がまだ定義されていなければ、以下の定義を行うという意味です。これも同様に、古い`glibc`のヘッダーファイルにこれらの定数が含まれていない場合に備えたものです。
    *   `PTRACE_SETOPTIONS` は、`ptrace`システムコールに渡すリクエストの一つで、トレースオプションを設定するために使用されます。
    *   `PTRACE_GETEVENTMSG` は、`ptrace`イベントに関連する追加情報を取得するためのリクエストです。
    *   `PTRACE_O_TRACE*` で始まる定数は、`PTRACE_SETOPTIONS`と共に使用され、`ptrace`がどの種類のイベント(`fork`、`exec`、`clone`など)をトレースするかを指定します。
    *   `PTRACE_EVENT_*` で始まる定数は、`ptrace`イベントが発生した際に、トレーサーに通知されるイベントの種類を示すコードです。

これらの変更の目的は、Goのビルドが依存するこれらのシステム定数が、古い`glibc`を使用する特定のビルド環境("thresher")で不足していた問題を解決することです。`#ifndef`ガードを使用することで、これらの定数が既に新しい`glibc`によって定義されている環境では、重複定義によるコンパイルエラーを回避し、互換性を保っています。

この修正は、GoのランタイムがLinux上でプロセス管理やデバッグ機能(例えば、Goのデバッガである`delve`など)を実装する際に、これらの低レベルなシステムコールインターフェースを正しく利用できるようにするために不可欠です。

## 関連リンク

*   `ptrace` man page: [https://man7.org/linux/man-pages/man2/ptrace.2.html](https://man7.org/linux/man-pages/man2/ptrace.2.html)
*   `waitpid` man page: [https://man7.org/linux/man-pages/man2/waitpid.2.html](https://man7.org/linux/man-pages/man2/waitpid.2.html)
*   GNU C Library (glibc) 公式サイト: [https://www.gnu.org/software/libc/](https://www.gnu.org/software/libc/)

## 参考にした情報源リンク

*   Linux kernel source code (for constant values and definitions)
*   `glibc` source code (for header file definitions)
*   Stack Overflow and other programming forums discussing `ptrace` and `waitpid` constants.
*   Go project's issue tracker and commit history (for context on "thresher" and early build issues).
*   `crosstool-ng` documentation (for understanding crosstool chains).
*   C Preprocessor directives (`#ifndef`, `#define`) documentation.