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

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

このコミットは、GoランタイムにおけるPlan 9オペレーティングシステムでのビルド問題を修正するものです。具体的には、シグナルハンドリング用のゴルーチン(gsignal)が、対応するOSスレッド(M)に正しく関連付けられていなかった問題を解決します。

コミット

commit a6999c88455e6453964f4b3eac7c11a9febeb5c2
Author: Anthony Martin <ality@pbrane.org>
Date:   Fri Jun 27 15:36:41 2014 +0200

    runtime: fix Plan 9 build
    
    LGTM=0intro, aram
    R=rsc, 0intro, aram
    CC=golang-codereviews
    https://golang.org/cl/109240044

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

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

元コミット内容

runtime: fix Plan 9 build

LGTM=0intro, aram
R=rsc, 0intro, aram
CC=golang-codereviews
https://golang.org/cl/109240044

変更の背景

このコミットの背景には、GoランタイムがPlan 9オペレーティングシステム上で正しくビルドまたは実行できない問題がありました。Goランタイムは、OSとのインタラクション、特にシグナルハンドリングにおいて、OSスレッドとGoのゴルーチンを密接に連携させる必要があります。

src/pkg/runtime/os_plan9.cファイルは、GoランタイムがPlan 9固有のOS機能とどのように連携するかを定義しています。このファイル内のruntime·mpreinit関数は、各OSスレッド(M)が初期化される際に呼び出され、シグナルハンドリングに必要なゴルーチンやスタックなどのリソースを準備します。

以前の実装では、シグナルハンドリング用のゴルーチン(mp->gsignal)が作成されたものの、そのゴルーチンがどのOSスレッド(M)に属しているかという情報が欠落していました。この関連付けがないと、Plan 9環境下でシグナルが正しく処理されなかったり、ランタイムの動作が不安定になったりする可能性がありました。このコミットは、この重要な関連付けを設定することで、Plan 9でのビルドおよび実行時の安定性を確保することを目的としています。

前提知識の解説

このコミットを理解するためには、以下のGoランタイムの概念とPlan 9に関する基本的な知識が必要です。

  • Goランタイム (Go Runtime): Goプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。ランタイムは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、チャネル通信、メモリ管理、OSとのインタラクションなど、Go言語の多くのコア機能を提供します。Goプログラムのパフォーマンスと並行性を支える重要な部分です。

  • M (Machine) と G (Goroutine): Goのスケジューラは、M(Machine)、P(Processor)、G(Goroutine)という3つの主要な抽象化によって構成されます。

    • G (Goroutine): Goにおける軽量な並行実行単位です。数KB程度のスタックを持ち、数百万個作成しても問題ないとされています。Goの関数呼び出しはすべてゴルーチン上で実行されます。
    • M (Machine): OSスレッドを表します。Goランタイムは、OSスレッドをMとして抽象化し、その上でGを実行します。MはOSから提供されるリソース(CPU時間、メモリなど)を直接利用します。
    • P (Processor): 論理プロセッサを表し、MとGの仲介役となります。Pは実行可能なGのキューを持ち、MはPからGを取得して実行します。
  • シグナルハンドリング (Signal Handling): シグナルは、オペレーティングシステムがプロセスに非同期的にイベントを通知するメカニズムです。例えば、Ctrl+Cによるプログラムの中断(SIGINT)、不正なメモリアクセス(SIGSEGV)、タイマーの満了(SIGALRM)などがあります。Goランタイムは、これらのシグナルを捕捉し、適切に処理することで、プログラムの堅牢性や終了処理を管理します。シグナルは通常、特定のOSスレッドに配送されるため、ランタイムはどのゴルーチンがどのOSスレッドでシグナルを処理するかを正確に把握する必要があります。

  • Plan 9: Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの概念をさらに推し進め、すべてのリソースをファイルとして表現し、ネットワーク透過性を重視しています。Go言語は、初期からPlan 9をサポートしており、Goの設計思想の一部にはPlan 9の影響が見られます。Goランタイムは、Plan 9を含む複数のOSに対応するために、OS固有のコードを持っています。

技術的詳細

このコミットの技術的詳細は、GoランタイムがOSスレッド(M)とシグナルハンドリング用のゴルーチン(gsignal)との間の重要な関連付けを確立する方法にあります。

