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

[インデックス 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ランタイムはカーネルと直接対話するため、カーネル側の正確な定義を使用する必要があります。手動でこれらの定義を管理することは、以下のような問題を引き起こします。

  1. メンテナンスの困難さ: カーネルのバージョンアップやアーキテクチャの変更に伴い、手動で定義を更新し続けるのは手間がかかり、エラーの温床となります。
  2. 定義の不一致: glibcとカーネルの定義の差異を常に意識し、Goランタイムがカーネルと期待通りに動作するように手動で調整するのは非常に複雑です。
  3. 移植性の問題: 異なる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ツールが使用されます。

  1. godefsの導入:

    • src/runtime/linux/defs.csrc/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_NONEPROT_NONEというGoの定数に、$TimespecTimespecというGoの構造体になります。
    • defs.cのコメントには、glibcとLinuxカーネルの定義の衝突について明記されており、Goランタイムがカーネル側の定義を必要としていることが示されています。defs1.cは、ucontext.hのような、より複雑な構造体を含むヘッダを処理するために分離されています。
  2. 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ランタイムがカーネルと正確に連携するために不可欠です。
  3. ランタイムコードの適応:

    • src/runtime/linux/signal.csrc/runtime/linux/thread.cの既存のコードが、新しい自動生成された型定義を使用するように変更されました。
    • 例えば、signal.cでは、以前手動で定義されていたstruct _fpstate, struct sigcontext, struct ucontextなどが削除され、defs.hで定義されたSigcontext, Ucontextなどの型が直接使用されています。
    • また、signal.cdumpregs関数(以前は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

  • 手動で定義されていたtypedefstruct定義(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 longtimestatic Timespec longtimeに変更されました。

コアとなるコードの解説

このコミットの主要な変更は、GoランタイムがLinuxシステムと対話するために必要な低レベルな型定義の管理方法を根本的に変えた点にあります。

  1. godefs入力ファイル (defs.c, defs1.c):

    • これらのCファイルは、GoランタイムがLinuxカーネルから取得する必要がある構造体や定数を定義するための「テンプレート」として機能します。
    • #include <asm/signal.h>などのカーネルヘッダを直接インクルードすることで、glibcの定義ではなく、カーネルの正確な定義を参照しています。
    • $PROT_NONE = PROT_NONEtypedef struct timespec $Timespec;のような構文は、godefsツールに対する指示です。$プレフィックスは、godefsがこれらのCの定義をGoの対応する型や定数に変換すべきであることを示します。
    • defs.cdefs1.cに分割されているのは、ucontext.hのような特定のヘッダが、他のヘッダとインクルード順序や定義の衝突を引き起こす可能性があるため、分離して処理することでgodefsの実行を容易にするためです。
  2. 自動生成されたdefs.h:

    • godefsdefs.cdefs1.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の構造体として表現されます。これは、シグナル発生時のレジスタ状態やスタック情報などを正確に読み取るために非常に重要です。
  3. ランタイムコードの適応 (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/asminclude/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ランタイムはカーネルと直接対話するため、カーネル側の正確な定義を使用する必要があります。手動でこれらの定義を管理することは、以下のような問題を引き起こします。

  1. メンテナンスの困難さ: カーネルのバージョンアップやアーキテクチャの変更に伴い、手動で定義を更新し続けるのは手間がかかり、エラーの温床となります。
  2. 定義の不一致: glibcとカーネルの定義の差異を常に意識し、Goランタイムがカーネルと期待通りに動作するように手動で調整するのは非常に複雑です。
  3. 移植性の問題: 異なる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ツールが使用されます。

  1. godefsの導入:

    • src/runtime/linux/defs.csrc/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_NONEPROT_NONEというGoの定数に、$TimespecTimespecというGoの構造体になります。
    • defs.cのコメントには、glibcとLinuxカーネルの定義の衝突について明記されており、Goランタイムがカーネル側の定義を必要としていることが示されています。defs1.cは、ucontext.hのような、より複雑な構造体を含むヘッダを処理するために分離されています。
  2. 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ランタイムがカーネルと正確に連携するために不可欠です。
  3. ランタイムコードの適応:

    • src/runtime/linux/signal.csrc/runtime/linux/thread.cの既存のコードが、新しい自動生成された型定義を使用するように変更されました。
    • 例えば、signal.cでは、以前手動で定義されていたstruct _fpstate, struct sigcontext, struct ucontextなどが削除され、defs.hで定義されたSigcontext, Ucontextなどの型が直接使用されています。
    • また、signal.cdumpregs関数(以前は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

  • 手動で定義されていたtypedefstruct定義(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 longtimestatic Timespec longtimeに変更されました。

コアとなるコードの解説

このコミットの主要な変更は、GoランタイムがLinuxシステムと対話するために必要な低レベルな型定義の管理方法を根本的に変えた点にあります。

  1. godefs入力ファイル (defs.c, defs1.c):

    • これらのCファイルは、GoランタイムがLinuxカーネルから取得する必要がある構造体や定数を定義するための「テンプレート」として機能します。
    • #include <asm/signal.h>などのカーネルヘッダを直接インクルードすることで、glibcの定義ではなく、カーネルの正確な定義を参照しています。
    • $PROT_NONE = PROT_NONEtypedef struct timespec $Timespec;のような構文は、godefsツールに対する指示です。$プレフィックスは、godefsがこれらのCの定義をGoの対応する型や定数に変換すべきであることを示します。
    • defs.cdefs1.cに分割されているのは、ucontext.hのような特定のヘッダが、他のヘッダとインクルード順序や定義の衝突を引き起こす可能性があるため、分離して処理することでgodefsの実行を容易にするためです。
  2. 自動生成されたdefs.h:

    • godefsdefs.cdefs1.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の構造体として表現されます。これは、シグナル発生時のレジスタ状態やスタック情報などを正確に読み取るために非常に重要です。
  3. ランタイムコードの適応 (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/asminclude/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固有部分のビルドプロセスで使用されます。)