[インデックス 17731] ファイルの概要
このコミットは、GoランタイムのWindows固有のシステムコール関連ファイルである src/pkg/runtime/syscall_windows.goc
に変更を加えています。具体的には、syscall.NewCallbackCDecl
関数の定義をコメントアウトし、その機能を一時的に無効化しています。
コミット
commit 4216203bcf8b46ee874d4f5a637891c34ae9d7ca
Author: Russ Cox <rsc@golang.org>
Date: Wed Oct 2 21:39:45 2013 -0400
runtime: remove syscall.NewCallbackCDecl on Windows
It is not possible to use (there is no declaration in package syscall),
and no one seems to care.
Alex Brainman may bring this back properly for Go 1.3.
Fixes #6338.
R=golang-dev, r, alex.brainman
CC=golang-dev
https://golang.org/cl/14287043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/4216203bcf8b46ee874d4f5a637891c34ae9d7ca
元コミット内容
GoランタイムからWindowsにおける syscall.NewCallbackCDecl
を削除します。
この関数は使用不可能であり(syscall
パッケージに宣言がないため)、誰も関心を示していないようです。
Alex BrainmanがGo 1.3でこれを適切に復活させる可能性があります。
Issue #6338 を修正します。
変更の背景
このコミットの主な背景は、syscall.NewCallbackCDecl
関数がGoの syscall
パッケージ内で適切に宣言されておらず、結果として利用できない状態であったことです。加えて、この機能に対するユーザーからの需要や関心が低いと判断されたため、一時的に削除されることになりました。
コミットメッセージには「Alex Brainman may bring this back properly for Go 1.3.」とあり、これは将来的にこの機能がより適切に実装され、Go 1.3で再導入される可能性が示唆されています。これは、単なる不要なコードの削除ではなく、将来的な改善を見据えた一時的な措置であることを意味します。
また、「Fixes #6338」とあることから、このコミットが特定のバグや問題(Issue 6338)を解決する目的も持っていたことがわかります。
前提知識の解説
1. Goの syscall
パッケージと外部関数インターフェース (FFI)
Go言語の syscall
パッケージは、オペレーティングシステムが提供する低レベルなプリミティブ(システムコール)へのアクセスを提供します。Windows環境においては、Win32 APIなどのネイティブなC言語ベースのライブラリと連携するために、GoからCの関数を呼び出したり、CのコードからGoの関数をコールバックとして呼び出したりする機能が必要になります。このような異なる言語間の連携を可能にする仕組みを外部関数インターフェース (FFI: Foreign Function Interface) と呼びます。
2. コールバック関数
コールバック関数とは、ある関数に引数として渡され、その関数内で特定のイベントが発生した際に呼び出される関数のことです。Windowsプログラミングでは、GUIイベント処理、非同期I/O、タイマー処理など、様々な場面でコールバックが利用されます。Goの関数をWindows APIにコールバックとして登録する場合、Goの関数ポインタをWindowsが理解できる形式(C言語の関数ポインタ)に変換する必要があります。
3. syscall.NewCallback
と syscall.NewCallbackCDecl
Goの syscall
パッケージには、Goの関数をC言語の関数ポインタに変換するための NewCallback
関数が存在します。これは、Goの関数をWindows APIが期待する形式(通常は stdcall
呼び出し規約)に変換するために使用されます。
一方、syscall.NewCallbackCDecl
は、Goの関数を cdecl
呼び出し規約に従うC言語の関数ポインタに変換することを意図した関数です。
4. 呼び出し規約 (Calling Convention)
呼び出し規約とは、関数が呼び出される際に、引数がどのようにスタックに積まれ、誰がスタックをクリーンアップするか、戻り値がどのように返されるかなどを定義する取り決めです。Windows環境では主に以下の2つの呼び出し規約がよく使われます。
stdcall
(Standard Call):- Windows API関数の多くで採用されている標準的な呼び出し規約です。
- 引数は右から左へスタックに積まれます。
- 呼び出された関数(callee)がスタックをクリーンアップします。
- 可変長引数を持つ関数には使用できません。
cdecl
(C Declaration):- C/C++言語のデフォルトの呼び出し規約です。
- 引数は右から左へスタックに積まれます。
- 呼び出し元(caller)がスタックをクリーンアップします。
- 可変長引数を持つ関数に使用できます。
GoのランタイムがWindows APIと連携する際には、これらの呼び出し規約を正しく扱う必要があります。NewCallback
は通常 stdcall
を、NewCallbackCDecl
は cdecl
を扱うために設計されていました。
技術的詳細
このコミットは、GoランタイムのWindows固有のコールバックメカニズムに関するものです。syscall.NewCallbackCDecl
は、Goの関数をC言語の cdecl
呼び出し規約に準拠したコールバック関数ポインタとしてエクスポートすることを目的としていました。しかし、コミットメッセージが示すように、この関数は syscall
パッケージ内で適切に宣言されていなかったため、実質的に使用不可能でした。
Goの syscall
パッケージは、OSの低レベルな機能にアクセスするためのインターフェースを提供しますが、その実装はOSごとに異なります。Windowsの場合、GoのランタイムはWin32 APIと連携するために、Goの関数をCの関数ポインタとして公開するメカニズムを必要とします。runtime·compilecallback
は、Goの関数をコンパイルして、Cのコードから呼び出し可能なエントリポイントを生成するランタイム内部関数です。この関数は、引数 true
または false
を取ることで、それぞれ stdcall
または cdecl
呼び出し規約に対応するコールバックを生成するように設計されていました。
syscall.NewCallbackCDecl
が削除された技術的な理由は、syscall
パッケージにその宣言が存在しなかったため、Goのユーザーコードからこの関数を呼び出すことができなかった点にあります。つまり、ランタイム内部にはその機能の実装(runtime·compilecallback
を false
で呼び出す部分)が存在していたものの、外部に公開されていなかったため、デッドコードとなっていたわけです。
この削除は、Goのランタイムが不要なコードを整理し、メンテナンス性を向上させるための措置と見なせます。また、cdecl
呼び出し規約のコールバックがGoのWindowsアプリケーション開発においてあまり必要とされていなかったことも、削除の判断に影響したと考えられます。多くのWindows APIは stdcall
を使用しており、NewCallback
で十分なケースが多かったのでしょう。
コミットメッセージにある「Alex Brainman may bring this back properly for Go 1.3.」という記述は、この機能自体が完全に不要になったわけではなく、将来的に必要性が生じた場合、より堅牢で適切な形で再導入される可能性を示唆しています。これは、Goの開発プロセスが、必要に応じて機能を一時的に削除し、より良い設計で再導入するというアプローチを取ることがあることを示しています。
コアとなるコードの変更箇所
変更は src/pkg/runtime/syscall_windows.goc
ファイルで行われています。
--- a/src/pkg/runtime/syscall_windows.goc
+++ b/src/pkg/runtime/syscall_windows.goc
@@ -40,9 +40,14 @@ func NewCallback(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, true);
}\n
+/*
+ * If this is needed, uncomment here and add a declaration in package syscall
+ * next to the NewCallback declaration.
+ *
func NewCallbackCDecl(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, false);
}\n
+ */
func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
WinCall c;
具体的には、func NewCallbackCDecl(fn Eface) (code uintptr)
の定義全体がC言語のコメントブロック /* ... */
で囲まれ、コメントアウトされています。
コアとなるコードの解説
コメントアウトされた NewCallbackCDecl
関数は、以下のような構造をしていました。
func NewCallbackCDecl(fn Eface) (code uintptr) {
code = (uintptr)runtime·compilecallback(fn, false);
}
この関数は、Goの Eface
型(インターフェース値)として渡された関数 fn
を、runtime·compilecallback
という内部ランタイム関数に渡しています。runtime·compilecallback
は、Goの関数をC言語から呼び出し可能な形式にコンパイルし、そのエントリポイントのアドレス(uintptr
型)を返します。
ここで重要なのは、runtime·compilecallback
の第二引数に false
が渡されている点です。この false
は、生成されるコールバックが cdecl
呼び出し規約に従うことを示していました。対照的に、NewCallback
関数では true
が渡され、stdcall
呼び出し規約のコールバックを生成します。
このコミットでは、NewCallbackCDecl
関数全体がコメントアウトされました。これは、この関数が syscall
パッケージで宣言されていなかったため、外部から呼び出すことができず、実質的にデッドコードとなっていたためです。
コメントブロックの冒頭には、以下のコメントが追加されています。
/*
* If this is needed, uncomment here and add a declaration in package syscall
* next to the NewCallback declaration.
*
このコメントは、将来的に NewCallbackCDecl
が必要になった場合、この部分のコメントを解除し、同時に syscall
パッケージ内の NewCallback
の宣言の隣に NewCallbackCDecl
の宣言を追加する必要があることを明確に指示しています。これは、コードの意図を明確にし、将来的な再導入の際のガイドラインを提供するためのものです。
この変更により、GoのWindowsランタイムは cdecl
呼び出し規約のコールバックを直接生成する機能を一時的に失いましたが、必要に応じて容易に復活させられるようになっています。
関連リンク
- Go Change-Id:
I2111111111111111111111111111111111111111
(Go CL 14287043): https://golang.org/cl/14287043 - Go Issue #6338: コミットメッセージには
Fixes #6338
と記載されていますが、公開されているGoのIssueトラッカーでこの番号のIssueを直接見つけることはできませんでした。これは、内部的なトラッキング番号であるか、あるいは非常に古い、または非公開のIssueである可能性があります。
参考にした情報源リンク
syscall.NewCallbackCDecl
の目的とcdecl
呼び出し規約に関する情報:cdecl
呼び出し規約の詳細:- GoとWindows APIの連携に関する一般的な情報:
- Go Issue #6338の検索結果(関連するCPUモデルについて言及):