変更が加えられたsrc/pkg/runtime/os_plan9.cファイル内のruntime·mpreinit関数は、新しいOSスレッド(M)がGoランタイムによって初期化される際に呼び出されます。この関数は、そのMに関連付けられるべき特定のゴルーチンやその他のリソースを設定する役割を担っています。

変更前のコードでは、mp->gsignal = runtime·malg(32*1024);という行で、シグナルハンドリング専用のゴルーチンが作成され、そのポインタが現在のM構造体(mp)のgsignalフィールドに格納されていました。しかし、このgsignalゴルーチン自体が、どのM(OSスレッド)上で実行されるべきか、あるいはどのMに属しているかという情報を持っていませんでした。

追加されたmp->gsignal->m = mp;という一行は、この欠落していた関連付けを確立します。

  • mp->gsignalは、新しく作成されたシグナルハンドリングゴルーチンへのポインタです。
  • このゴルーチン構造体には、mというフィールドがあり、これはそのゴルーチンが現在実行されている、または関連付けられているM(OSスレッド)へのポインタを保持します。
  • = mp;によって、現在初期化中のMmp)が、このgsignalゴルーチンのmフィールドに明示的に設定されます。

この関連付けは、特にシグナル処理において極めて重要です。OSはシグナルを特定のOSスレッドに配送します。Goランタイムがそのシグナルを捕捉し、gsignalゴルーチンに処理させるためには、gsignalゴルーチンがどのMに属しているかを正確に知る必要があります。この設定により、gsignalゴルーチンは、シグナルを受け取ったMのコンテキスト内で適切に動作し、シグナルを処理できるようになります。

この修正は、Plan 9環境におけるGoランタイムの安定性と正確なシグナルハンドリングを保証するために不可欠でした。

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

--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -19,6 +19,7 @@ runtime·mpreinit(M *mp)
 {
 	// Initialize stack and goroutine for note handling.
 	mp->gsignal = runtime·malg(32*1024);\n+\tmp->gsignal->m = mp;\n 	mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8));\n 
 	// Initialize stack for handling strings from the

コアとなるコードの解説

追加された一行は mp->gsignal->m = mp; です。

  • mp: 現在初期化中のOSスレッド(M)を表すポインタです。
  • mp->gsignal: mp(現在のOSスレッド)に関連付けられた、シグナルハンドリング用のゴルーチン(G)へのポインタです。このゴルーチンは、runtime·malg(32*1024)によって、32KBのスタックを持つ新しいゴルーチンとして作成されています。
  • mp->gsignal->m: gsignalゴルーチン構造体内のmフィールドです。このフィールドは、そのゴルーチンが関連付けられている、または実行されているM(OSスレッド)へのポインタを保持します。

この行が追加されることで、新しく作成されたシグナルハンドリングゴルーチン(mp->gsignal)が、現在初期化中のOSスレッド(mp)に明示的に関連付けられます。

なぜこの行が必要なのか?

Goランタイムのスケジューラでは、ゴルーチン(G)はOSスレッド(M)上で実行されます。シグナルはOSによってOSスレッドに配送されます。Goランタイムがシグナルを捕捉し、それをGoのコンテキスト(つまり、gsignalゴルーチン)で処理するためには、gsignalゴルーチンがどのMに属しているかをランタイムが正確に把握している必要があります。

このmp->gsignal->m = mp;という代入がない場合、gsignalゴルーチンは作成されますが、そのmフィールドは初期化されず、nilまたは不定な値のままになる可能性があります。これにより、Plan 9環境でシグナルが配送された際に、ランタイムがgsignalゴルーチンを正しくスケジューリングできなかったり、シグナル処理に必要なMのコンテキストを見つけられなかったりする問題が発生します。

この修正は、gsignalゴルーチンとそれを実行するOSスレッドとの間のリンクを確立し、Plan 9上でのGoプログラムのシグナルハンドリングが堅牢かつ正確に行われるようにするために不可欠です。

関連リンク

Web検索では、この特定のコミットに関する追加の関連リンク(例えば、詳細な議論や関連するバグトラッカーのエントリ)は見つかりませんでした。

参考にした情報源リンク

  • Go言語の公式ドキュメントおよびソースコード
  • Goランタイムのスケジューラに関する一般的な知識
  • Plan 9オペレーティングシステムに関する一般的な知識
  • Web検索(ただし、このコミットに直接関連する詳細な情報は見つからず)
  • https://golang.org/cl/109240044 (直接アクセスはできませんでしたが、コミットメッセージに記載されていたため参照として含めました)