[インデックス 19692] ファイルの概要
このコミットは、Go言語のランタイムがPlan 9オペレーティングシステム上でシステムコールを行う際に存在していた、特定の「NxMスケジューリングに関する仮定」を削除するものです。具体的には、src/pkg/syscall/asm_plan9_amd64.s
ファイル内のアセンブリコードから、システムコール呼び出し時にレジスタAX
に0x8000
という値を設定する命令が削除されています。これは、GoランタイムがPlan 9環境でより汎用的かつ効率的に動作するための改善の一環と考えられます。
コミット
commit 38e75f9d0e8a58ad30871dda7faa92dc9541d68f
Author: Aram Hăvărneanu <aram@mgk.ro>
Date: Wed Jul 9 12:32:18 2014 +0200
syscall: remove more NxM assumptions on Plan 9
LGTM=0intro, r
R=0intro, r
CC=ality, dave, golang-codereviews, jas, mischief, rsc
https://golang.org/cl/111910043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/38e75f9d0e8a58ad30871dda7faa92dc9541d68f
元コミット内容
--- a/src/pkg/syscall/asm_plan9_amd64.s
+++ b/src/pkg/syscall/asm_plan9_amd64.s
@@ -16,12 +16,8 @@
//func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
//func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
-// Trap # in BP, args on stack above caller pc.
-// NxM requires that Plan 9 system calls be
-// marked with $0x8000 in AX.
TEXT ·Syscall(SB),NOSPLIT,$0-64
CALL runtime·entersyscall(SB)
-\tMOVQ $0x8000, AX\t// for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
LEAQ 16(SP), SI
@@ -57,7 +53,6 @@ copyresult3:
TEXT ·Syscall6(SB),NOSPLIT,$0-88
CALL runtime·entersyscall(SB)
-\tMOVQ $0x8000, AX\t// for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
LEAQ 16(SP), SI
@@ -95,7 +90,6 @@ copyresult4:
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
-\tMOVQ $0x8000, AX\t// for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
LEAQ 16(SP), SI
@@ -111,7 +105,6 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-56
RET
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
-\tMOVQ $0x8000, AX\t// for NxM
MOVQ 8(SP), BP // syscall entry
// slide args down on top of system call number
LEAQ 16(SP), SI
@@ -136,7 +129,6 @@ TEXT ·seek(SB),NOSPLIT,$0-56
LEAQ newoffset+40(SP), AX
MOVQ AX, placeholder+8(SP)
-\tMOVQ $0x8000, AX\t// for NxM
MOVQ $SYS_SEEK, BP // syscall entry
SYSCALL
変更の背景
このコミットの背景には、Go言語のランタイムがPlan 9オペレーティングシステム上でシステムコールを扱う際の進化があります。Goは、その設計者の一部がPlan 9の開発にも深く関わっていたため、Plan 9との歴史的なつながりがあります。Goのランタイムは、多数の軽量なゴルーチン(N)を少数のOSスレッド(M)にマッピングする「M:Nスケジューリング」という独自のスケジューリングモデルを採用しています。
以前のGoランタイムでは、Plan 9上でのシステムコールにおいて、このM:Nスケジューリングの特性を考慮した特定の「仮定」が組み込まれていました。具体的には、システムコールを呼び出す際に、AX
レジスタに0x8000
という値を設定する必要がありました。これは、Plan 9のネイティブなシステムコール規約ではなく、Goランタイムが内部的にM:Nスケジューリングのコンテキストでシステムコールを識別または処理するために導入した独自のマーカーであったと考えられます。
このコミットは、Goランタイムの成熟とPlan 9との統合の改善により、この特定の0x8000
という仮定が不要になったことを示しています。ランタイムの内部的なシステムコール処理ロジックがより洗練され、この明示的なマーカーなしでもM:Nスケジューリングを適切に管理できるようになったため、コードの簡素化と汎用性の向上が図られました。これにより、Plan 9上でのGoプログラムの動作がより標準的なシステムコール規約に近づき、保守性が向上するとともに、将来的な変更への対応も容易になります。
前提知識の解説
このコミットを理解するためには、以下の概念について基本的な知識が必要です。
- Go言語のランタイム: Goプログラムが実行される環境であり、ゴルーチンのスケジューリング、ガベージコレクション、システムコールなど、プログラムの実行に必要な低レベルの機能を提供します。
- M:Nスケジューリング (Goroutine Scheduling): Goの大きな特徴の一つで、多数のゴルーチン(軽量な並行実行単位)を、OSが提供する少数のスレッド上で効率的に実行する仕組みです。N個のゴルーチンをM個のOSスレッドにマッピングするため、「M:Nスケジューリング」と呼ばれます。これにより、OSスレッドの切り替えコストを抑えつつ、高い並行性を実現しています。
- Plan 9 from Bell Labs: ベル研究所で開発された分散オペレーティングシステムです。「すべてがファイルである」という哲学を持ち、システムリソース(デバイス、ネットワーク接続など)をファイルとして抽象化してアクセスするユニークな設計が特徴です。Go言語の設計者であるRob PikeやKen ThompsonがPlan 9の開発にも深く関わっていたため、Go言語にはPlan 9の影響が見られます。
- システムコール (Syscall): オペレーティングシステムが提供するサービス(ファイルの読み書き、メモリの確保、プロセスの作成など)を、ユーザープログラムが利用するためのインターフェースです。プログラムはシステムコールを通じてOSカーネルに処理を要求します。
- アセンブリ言語 (Assembly Language): コンピュータのCPUが直接理解できる機械語に非常に近い低レベルのプログラミング言語です。特定のCPUアーキテクチャ(この場合はAMD64)に特化しており、レジスタの操作やメモリへの直接アクセスなど、ハードウェアに近い制御が可能です。Goランタイムのシステムコール部分は、パフォーマンスとOSとの正確な連携のためにアセンブリ言語で記述されることがあります。
- レジスタ (Registers): CPU内部にある高速な記憶領域で、演算やデータ転送の一時的なデータを保持するために使用されます。
AX
(または64ビット環境ではRAX
)は汎用レジスタの一つで、関数呼び出しの引数や戻り値、システムコール番号などを格納するためによく使われます。 MOVQ
命令: x86-64アセンブリ言語における命令の一つで、64ビットの値をレジスタやメモリ間で移動(コピー)するために使用されます。MOVQ $0x8000, AX
は、「即値0x8000
をAX
レジスタに移動する」という意味になります。
技術的詳細
このコミットは、GoランタイムのPlan 9向けシステムコール実装における特定の最適化または規約の削除を意味します。
GoのM:Nスケジューラは、ゴルーチンがシステムコールを実行する際に、OSスレッドをブロックしないように工夫されています。ゴルーチンがブロッキングシステムコールを発行すると、そのゴルーチンは現在のOSスレッドから切り離され、別の実行可能なゴルーチンがそのスレッド上で実行されます。システムコールが完了すると、元のゴルーチンは再びスケジューラによって実行可能な状態に戻されます。
Plan 9環境において、Goランタイムはシステムコールを呼び出す際に、AX
レジスタに0x8000
という値を設定していました。これは、Plan 9の標準的なシステムコール規約の一部ではなく、GoランタイムがM:Nスケジューリングのコンテキストでシステムコールを処理するための内部的な「フラグ」または「マーカー」として機能していたと考えられます。この0x8000
という値は、システムコールがGoのスケジューラによって管理されるべきものであることを示唆していた可能性があります。例えば、このフラグを見て、ランタイムがシステムコール完了後にゴルーチンを再スケジュールするなどの特別な処理を行っていたのかもしれません。
コミットメッセージにある「remove more NxM assumptions」という表現は、GoランタイムがPlan 9上でのシステムコール処理において、より洗練された、あるいはより汎用的なメカニズムを採用したことを示唆しています。つまり、システムコールがM:Nスケジューリングのコンテキストで実行されていることを明示的にAX
レジスタに0x8000
を設定して示す必要がなくなったということです。これは、ランタイムの内部ロジックが、システムコールの種類や実行コンテキストに基づいて、自動的に適切なスケジューリング動作を決定できるようになったことを意味するかもしれません。
この変更により、GoランタイムはPlan 9のシステムコールインターフェースをより「素直に」利用できるようになり、特定のGo固有の仮定に依存しない、よりクリーンなコードベースへと進化しています。これは、Goのクロスプラットフォーム対応と、各OS環境への適応能力を高める上で重要なステップです。
コアとなるコードの変更箇所
変更はsrc/pkg/syscall/asm_plan9_amd64.s
ファイルに集中しています。このファイルは、Goのsyscall
パッケージがPlan 9のAMD64アーキテクチャ上でシステムコールを呼び出すためのアセンブリコードを含んでいます。
具体的には、以下のGoのシステムコールラッパー関数に対応するアセンブリコードブロックから、MOVQ $0x8000, AX
という命令が削除されています。
TEXT ·Syscall(SB)
: 一般的なシステムコール呼び出しTEXT ·Syscall6(SB)
: 6つの引数を持つシステムコール呼び出しTEXT ·RawSyscall(SB)
: 生のシステムコール呼び出し(Goスケジューラによる特別な処理なし)TEXT ·RawSyscall6(SB)
: 6つの引数を持つ生のシステムコール呼び出しTEXT ·seek(SB)
:seek
システムコール(ファイルポインタの移動)
これらの命令は、システムコールを実行する直前にAX
レジスタに0x8000
を設定していました。コメントには「// for NxM
」と明記されており、これがM:Nスケジューリングに関連する仮定であったことがわかります。このコミットでは、これらの行がすべて削除されています。
コアとなるコードの解説
削除されたMOVQ $0x8000, AX
命令は、システムコールを呼び出す直前にAX
レジスタに特定の値を設定する役割を担っていました。アセンブリ言語において、レジスタはCPUがデータを一時的に保持するために使用する高速な記憶領域です。AX
レジスタは、x86アーキテクチャにおいて、関数呼び出しの戻り値やシステムコール番号、あるいは特定のフラグを渡すためによく使われます。
この場合、0x8000
という値は、Plan 9のネイティブなシステムコール規約の一部ではなく、GoランタイムがPlan 9上でM:Nスケジューリングを実装する際に導入した独自の規約であったと推測されます。つまり、Goランタイムは、この0x8000
というフラグがAX
レジスタに設定されていることを検知することで、そのシステムコールがGoのゴルーチンによって発行されたものであり、M:Nスケジューラの管理下にあることを認識していた可能性があります。これにより、ランタイムはシステムコールが完了した際に、ゴルーチンを適切に再スケジュールしたり、OSスレッドのブロックを回避したりするなどの特別な処理を行うことができたと考えられます。
このコミットでこれらの命令が削除されたということは、GoランタイムがPlan 9上でのシステムコール処理において、より洗練された、あるいはより汎用的なアプローチを採用したことを意味します。例えば、以下のような変更がランタイム内部で行われた可能性があります。
- コンテキストの自動認識: ランタイムが、システムコールが発行されたゴルーチンのコンテキストを自動的に認識し、
0x8000
のような明示的なフラグなしでもM:Nスケジューリングの要件を満たすようになった。 - Plan 9とのより深い統合: Plan 9のシステムコールインターフェースをより直接的に利用できるようになり、Go固有の「仮定」を減らすことで、コードの複雑性を低減し、保守性を向上させた。
- スケジューラの改善: Goのスケジューラ自体が進化し、システムコール処理における特定のマーカーへの依存がなくなった。
この変更は、Goランタイムが特定のOS環境(この場合はPlan 9)に特化した仮定を減らし、より抽象的で汎用的な設計へと移行していることを示しており、Goのクロスプラットフォーム対応能力とコードのクリーンさを向上させる上で重要な意味を持ちます。
関連リンク
- Go言語の公式ウェブサイト: https://golang.org/
- Plan 9 from Bell Labs: https://9p.io/plan9/
- GoのM:Nスケジューリングに関する解説 (Goスケジューラ): https://go.dev/doc/articles/go_scheduler.html (英語)
参考にした情報源リンク
- Go runtime source code (特に
src/pkg/syscall/asm_plan9_amd64.s
の変更履歴) - Go言語のM:Nスケジューリングに関するドキュメントや記事
- Plan 9のシステムコール規約に関する情報
- x86-64アセンブリ言語のレジスタと命令に関する資料
- Web検索: "Go runtime NxM Plan 9 syscall 0x8000 AX", "Go scheduler Plan 9"