[インデックス 12046] ファイルの概要
このコミットは、Go言語のruntime
パッケージのAPIを整理し、特定の低レベル関数を公開APIから削除することを目的としています。具体的には、メモリ割り当て/解放に関連するAlloc
、Free
、Lookup
関数と、セマフォ操作に関連するSemacquire
、Semrelease
関数が対象です。これらの関数は、Goの内部実装やテストでのみ使用されるべきものであり、外部のユーザーが直接利用することを意図していませんでした。この変更により、runtime
パッケージの公開APIがよりクリーンになり、Goの同期プリミティブ(sync
パッケージ)がこれらの内部関数をより適切に利用するようになります。
コミット
commit 03f2289f7e3b419df36cdf97f4c49911c56b7b66
Author: Russ Cox <rsc@golang.org>
Date: Sun Feb 19 00:11:44 2012 -0500
runtime: API
Delete Alloc, Free, Lookup, Semacquire, Semrelease
Fixes #2955.
R=golang-dev, r, bradfitz
CC=golang-dev
https://golang.org/cl/5675093
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/03f2289f7e3b419df36cdf97f4c49911c56b7b66
元コミット内容
このコミットの元の内容は、Goのruntime
パッケージから以下の5つの関数を削除することです。
Alloc(uintptr) *byte
Free(*byte)
Lookup(*byte) (*byte, uintptr)
Semacquire(s *uint32)
Semrelease(s *uint32)
これらの関数は、それぞれメモリ管理とセマフォ操作のための低レベルなプリミティブでした。コミットメッセージには「FOR TESTING AND DEBUGGING ONLY.」や「It is intended as a simple sleep primitive for use by the synchronization library and should not be used directly.」といったコメントが付されており、これらが公開APIとして提供されるべきではないという意図が示されています。
変更の背景
この変更の背景には、Go言語のruntime
パッケージのAPI設計の洗練があります。Goの開発チームは、ユーザーが直接操作すべきではない低レベルな内部関数を公開APIから削除し、より高レベルで安全な抽象化を提供することを目指しています。
具体的には、以下の点が背景として考えられます。
- APIのクリーンアップ:
runtime
パッケージはGoランタイムのコア機能を提供しますが、その中にはデバッグや内部実装のためにのみ必要な関数も含まれていました。これらの関数を公開APIから削除することで、ユーザーが誤って低レベルな実装詳細に依存することを防ぎ、APIの意図を明確にします。 - カプセル化の強化:
Alloc
,Free
,Lookup
はメモリ管理の、Semacquire
,Semrelease
はセマフォの低レベルな操作を提供していました。これらを内部化することで、Goのメモリ管理や並行処理の内部実装が変更されても、外部のコードに影響を与えにくくなります。 sync
パッケージとの連携:sync
パッケージはGoの並行処理の基本的なプリミティブ(Mutex, Cond, WaitGroupなど)を提供します。これらのプリミティブは内部的にセマフォを利用しており、以前はruntime.Semacquire
やruntime.Semrelease
を直接呼び出していました。このコミットでは、これらの関数をruntime_Semacquire
、runtime_Semrelease
という内部関数にリネームし、sync
パッケージが引き続きこれらを利用できるようにしつつ、外部からは見えないようにしています。- Issue #2955の解決: コミットメッセージに「Fixes #2955」とあるように、この変更は特定の課題を解決するものです。GoのIssueトラッカーにおける#2955は、Goランタイムにおける
Type
とその実装の削除、そしてreflect
パッケージの使用を推奨する変更に関連していることが示唆されています。これは、runtime
パッケージのAPIをより洗練されたものにするという、より広範な取り組みの一部であると考えられます。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念と背景知識が必要です。
-
Goランタイム (
runtime
パッケージ): Goプログラムは、Goランタイムと呼ばれる軽量な実行環境上で動作します。runtime
パッケージは、ガベージコレクション、ゴルーチン(軽量スレッド)のスケジューリング、メモリ管理、システムコールなど、Goプログラムの実行に必要な低レベルな機能を提供します。通常、開発者がこのパッケージの関数を直接呼び出すことは稀で、Goコンパイラや標準ライブラリが内部的に利用します。 -
ゴルーチンと並行処理: Goはゴルーチンと呼ばれる軽量な並行処理の仕組みを提供します。ゴルーチンはOSのスレッドよりもはるかに軽量で、数百万個を同時に実行することも可能です。ゴルーチン間の同期には、チャネルや
sync
パッケージのプリミティブが使用されます。 -
セマフォ: セマフォは、並行プログラミングにおいて共有リソースへのアクセスを制御するための同期メカニズムです。セマフォはカウンタを持ち、
acquire
(取得)操作でカウンタを減らし、release
(解放)操作でカウンタを増やします。カウンタが0の場合、acquire
操作はブロックされます。Goのsync
パッケージの多くの同期プリミティブ(例:sync.Mutex
,sync.WaitGroup
,sync.Cond
)は、内部的にセマフォのような低レベルなメカニズムを利用してゴルーチンの待機と通知を実現しています。 -
公開APIと内部API: ソフトウェアライブラリやフレームワークでは、外部のユーザーが利用できる「公開API」と、ライブラリ内部でのみ使用される「内部API」を区別することが一般的です。公開APIは安定性が求められ、互換性を維持しながら進化しますが、内部APIはライブラリの実装詳細であり、予告なく変更される可能性があります。Goでは、パッケージ名が小文字で始まる関数や変数、あるいは特定のパッケージ内でのみ使用されることを意図した関数は、慣習的に内部APIとみなされます。
-
go test
とビルドタグ (+build ignore
): Goのテストは通常、go test
コマンドで実行されます。ソースファイルに+build ignore
というビルドタグが記述されている場合、そのファイルは通常のビルドプロセスやテストプロセスから除外されます。これは、特定のファイルがGoのツールチェーンによって直接実行されることを意図していない場合(例: 内部的なテストヘルパー、コード生成スクリプトなど)に利用されます。
技術的詳細
このコミットの技術的詳細は、主にruntime
パッケージとsync
パッケージ間の依存関係の変更、および内部関数の命名規則の統一にあります。
-
runtime
パッケージからの公開API削除:src/pkg/runtime/debug.go
からAlloc
,Free
,Lookup
が削除されました。これらの関数は、Goのメモリ管理の低レベルな側面を公開していましたが、デバッグやテスト目的以外での使用は推奨されていませんでした。src/pkg/runtime/extern.go
からSemacquire
,Semrelease
が削除されました。これらはセマフォの低レベルな操作を提供し、sync
パッケージが内部的に利用していましたが、直接の利用は非推奨でした。src/pkg/runtime/malloc.goc
では、C言語で実装されていたAlloc
,Free
,Lookup
の定義が削除されました。
-
sync
パッケージへのセマフォ関数の内部化と移動:src/pkg/runtime/sema.goc
内のSemacquire
とSemrelease
関数が、それぞれruntime_Semacquire
とruntime_Semrelease
にリネームされました。- さらに重要なのは、このファイルが
package runtime
からpackage sync
に変更されたことです。これにより、セマフォの低レベルな実装がsync
パッケージの内部に移動し、runtime
パッケージの公開APIからは見えなくなりました。ただし、実際のセマフォのプリミティブは引き続きGoランタイム(C言語部分)で実装されており、runtime_Semacquire
やruntime_Semrelease
はそれらへのGo側のラッパーとして機能します。
-
sync
パッケージの変更:src/pkg/sync/cond.go
,src/pkg/sync/mutex.go
,src/pkg/sync/rwmutex.go
,src/pkg/sync/waitgroup.go
といったsync
パッケージ内のファイルから、"runtime"
のインポートが削除されました。- これらのファイル内の
runtime.Semacquire
およびruntime.Semrelease
への呼び出しが、新しく内部化されたruntime_Semacquire
およびruntime_Semrelease
への呼び出しに置き換えられました。これにより、sync
パッケージは引き続きランタイムのセマフォ機能を利用できますが、その依存関係はより明確に内部的なものとして扱われます。
-
テストファイルの移動と変更:
test/malloc*.go
のようなテストファイルがsrc/pkg/runtime/malloc*.go
に移動し、+build ignore
タグが追加されました。これは、これらのテストがGoの標準テストスイートの一部ではなく、ランタイムの内部テストとして扱われることを意味します。src/pkg/runtime/sema_test.go
がsrc/pkg/sync/runtime_sema_test.go
にリネームされ、パッケージもruntime_test
からsync_test
に変更されました。これにより、セマフォ関連のテストがsync
パッケージのテストとして適切に配置されました。また、sync
パッケージからエクスポートされたテスト用のセマフォ関数(Runtime_Semacquire
,Runtime_Semrelease
)を使用するように変更されています。
-
src/pkg/sync/runtime.go
の導入:- 新しく
src/pkg/sync/runtime.go
ファイルが追加されました。このファイルは、sync
パッケージ内でruntime_Semacquire
とruntime_Semrelease
という関数を宣言しています。これらの宣言は、実際の関数がruntime
パッケージのC言語部分で定義されていることをGoコンパイラに伝えます。これにより、sync
パッケージはこれらの内部関数を型安全に呼び出すことができます。
- 新しく
-
src/pkg/sync/export_test.go
の導入:- 新しく
src/pkg/sync/export_test.go
ファイルが追加されました。このファイルは、テスト目的でruntime_Semacquire
とruntime_Semrelease
をRuntime_Semacquire
とRuntime_Semrelease
としてエクスポートしています。これにより、sync
パッケージのテストコードが内部のセマフォ関数にアクセスできるようになります。
- 新しく
これらの変更は、Goのランタイムと標準ライブラリの間の境界をより明確にし、内部実装の詳細をカプセル化することで、将来的な変更に対する堅牢性を高めるものです。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更箇所は以下の通りです。
-
src/pkg/runtime/debug.go
:--- a/src/pkg/runtime/debug.go +++ b/src/pkg/runtime/debug.go @@ -32,18 +32,6 @@ func NumCgoCall() int64 // NumGoroutine returns the number of goroutines that currently exist. func NumGoroutine() int32 -// Alloc allocates a block of the given size. -// FOR TESTING AND DEBUGGING ONLY. -func Alloc(uintptr) *byte -// Free frees the block starting at the given pointer. -// FOR TESTING AND DEBUGGING ONLY. -func Free(*byte) -// Lookup returns the base and size of the block containing the given pointer. -// FOR TESTING AND DEBUGGING ONLY. -func Lookup(*byte) (*byte, uintptr) - // MemProfileRate controls the fraction of memory allocations // that are recorded and reported in the memory profile. // The profiler aims to sample an average of
Alloc
,Free
,Lookup
関数の定義が削除されています。 -
src/pkg/runtime/extern.go
:--- a/src/pkg/runtime/extern.go +++ b/src/pkg/runtime/extern.go @@ -68,17 +68,6 @@ func funcline_go(*Func, uintptr) (string, int) // mid returns the current os thread (m) id. func mid() uint32 -// Semacquire waits until *s > 0 and then atomically decrements it. -// It is intended as a simple sleep primitive for use by the synchronization -// library and should not be used directly. -func Semacquire(s *uint32) -// Semrelease atomically increments *s and notifies a waiting goroutine -// if one is blocked in Semacquire. -// It is intended as a simple wakeup primitive for use by the synchronization -// library and should not be used directly. -func Semrelease(s *uint32) - // SetFinalizer sets the finalizer associated with x to f. // When the garbage collector finds an unreachable block // with an associated finalizer, it clears the association and runs
Semacquire
,Semrelease
関数の定義が削除されています。 -
src/pkg/runtime/sema.goc
:--- a/src/pkg/runtime/sema.goc +++ b/src/pkg/runtime/sema.goc @@ -17,7 +17,7 @@ // See Mullender and Cox, ``Semaphores in Plan 9,''\n // http://swtch.com/semaphore.pdf -package runtime +package sync #include "runtime.h" #include "arch_GOARCH.h" @@ -169,10 +169,10 @@ runtime·semrelease(uint32 volatile *addr) runtime·ready(s->g); } -func Semacquire(addr *uint32) { +func runtime_Semacquire(addr *uint32) { runtime·semacquire(addr); } -func Semrelease(addr *uint32) { +func runtime_Semrelease(addr *uint32) { runtime·semrelease(addr); }
パッケージが
runtime
からsync
に変更され、Semacquire
とSemrelease
がruntime_Semacquire
とruntime_Semrelease
にリネームされています。 -
src/pkg/sync/runtime.go
(新規ファイル):--- /dev/null +++ b/src/pkg/sync/runtime.go @@ -0,0 +1,18 @@ +// Copyright 2012 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. + +package sync + +// defined in package runtime + +// Semacquire waits until *s > 0 and then atomically decrements it. +// It is intended as a simple sleep primitive for use by the synchronization +// library and should not be used directly. +func runtime_Semacquire(s *uint32) + +// Semrelease atomically increments *s and notifies a waiting goroutine +// if one is blocked in Semacquire. +// It is intended as a simple wakeup primitive for use by the synchronization +// library and should not be used directly. +func runtime_Semrelease(s *uint32)
sync
パッケージ内でruntime_Semacquire
とruntime_Semrelease
が宣言されています。 -
src/pkg/sync/cond.go
,src/pkg/sync/mutex.go
,src/pkg/sync/rwmutex.go
,src/pkg/sync/waitgroup.go
: これらのファイルでは、"runtime"
のインポートが削除され、runtime.Semacquire
やruntime.Semrelease
への呼び出しがruntime_Semacquire
やruntime_Semrelease
に置き換えられています。
コアとなるコードの解説
このコミットの核心は、Goのランタイムと標準ライブラリの間のインターフェースを再定義し、低レベルな内部実装の詳細を公開APIから隠蔽することにあります。
-
runtime
パッケージからの削除:Alloc
,Free
,Lookup
は、Goのメモリ管理の非常に低レベルな側面を直接操作するものでした。これらは通常、Goのガベージコレクタやアロケータによって自動的に処理されるべきであり、ユーザーが直接介入することは稀で、誤用につながる可能性がありました。同様に、Semacquire
とSemrelease
も、Goの並行処理の内部メカニズムを直接公開していました。これらの関数をruntime
パッケージの公開APIから削除することで、GoのAPIはより高レベルで抽象化されたものとなり、ユーザーはより安全で意図された方法でGoの機能を利用できるようになります。 -
sema.goc
の移動とリネーム:src/pkg/runtime/sema.goc
がpackage sync
に変更され、関数名がSemacquire
からruntime_Semacquire
、Semrelease
からruntime_Semrelease
にリネームされたことは非常に重要です。これは、セマフォの低レベルな実装が、もはやruntime
パッケージの公開部分ではなく、sync
パッケージの内部的な詳細として扱われることを意味します。runtime_
というプレフィックスは、Goの慣習として、その関数がランタイムによって提供される内部的なものであることを示唆しています。 -
sync
パッケージの適応:sync
パッケージ内のMutex
,Cond
,WaitGroup
などの同期プリミティブは、これまでruntime.Semacquire
やruntime.Semrelease
を直接呼び出してゴルーチンの待機と通知を行っていました。このコミットでは、これらの呼び出しが新しい内部関数runtime_Semacquire
とruntime_Semrelease
に切り替えられました。これにより、sync
パッケージは引き続きランタイムのセマフォ機能を利用できますが、その依存関係はより明確に内部的なものとして扱われます。src/pkg/sync/runtime.go
は、sync
パッケージがこれらの内部関数を型安全に呼び出すための「橋渡し」の役割を果たします。 -
テストの再編成: テストファイルの移動と
+build ignore
タグの追加は、これらのテストがGoのランタイムの内部的な動作を検証するためのものであり、一般的なGoプログラムのテストとは異なる性質を持つことを明確にしています。また、sync
パッケージのテストが内部のセマフォ関数にアクセスできるようにexport_test.go
が導入されたことも、テストの分離と内部APIへのアクセス制御のバランスを示しています。
全体として、このコミットはGoの内部アーキテクチャの洗練と、公開APIの堅牢性および使いやすさの向上を目的としたものです。低レベルな詳細をカプセル化し、高レベルな抽象化を通じて機能を提供することで、Goはより安定した開発体験を提供し、将来的なランタイムの変更にも柔軟に対応できるようになります。
関連リンク
- Go Issue #2955: https://github.com/golang/go/issues/2955 (このコミットが解決したとされるIssue)
- Go Change-Id 5675093: https://golang.org/cl/5675093 (このコミットのGoコードレビューページ)
参考にした情報源リンク
- Go言語の公式ドキュメント:
runtime
パッケージ,sync
パッケージ - Go言語のソースコード
- Go言語のIssueトラッカー
- Go言語のコードレビューシステム (Gerrit)
- セマフォに関する一般的な情報(並行プログラミングの概念)
- Goのビルドタグに関する情報 (
+build ignore
)