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

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

このコミットは、Go言語のsyscallパッケージにおけるPlan 9オペレーティングシステム向けのAwait関数のバグ修正に関するものです。具体的には、Plan 9のawait()システムコールが正常終了時に空文字列 ('') を返す挙動が、Goプログラム、特にgotestによってエラーと誤認識される問題を解決しています。

コミット

  • コミットハッシュ: d1f48db1cc021924e52614b5f7a71ab8bfa3f1cd
  • Author: Andrey Mirtchovski mirtchovski@gmail.com
  • Date: Mon Oct 31 13:34:59 2011 -0400
  • コミットメッセージ:
    syscall: fix Await msg on Plan 9
    
    Plan 9's await() returns '' for nil exit status but programs, most notably gotest,
    see this as an error return.
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5305079
    

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

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

元コミット内容

syscall: fix Await msg on Plan 9

Plan 9's await() returns '' for nil exit status but programs, most notably gotest,
see this as an error return.

R=rsc
CC=golang-dev
https://golang.org/cl/5305079

変更の背景

この変更は、Plan 9オペレーティングシステム上でGoプログラムがプロセス終了ステータスを待機する際に発生する特定の挙動に起因するバグを修正するために行われました。

Plan 9のawait()システムコールは、子プロセスの終了を待機し、その終了ステータスに関するメッセージを返します。通常、プロセスがエラーなく正常に終了した場合、このシステムコールは「nil exit status」(エラーなし)を示すために空文字列 ('') を返します。

しかし、Go言語のsyscallパッケージ内でこの空文字列が処理される際、またはGoの他のプログラム、特にテスト実行ツールであるgotestがこのメッセージを解釈する際に、この空文字列が「エラーメッセージ」として誤って認識されてしまう問題がありました。これにより、実際には正常に終了したプロセス(例えば、テストが成功したケース)であっても、gotestがエラーを報告してしまうという誤った挙動が発生していました。

このコミットは、syscallパッケージがPlan 9のawait()から受け取った空文字列を、Goの内部表現で「エラーなし」を意味する真の空文字列 ("") に変換することで、この誤認識を解消することを目的としています。

前提知識の解説

Plan 9 from Bell Labs

Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。Unixの概念をさらに推し進め、すべてのリソース(ファイル、デバイス、ネットワーク接続など)をファイルシステムとして表現するという哲学を持っています。これにより、システム全体が統一されたインターフェースでアクセス可能になります。Go言語の開発者の一部はPlan 9の開発にも携わっており、Go言語の設計思想にもPlan 9の影響が見られます。

await() システムコール (Plan 9)

Plan 9におけるawait()システムコールは、Unix系のwait()waitpid()に相当する機能を提供します。これは、子プロセスの終了を待機し、その終了に関する情報(プロセスID、終了時間、終了メッセージなど)を返します。特に重要なのは、子プロセスが正常終了した場合、await()は終了メッセージとして空文字列 ('') を返すというPlan 9特有の挙動です。これはUnixにおける終了ステータス0(成功)に相当します。

終了ステータスと終了メッセージ

オペレーティングシステムにおいて、プロセスが終了する際にはその成否を示す「終了ステータス」または「終了メッセージ」を親プロセスに伝えます。

  • Unix/Linux: 通常、0は成功、0以外の値はエラーを示します。
  • Plan 9: await()は終了メッセージとして文字列を返します。空文字列 ('') は成功を意味し、それ以外の文字列はエラーメッセージを示します。

gotest

gotestは、Go言語の標準的なテスト実行ツールです。Goのソースコード内のテスト関数(TestXxxという命名規則に従う関数)を検出し、実行し、その結果(成功/失敗)を報告します。gotestは、実行されたテストプロセスの終了ステータスやメッセージを解釈し、テストの成否を判断します。このコミットの背景にある問題は、gotestがPlan 9のawait()から返される空文字列を誤ってエラーと判断していたことにあります。

Go言語のsyscallパッケージ

