[インデックス 1875] ファイルの概要
このコミットは、GoランタイムにおけるLinuxシステムコール関連の定義(defs.h
)の生成方法を、手動定義から自動生成へと移行するものです。これにより、Linuxカーネルの構造体定義との整合性を高め、将来的なメンテナンス性を向上させています。
コミット
commit 209865be7cbb95e745c1599507d5bde16c9f0b92
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 24 15:04:18 2009 -0700
convert Linux to auto-generated defs.h
TBR=r
OCL=26686
CL=26688
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/209865be7cbb95e745c1599507d5bde16c9f0b92
元コミット内容
Linux向けのdefs.h
ファイルを自動生成されるものに変換する。
変更の背景
Goランタイムは、OSの低レベルな機能(シグナルハンドリング、スレッド管理、メモリマッピングなど)と直接やり取りするため、OS固有の構造体や定数を正確に定義する必要があります。これまでは、src/runtime/linux/amd64/defs.h
のようなファイルでこれらの定義が手動で行われていました。
しかし、Linux環境では、glibc(GNU C Library)が提供するヘッダファイルと、Linuxカーネルが提供するヘッダファイルの間で、同じ構造体(例: struct sigaction
, struct timespec
)であっても定義が異なる場合があります。Goランタイムはカーネルと直接対話するため、カーネル側の正確な定義を使用する必要があります。手動でこれらの定義を管理することは、以下のような問題を引き起こします。
- メンテナンスの困難さ: カーネルのバージョンアップやアーキテクチャの変更に伴い、手動で定義を更新し続けるのは手間がかかり、エラーの温床となります。
- 定義の不一致: glibcとカーネルの定義の差異を常に意識し、Goランタイムがカーネルと期待通りに動作するように手動で調整するのは非常に複雑です。
- 移植性の問題: 異なるLinuxディストリビューションやカーネルバージョンでGoランタイムが正しく動作することを保証するためには、より堅牢な定義の仕組みが必要です。
このコミットは、godefs
というツールを導入し、C言語のヘッダファイルからGoの構造体定義を自動生成することで、これらの問題を解決しようとしています。これにより、Goランタイムは常にLinuxカーネルの最新かつ正確な構造体定義を使用できるようになります。
前提知識の解説
GoランタイムとOSの相互作用
Goプログラムは、Goランタイム(runtime
パッケージ)を介してOSと対話します。ランタイムは、ガベージコレクション、スケジューリング、システムコール、シグナルハンドリングなど、プログラムの実行に必要な低レベルな機能を提供します。これらの機能の多くはOS固有であり、OSが提供するシステムコールやデータ構造に依存します。
Linuxシステムコール
Linuxカーネルは、ユーザー空間のプログラムがハードウェアやカーネルの機能にアクセスするためのインターフェースとしてシステムコールを提供します。例えば、ファイル操作、プロセス管理、メモリ管理、シグナル処理などがシステムコールを通じて行われます。Goランタイムは、これらのシステムコールを直接呼び出すことで、OSの機能を利用します。
シグナルハンドリング
シグナルは、OSがプロセスに非同期的にイベントを通知するメカニズムです。例えば、Ctrl+Cによる割り込み(SIGINT)、セグメンテーション違反(SIGSEGV)、子プロセスの終了(SIGCHLD)などがあります。Goランタイムは、プログラムのクラッシュを捕捉したり、特定のイベントに応答したりするためにシグナルハンドリングを利用します。シグナルハンドリングには、sigaction
構造体(シグナルハンドラの登録)、siginfo_t
構造体(シグナルに関する詳細情報)、ucontext_t
構造体(シグナル発生時のプロセスのコンテキスト)などが関与します。
godefs
ツール
godefs
は、Go言語のツールチェーンの一部として開発されたユーティリティです。その主な目的は、C言語のヘッダファイルに定義されている構造体、定数、型などを解析し、それに対応するGo言語の定義(Goの構造体、定数、型エイリアス)を自動生成することです。
godefs
は、Cのソースコード(通常は特定のCヘッダファイルをインクルードし、必要な型に$
プレフィックスを付けてtypedef
するだけのシンプルなCファイル)を読み込み、その中で定義されている型や定数をGoの構文に変換します。これにより、GoプログラムがCのライブラリやOSのAPIと連携する際に、手動でGoの型定義を作成する手間を省き、定義の正確性を保証できます。
glibcとLinuxカーネルヘッダの差異
Linuxシステムでは、ユーザー空間のプログラムは通常glibcを介してシステムコールを呼び出します。glibcは、カーネルのシステムコールをラップし、より高レベルなAPIを提供します。しかし、glibcが提供するヘッダファイルと、Linuxカーネルが直接提供するヘッダファイル(通常は/usr/include/asm
や/usr/include/linux
以下にある)では、同じシステム構造体であっても、その定義(特にフィールドの順序やパディング)が異なる場合があります。
Goランタイムのようにカーネルと直接対話する低レベルなコードでは、glibcの定義ではなく、カーネルの正確な定義に準拠する必要があります。このコミットは、godefs
を使用してカーネルのヘッダから直接定義を生成することで、この問題を回避しています。
技術的詳細
このコミットの核心は、GoランタイムがLinuxシステムと対話するために必要なC言語の構造体や定数の定義を、手動から自動生成に切り替えることです。この自動生成プロセスには、godefs
ツールが使用されます。
-
godefs
の導入:src/runtime/linux/defs.c
とsrc/runtime/linux/defs1.c
という新しいCソースファイルが導入されました。これらのファイルは、godefs
ツールへの入力として機能します。- これらのCファイルは、Linuxカーネルのヘッダファイル(例:
<asm/signal.h>
,<asm/siginfo.h>
,<asm/mman.h>
,<ucontext.h>
) をインクルードし、Goランタイムが必要とする特定の構造体や定数に$
プレフィックスを付けてtypedef
またはenum
で定義しています。 godefs
は、これらのCファイルを解析し、$
プレフィックスが付いた型や定数をGo言語の対応する定義に変換します。例えば、$PROT_NONE
はPROT_NONE
というGoの定数に、$Timespec
はTimespec
というGoの構造体になります。defs.c
のコメントには、glibcとLinuxカーネルの定義の衝突について明記されており、Goランタイムがカーネル側の定義を必要としていることが示されています。defs1.c
は、ucontext.h
のような、より複雑な構造体を含むヘッダを処理するために分離されています。
-
defs.h
の自動生成:src/runtime/linux/amd64/defs.h
ファイルの内容が大幅に変更されました。以前は手動で定義されていた構造体や定数が削除され、MACHINE GENERATED - DO NOT EDIT.
というコメントと共に、godefs
によって生成された内容に置き換えられました。- 生成された
defs.h
には、Timespec
,Timeval
,Sigaction
,Siginfo
,Usigset
,Fpxreg
,Xmmreg
,Fpstate
,Sigaltstack
,Mcontext
,Ucontext
,Sigcontext
などの構造体と、PROT_NONE
,MAP_ANON
,SA_RESTART
などの定数が含まれています。これらの定義は、Linuxカーネルのヘッダファイルから直接抽出されたものであり、Goランタイムがカーネルと正確に連携するために不可欠です。
-
ランタイムコードの適応:
src/runtime/linux/signal.c
とsrc/runtime/linux/thread.c
の既存のコードが、新しい自動生成された型定義を使用するように変更されました。- 例えば、
signal.c
では、以前手動で定義されていたstruct _fpstate
,struct sigcontext
,struct ucontext
などが削除され、defs.h
で定義されたSigcontext
,Ucontext
などの型が直接使用されています。 - また、
signal.c
のdumpregs
関数(以前はprint_sigcontext
)やsighandler
関数も、新しい型定義に合わせて引数や内部のアクセス方法が変更されています。出力形式もsys·printhex
からprintf
に変更され、より標準的なデバッグ出力になっています。 src/runtime/linux/os.h
が新しく追加され、Linux固有のシステムコール(futex
,clone
,rt_sigaction
)の宣言が含まれるようになりました。これにより、これらのシステムコールがdefs.h
とは別の場所で管理され、コードのモジュール性が向上しています。
この変更により、GoランタイムはLinuxシステムとのインターフェースにおいて、より堅牢で正確な型定義を持つことができるようになりました。カーネルの変更に追従する手間が軽減され、異なるLinux環境での互換性も向上します。
コアとなるコードの変更箇所
src/runtime/linux/amd64/defs.h
- 手動で定義されていた
typedef
やstruct
定義(dev_t
,ino_t
,timespec
,timeval
,stat
など)が削除されました。 godefs
によって自動生成された新しい定義が追加されました。これには、PROT_NONE
などの定数、Timespec
,Timeval
,Sigaction
,Siginfo
,Usigset
,Fpxreg
,Xmmreg
,Fpstate
,Sigaltstack
,Mcontext
,Ucontext
,Sigcontext
などの構造体が含まれます。
src/runtime/linux/defs.c
(新規ファイル)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* Input to godefs
* godefs -f -m64 defs.c >amd64/defs.h
* godefs -f -m64 defs1.c >>amd64/defs.h
* godefs defs.c >386/defs.h
* godefs defs1.c >>386/defs.h
*/
// Linux glibc and Linux kernel define different and conflicting
// definitions for struct sigaction, struct timespec, etc.
// We want the kernel ones, which are in the asm/* headers.
// But then we'd get conflicts when we include the system
// headers for things like ucontext_t, so that happens in
// a separate file, defs1.c.
#include <asm/signal.h>
#include <asm/siginfo.h>
#include <asm/mman.h>
enum {
$PROT_NONE = PROT_NONE,
$PROT_READ = PROT_READ,
$PROT_WRITE = PROT_WRITE,
$PROT_EXEC = PROT_EXEC,
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
$SA_RESTORER = SA_RESTORER,
$SA_SIGINFO = SA_SIGINFO,
};
typedef struct timespec $Timespec;
typedef struct timeval $Timeval;
typedef struct sigaction $Sigaction;
typedef siginfo_t $Siginfo;
src/runtime/linux/defs1.c
(新規ファイル)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* Input to godefs
* godefs -f -m64 defs.c >amd64/defs.h
* godefs -f -m64 defs1.c >>amd64/defs.h
* godefs defs.c >386/defs.h
* godefs defs1.c >>386/defs.h
*/
#include <ucontext.h>
typedef __sigset_t $Usigset;
typedef struct _libc_fpxreg $Fpxreg;
typedef struct _libc_xmmreg $Xmmreg;
typedef struct _libc_fpstate $Fpstate;
typedef struct _fpxreg $Fpxreg1;
typedef struct _xmmreg $Xmmreg1;
typedef struct _fpstate $Fpstate1;
typedef struct sigaltstack $Sigaltstack;
typedef mcontext_t $Mcontext;
typedef ucontext_t $Ucontext;
typedef struct sigcontext $Sigcontext;
src/runtime/linux/os.h
(新規ファイル)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Linux-specific system calls
int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
int64 clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
void rt_sigaction(int64, struct Sigaction*, void*, uint64);
src/runtime/linux/signal.c
- 手動で定義されていた
_fpstate
,sigcontext
,sigaltstack
,ucontext
,siginfo
,sigaction
などの構造体定義が削除されました。 #include "os.h"
が追加されました。print_sigcontext
関数がdumpregs
にリネームされ、引数と内部のレジスタアクセスがSigcontext
型を使用するように変更されました。また、sys·printhex
からprintf
による出力に変更されました。sighandler
関数がSiginfo* info, void* context
を引数にとるように変更され、内部でUcontext
,Mcontext
,Sigcontext
型を使用するように修正されました。signalstack
関数がSigaltstack
型を使用するように変更されました。initsig
関数がSigaction
型を使用するように変更されました。
src/runtime/linux/thread.c
#include "os.h"
が追加されました。static struct timespec longtime
がstatic Timespec longtime
に変更されました。
コアとなるコードの解説
このコミットの主要な変更は、GoランタイムがLinuxシステムと対話するために必要な低レベルな型定義の管理方法を根本的に変えた点にあります。
-
godefs
入力ファイル (defs.c
,defs1.c
):- これらのCファイルは、GoランタイムがLinuxカーネルから取得する必要がある構造体や定数を定義するための「テンプレート」として機能します。
#include <asm/signal.h>
などのカーネルヘッダを直接インクルードすることで、glibcの定義ではなく、カーネルの正確な定義を参照しています。$PROT_NONE = PROT_NONE
やtypedef struct timespec $Timespec;
のような構文は、godefs
ツールに対する指示です。$
プレフィックスは、godefs
がこれらのCの定義をGoの対応する型や定数に変換すべきであることを示します。defs.c
とdefs1.c
に分割されているのは、ucontext.h
のような特定のヘッダが、他のヘッダとインクルード順序や定義の衝突を引き起こす可能性があるため、分離して処理することでgodefs
の実行を容易にするためです。
-
自動生成された
defs.h
:godefs
がdefs.c
とdefs1.c
を処理することで、src/runtime/linux/amd64/defs.h
が生成されます。このファイルは、GoランタイムがCgoなしでLinuxシステムコールを直接呼び出す際に使用する、Go言語の構造体と定数の定義を含んでいます。- 例えば、
struct Timespec
はGoのTimespec
構造体として定義され、int64 tv_sec; int64 tv_nsec;
といったフィールドがGoの型にマッピングされます。これにより、GoコードからLinuxのtimespec
構造体を安全かつ正確に操作できるようになります。 Sigaction
,Siginfo
,Ucontext
,Mcontext
,Sigcontext
といったシグナルハンドリングに関連する複雑な構造体も、カーネルの定義に基づいて正確にGoの構造体として表現されます。これは、シグナル発生時のレジスタ状態やスタック情報などを正確に読み取るために非常に重要です。
-
ランタイムコードの適応 (
signal.c
,thread.c
):- 以前は、これらのファイル内でLinuxのシステム構造体が手動で再定義されていました。これは、カーネルの定義と同期が取れていない場合、バグの原因となる可能性がありました。
- このコミットにより、手動定義が削除され、自動生成された
defs.h
で提供される型(例:Sigcontext
,Ucontext
)が直接使用されるようになりました。これにより、Goランタイムのコードは常にカーネルの最新かつ正確な定義に準拠するようになります。 dumpregs
関数がprintf
を使用するように変更されたのは、Goランタイムのデバッグ出力の標準化と、より柔軟なフォーマットを可能にするためと考えられます。
この一連の変更は、Goランタイムの低レベルなOSインターフェースの堅牢性とメンテナンス性を大幅に向上させます。手動での定義管理に伴うエラーのリスクを減らし、Goが様々なLinux環境でより安定して動作するための基盤を強化しています。
関連リンク
- Go言語の
syscall
パッケージのドキュメント(Goランタイムがシステムコールをどのように扱うか理解するのに役立ちます) godefs
ツールのソースコードや関連ドキュメント(Goプロジェクト内でどのように使用されているか)- Linuxカーネルのソースコード(特に
arch/x86/include/asm
やinclude/uapi/linux
以下のヘッダファイル)
参考にした情報源リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goのソースコードリポジトリ: https://github.com/golang/go
- Linuxカーネルのドキュメントやソースコード(特定の構造体定義の確認のため)
godefs
に関する情報(Goのツールチェーンの一部として)godefs
のソースコードはGoリポジトリ内のsrc/cmd/godefs
にあります。godefs
の基本的な使い方や目的については、Goの初期の設計に関する議論やドキュメントで触れられていることがあります。
(注: godefs
はGoの内部ツールであり、一般的なユーザー向けに詳細なドキュメントが公開されているわけではありません。その機能は主にGoランタイムや標準ライブラリのOS固有部分のビルドプロセスで使用されます。)
[インデックス 1875] ファイルの概要
このコミットは、GoランタイムにおけるLinuxシステムコール関連の定義(defs.h
)の生成方法を、手動定義から自動生成へと移行するものです。これにより、Linuxカーネルの構造体定義との整合性を高め、将来的なメンテナンス性を向上させています。
コミット
commit 209865be7cbb95e745c1599507d5bde16c9f0b92
Author: Russ Cox <rsc@golang.org>
Date: Tue Mar 24 15:04:18 2009 -0700
convert Linux to auto-generated defs.h
TBR=r
OCL=26686
CL=26688
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/209865be7cbb95e745c1599507d5bde16c9f0b92
元コミット内容
Linux向けのdefs.h
ファイルを自動生成されるものに変換する。
変更の背景
Goランタイムは、OSの低レベルな機能(シグナルハンドリング、スレッド管理、メモリマッピングなど)と直接やり取りするため、OS固有の構造体や定数を正確に定義する必要があります。これまでは、src/runtime/linux/amd64/defs.h
のようなファイルでこれらの定義が手動で行われていました。
しかし、Linux環境では、glibc(GNU C Library)が提供するヘッダファイルと、Linuxカーネルが提供するヘッダファイルの間で、同じ構造体(例: struct sigaction
, struct timespec
)であっても定義が異なる場合があります。Goランタイムはカーネルと直接対話するため、カーネル側の正確な定義を使用する必要があります。手動でこれらの定義を管理することは、以下のような問題を引き起こします。
- メンテナンスの困難さ: カーネルのバージョンアップやアーキテクチャの変更に伴い、手動で定義を更新し続けるのは手間がかかり、エラーの温床となります。
- 定義の不一致: glibcとカーネルの定義の差異を常に意識し、Goランタイムがカーネルと期待通りに動作するように手動で調整するのは非常に複雑です。
- 移植性の問題: 異なるLinuxディストリビューションやカーネルバージョンでGoランタイムが正しく動作することを保証するためには、より堅牢な定義の仕組みが必要です。
このコミットは、godefs
というツールを導入し、C言語のヘッダファイルからGoの構造体定義を自動生成することで、これらの問題を解決しようとしています。これにより、Goランタイムは常にLinuxカーネルの最新かつ正確な構造体定義を使用できるようになります。
前提知識の解説
GoランタイムとOSの相互作用
Goプログラムは、Goランタイム(runtime
パッケージ)を介してOSと対話します。ランタイムは、ガベージコレクション、スケジューリング、システムコール、シグナルハンドリングなど、プログラムの実行に必要な低レベルな機能を提供します。これらの機能の多くはOS固有であり、OSが提供するシステムコールやデータ構造に依存します。
Linuxシステムコール
Linuxカーネルは、ユーザー空間のプログラムがハードウェアやカーネルの機能にアクセスするためのインターフェースとしてシステムコールを提供します。例えば、ファイル操作、プロセス管理、メモリ管理、シグナル処理などがシステムコールを通じて行われます。Goランタイムは、これらのシステムコールを直接呼び出すことで、OSの機能を利用します。
シグナルハンドリング
シグナルは、OSがプロセスに非同期的にイベントを通知するメカニズムです。例えば、Ctrl+Cによる割り込み(SIGINT)、セグメンテーション違反(SIGSEGV)、子プロセスの終了(SIGCHLD)などがあります。Goランタイムは、プログラムのクラッシュを捕捉したり、特定のイベントに応答したりするためにシグナルハンドリングを利用します。シグナルハンドリングには、sigaction
構造体(シグナルハンドラの登録)、siginfo_t
構造体(シグナルに関する詳細情報)、ucontext_t
構造体(シグナル発生時のプロセスのコンテキスト)などが関与します。
godefs
ツール
godefs
は、Go言語のツールチェーンの一部として開発されたユーティリティです。その主な目的は、C言語のヘッダファイルに定義されている構造体、定数、型などを解析し、それに対応するGo言語の定義(Goの構造体、定数、型エイリアス)を自動生成することです。
godefs
は、Cのソースコード(通常は特定のCヘッダファイルをインクルードし、必要な型に$
プレフィックスを付けてtypedef
するだけのシンプルなCファイル)を読み込み、その中で定義されている型や定数をGoの構文に変換します。これにより、GoプログラムがCのライブラリやOSのAPIと連携する際に、手動でGoの型定義を作成する手間を省き、定義の正確性を保証できます。
glibcとLinuxカーネルヘッダの差異
Linuxシステムでは、ユーザー空間のプログラムは通常glibcを介してシステムコールを呼び出します。glibcは、カーネルのシステムコールをラップし、より高レベルなAPIを提供します。しかし、glibcが提供するヘッダファイルと、Linuxカーネルが直接提供するヘッダファイル(通常は/usr/include/asm
や/usr/include/linux
以下にある)では、同じシステム構造体であっても、その定義(特にフィールドの順序やパディング)が異なる場合があります。
Goランタイムのようにカーネルと直接対話する低レベルなコードでは、glibcの定義ではなく、カーネルの正確な定義に準拠する必要があります。このコミットは、godefs
を使用してカーネルのヘッダから直接定義を生成することで、この問題を回避しています。
技術的詳細
このコミットの核心は、GoランタイムがLinuxシステムと対話するために必要なC言語の構造体や定数の定義を、手動から自動生成に切り替えることです。この自動生成プロセスには、godefs
ツールが使用されます。
-
godefs
の導入:src/runtime/linux/defs.c
とsrc/runtime/linux/defs1.c
という新しいCソースファイルが導入されました。これらのファイルは、godefs
ツールへの入力として機能します。- これらのCファイルは、Linuxカーネルのヘッダファイル(例:
<asm/signal.h>
,<asm/siginfo.h>
,<asm/mman.h>
,<ucontext.h>
) をインクルードし、Goランタイムが必要とする特定の構造体や定数に$
プレフィックスを付けてtypedef
またはenum
で定義しています。 godefs
は、これらのCファイルを解析し、$
プレフィックスが付いた型や定数をGo言語の対応する定義に変換します。例えば、$PROT_NONE
はPROT_NONE
というGoの定数に、$Timespec
はTimespec
というGoの構造体になります。defs.c
のコメントには、glibcとLinuxカーネルの定義の衝突について明記されており、Goランタイムがカーネル側の定義を必要としていることが示されています。defs1.c
は、ucontext.h
のような、より複雑な構造体を含むヘッダを処理するために分離されています。
-
defs.h
の自動生成:src/runtime/linux/amd64/defs.h
ファイルの内容が大幅に変更されました。以前は手動で定義されていた構造体や定数が削除され、MACHINE GENERATED - DO NOT EDIT.
というコメントと共に、godefs
によって生成された内容に置き換えられました。- 生成された
defs.h
には、Timespec
,Timeval
,Sigaction
,Siginfo
,Usigset
,Fpxreg
,Xmmreg
,Fpstate
,Sigaltstack
,Mcontext
,Ucontext
,Sigcontext
などの構造体と、PROT_NONE
,MAP_ANON
,SA_RESTART
などの定数が含まれています。これらの定義は、Linuxカーネルのヘッダファイルから直接抽出されたものであり、Goランタイムがカーネルと正確に連携するために不可欠です。
-
ランタイムコードの適応:
src/runtime/linux/signal.c
とsrc/runtime/linux/thread.c
の既存のコードが、新しい自動生成された型定義を使用するように変更されました。- 例えば、
signal.c
では、以前手動で定義されていたstruct _fpstate
,struct sigcontext
,struct ucontext
などが削除され、defs.h
で定義されたSigcontext
,Ucontext
などの型が直接使用されています。 - また、
signal.c
のdumpregs
関数(以前はprint_sigcontext
)やsighandler
関数も、新しい型定義に合わせて引数や内部のアクセス方法が変更されています。出力形式もsys·printhex
からprintf
に変更され、より標準的なデバッグ出力になっています。 src/runtime/linux/os.h
が新しく追加され、Linux固有のシステムコール(futex
,clone
,rt_sigaction
)の宣言が含まれるようになりました。これにより、これらのシステムコールがdefs.h
とは別の場所で管理され、コードのモジュール性が向上しています。
この変更により、GoランタイムはLinuxシステムとのインターフェースにおいて、より堅牢で正確な型定義を持つことができるようになりました。カーネルの変更に追従する手間が軽減され、異なるLinux環境での互換性も向上します。
コアとなるコードの変更箇所
src/runtime/linux/amd64/defs.h
- 手動で定義されていた
typedef
やstruct
定義(dev_t
,ino_t
,timespec
,timeval
,stat
など)が削除されました。 godefs
によって自動生成された新しい定義が追加されました。これには、PROT_NONE
などの定数、Timespec
,Timeval
,Sigaction
,Siginfo
,Usigset
,Fpxreg
,Xmmreg
,Fpstate
,Sigaltstack
,Mcontext
,Ucontext
,Sigcontext
などの構造体が含まれます。
src/runtime/linux/defs.c
(新規ファイル)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* Input to godefs
* godefs -f -m64 defs.c >amd64/defs.h
* godefs -f -m64 defs1.c >>amd64/defs.h
* godefs defs.c >386/defs.h
* godefs defs1.c >>386/defs.h
*/
// Linux glibc and Linux kernel define different and conflicting
// definitions for struct sigaction, struct timespec, etc.
// We want the kernel ones, which are in the asm/* headers.
// But then we'd get conflicts when we include the system
// headers for things like ucontext_t, so that happens in
// a separate file, defs1.c.
#include <asm/signal.h>
#include <asm/siginfo.h>
#include <asm/mman.h>
enum {
$PROT_NONE = PROT_NONE,
$PROT_READ = PROT_READ,
$PROT_WRITE = PROT_WRITE,
$PROT_EXEC = PROT_EXEC,
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
$SA_RESTORER = SA_RESTORER,
$SA_SIGINFO = SA_SIGINFO,
};
typedef struct timespec $Timespec;
typedef struct timeval $Timeval;
typedef struct sigaction $Sigaction;
typedef siginfo_t $Siginfo;
src/runtime/linux/defs1.c
(新規ファイル)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
* Input to godefs
* godefs -f -m64 defs.c >amd64/defs.h
* godefs -f -m64 defs1.c >>amd64/defs.h
* godefs defs.c >386/defs.h
* godefs defs1.c >>386/defs.h
*/
#include <ucontext.h>
typedef __sigset_t $Usigset;
typedef struct _libc_fpxreg $Fpxreg;
typedef struct _libc_xmmreg $Xmmreg;
typedef struct _libc_fpstate $Fpstate;
typedef struct _fpxreg $Fpxreg1;
typedef struct _xmmreg $Xmmreg1;
typedef struct _fpstate $Fpstate1;
typedef struct sigaltstack $Sigaltstack;
typedef mcontext_t $Mcontext;
typedef ucontext_t $Ucontext;
typedef struct sigcontext $Sigcontext;
src/runtime/linux/os.h
(新規ファイル)
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Linux-specific system calls
int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
int64 clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
void rt_sigaction(int64, struct Sigaction*, void*, uint64);
src/runtime/linux/signal.c
- 手動で定義されていた
_fpstate
,sigcontext
,sigaltstack
,ucontext
,siginfo
,sigaction
などの構造体定義が削除されました。 #include "os.h"
が追加されました。print_sigcontext
関数がdumpregs
にリネームされ、引数と内部のレジスタアクセスがSigcontext
型を使用するように変更されました。また、sys·printhex
からprintf
による出力に変更されました。sighandler
関数がSiginfo* info, void* context
を引数にとるように変更され、内部でUcontext
,Mcontext
,Sigcontext
型を使用するように修正されました。signalstack
関数がSigaltstack
型を使用するように変更されました。initsig
関数がSigaction
型を使用するように変更されました。
src/runtime/linux/thread.c
#include "os.h"
が追加されました。static struct timespec longtime
がstatic Timespec longtime
に変更されました。
コアとなるコードの解説
このコミットの主要な変更は、GoランタイムがLinuxシステムと対話するために必要な低レベルな型定義の管理方法を根本的に変えた点にあります。
-
godefs
入力ファイル (defs.c
,defs1.c
):- これらのCファイルは、GoランタイムがLinuxカーネルから取得する必要がある構造体や定数を定義するための「テンプレート」として機能します。
#include <asm/signal.h>
などのカーネルヘッダを直接インクルードすることで、glibcの定義ではなく、カーネルの正確な定義を参照しています。$PROT_NONE = PROT_NONE
やtypedef struct timespec $Timespec;
のような構文は、godefs
ツールに対する指示です。$
プレフィックスは、godefs
がこれらのCの定義をGoの対応する型や定数に変換すべきであることを示します。defs.c
とdefs1.c
に分割されているのは、ucontext.h
のような特定のヘッダが、他のヘッダとインクルード順序や定義の衝突を引き起こす可能性があるため、分離して処理することでgodefs
の実行を容易にするためです。
-
自動生成された
defs.h
:godefs
がdefs.c
とdefs1.c
を処理することで、src/runtime/linux/amd64/defs.h
が生成されます。このファイルは、GoランタイムがCgoなしでLinuxシステムコールを直接呼び出す際に使用する、Go言語の構造体と定数の定義を含んでいます。- 例えば、
struct Timespec
はGoのTimespec
構造体として定義され、int64 tv_sec; int64 tv_nsec;
といったフィールドがGoの型にマッピングされます。これにより、GoコードからLinuxのtimespec
構造体を安全かつ正確に操作できるようになります。 Sigaction
,Siginfo
,Ucontext
,Mcontext
,Sigcontext
といったシグナルハンドリングに関連する複雑な構造体も、カーネルの定義に基づいて正確にGoの構造体として表現されます。これは、シグナル発生時のレジスタ状態やスタック情報などを正確に読み取るために非常に重要です。
-
ランタイムコードの適応 (
signal.c
,thread.c
):- 以前は、これらのファイル内でLinuxのシステム構造体が手動で再定義されていました。これは、カーネルの定義と同期が取れていない場合、バグの原因となる可能性がありました。
- このコミットにより、手動定義が削除され、自動生成された
defs.h
で提供される型(例:Sigcontext
,Ucontext
)が直接使用されるようになりました。これにより、Goランタイムのコードは常にカーネルの最新かつ正確な定義に準拠するようになります。 dumpregs
関数がprintf
を使用するように変更されたのは、Goランタイムのデバッグ出力の標準化と、より柔軟なフォーマットを可能にするためと考えられます。
この一連の変更は、Goランタイムの低レベルなOSインターフェースの堅牢性とメンテナンス性を大幅に向上させます。手動での定義管理に伴うエラーのリスクを減らし、Goが様々なLinux環境でより安定して動作するための基盤を強化しています。
関連リンク
- Go言語の
syscall
パッケージのドキュメント(Goランタイムがシステムコールをどのように扱うか理解するのに役立ちます) godefs
ツールのソースコードや関連ドキュメント(Goプロジェクト内でどのように使用されているか)- Linuxカーネルのソースコード(特に
arch/x86/include/asm
やinclude/uapi/linux
以下のヘッダファイル)
参考にした情報源リンク
- Go言語の公式ドキュメント: https://go.dev/doc/
- Goのソースコードリポジトリ: https://github.com/golang/go
- Linuxカーネルのドキュメントやソースコード(特定の構造体定義の確認のため)
godefs
に関する情報(Goのツールチェーンの一部として)godefs
のソースコードはGoリポジトリ内のsrc/cmd/godefs
にあります。godefs
の基本的な使い方や目的については、Goの初期の設計に関する議論やドキュメントで触れられていることがあります。
(注: godefs
はGoの内部ツールであり、一般的なユーザー向けに詳細なドキュメントが公開されているわけではありません。その機能は主にGoランタイムや標準ライブラリのOS固有部分のビルドプロセスで使用されます。)