Go言語のsyscallパッケージは、オペレーティングシステムの低レベルなシステムコールへのインターフェースを提供します。これにより、Goプログラムはファイル操作、プロセス管理、ネットワーク通信など、OSカーネルが提供する機能に直接アクセスできます。このコミットでは、Plan 9向けのsyscallパッケージの実装、特にAwait関数が修正の対象となっています。

技術的詳細

Plan 9のawait()システムコールは、子プロセスの終了時に以下のような形式のメッセージを返します。

pid time[0] time[1] time[2] msg

ここで、msgは終了メッセージです。プロセスが正常に終了した場合、このmsgは空文字列、すなわち''となります。これは、Plan 9のシェルや他のツールが「エラーなし」と解釈する標準的な挙動です。

Go言語のsyscallパッケージ内のAwait関数は、このawait()システムコールからの生のメッセージを解析し、GoのWaitmsg構造体に格納します。Waitmsg構造体には、終了メッセージを格納するためのMsgフィールド(型はstring)があります。

問題は、Plan 9のawait()が返す空文字列''が、Goのsyscallパッケージ内で文字列として処理される際に、Goの文字列リテラルとしての空文字列""とは異なるものとして扱われる可能性があったことです。特に、await()が返す''は、Goの文字列として"''"(シングルクォートで囲まれた空文字列)として解釈されてしまい、これがGoのプログラム(特にgotest)によって「何らかのエラーメッセージが存在する」と誤解されていました。

このコミットの修正は、syscall/syscall_plan9.go内のAwait関数において、await()システムコールから取得したメッセージが"''"(シングルクォートで囲まれた空文字列)である場合に、それをGoの真の空文字列""に変換するというシンプルなロジックを追加することで、この問題を解決しています。これにより、gotestなどのGoプログラムが、Plan 9の正常終了メッセージを正しく「エラーなし」と認識できるようになります。

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

--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -245,6 +245,10 @@ func Await(w *Waitmsg) (err Error) {
 	w.Time[1] = uint32(atoi(f[2]))
 	w.Time[2] = uint32(atoi(f[3]))
 	w.Msg = cstring(f[4])
+	if w.Msg == "''" {
+		// await() returns '' for no error
+		w.Msg = ""
+	}
 	return
 }

コアとなるコードの解説

変更はsrc/pkg/syscall/syscall_plan9.goファイルのAwait関数内で行われています。

Await関数は、Plan 9のawait()システムコールから返された情報を解析し、Waitmsg構造体のポインタwにその結果を格納します。

  1. w.Msg = cstring(f[4])

    • f[4]は、await()システムコールから返されたメッセージ文字列のフィールドです。
    • cstring関数は、Cスタイルの文字列(null終端文字列)をGoの文字列に変換するユーティリティ関数です。
    • ここで、Plan 9のawait()が正常終了時に返す''という文字列が、Goのw.Msgフィールドに代入されます。問題は、この''がGoの文字列として"''"(シングルクォートで囲まれた空文字列)として解釈されてしまう点にありました。
  2. if w.Msg == "''" { ... }

    • このif文が追加された修正の核心です。
    • w.Msgに格納された文字列が、もし"''"(シングルクォートで囲まれた空文字列)と完全に一致する場合、つまりPlan 9のawait()が正常終了を示している場合、以下の処理が実行されます。
  3. w.Msg = ""

    • w.Msgの値を、Goの真の空文字列 ("") に上書きします。
    • この変換により、Await関数を呼び出したGoのプログラム(例: gotest)は、w.Msgが真に空であること、すなわちエラーメッセージが存在しないことを正しく認識できるようになります。これにより、正常終了がエラーと誤認識される問題が解消されます。

この修正は、Plan 9の特定の挙動とGoの文字列処理の間の不一致を、syscallパッケージの低レベルな部分で吸収することで、上位のGoプログラムが期待するセマンティクス(空文字列はエラーなし)を提供するようにしています。

関連リンク

参考にした情報源リンク