[インデックス 17507] ファイルの概要
このコミットは、GoランタイムがDragonFly BSD上でビルドできなくなっていた問題を修正するものです。具体的には、DragonFly BSD固有のメモリ管理関数(SysAlloc
, SysFree
, SysMap
)が、Goランタイムの新しいメモリ統計システムと連携するように更新されています。これにより、メモリ統計の更新がより正確かつ安全に行われるようになります。
コミット
commit 3b089179c4779c09becd395634b0a31f376865f1
Author: Joel Sing <jsing@google.com>
Date: Mon Sep 9 08:48:06 2013 -0700
runtime: unbreak build on dragonfly
Update dragonfly memory functions to work with new memory statistics.
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/13615043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3b089179c4779c09becd395634b0a31f376865f1
元コミット内容
runtime: unbreak build on dragonfly Update dragonfly memory functions to work with new memory statistics.
変更の背景
このコミットの背景には、Goランタイムにおけるメモリ統計の管理方法の変更があります。以前のバージョンでは、mstats.sys
というグローバル変数に直接メモリ使用量の統計を記録していました。しかし、Goランタイムの進化に伴い、より粒度の高い、あるいはより安全なメモリ統計の収集メカニズムが導入されたと考えられます。
この「新しいメモリ統計」システムへの移行により、mstats.sys
への直接的な加算・減算ではなく、uint64 *stat
というポインタを介して統計を更新する方式が採用されました。これは、複数のゴルーチンからの同時アクセスに対する安全性を高めるため、あるいは異なる種類のメモリ統計をより柔軟に管理するための方針変更であると推測されます。
DragonFly BSDは、Goがサポートするオペレーティングシステムの一つですが、このメモリ統計システムの変更がsrc/pkg/runtime/mem_dragonfly.c
内のメモリ管理関数(SysAlloc
, SysFree
, SysMap
)に適切に反映されていなかったため、ビルドが失敗する状態になっていました。このコミットは、そのビルドの破損を修正し、DragonFly BSD上でもGoランタイムが正しく動作し、メモリ統計が適切に収集されるようにするためのものです。
前提知識の解説
- Goランタイム (Go Runtime): Goプログラムの実行を管理する低レベルのシステムです。ガベージコレクション、スケジューリング、メモリ管理など、Go言語の並行処理や効率的な実行を支える重要な機能を提供します。
- DragonFly BSD: FreeBSDからフォークしたオープンソースのUnix系オペレーティングシステムです。Go言語は、Linux、macOS、Windowsなどと同様に、DragonFly BSDも公式にサポートしています。
mmap
(memory map): Unix系システムコールの一つで、ファイルやデバイスをプロセスのアドレス空間にマッピングするために使用されます。メモリを確保する際にも、匿名メモリマッピング(ファイルに関連付けないメモリ領域)として利用されます。nil
: C言語におけるNULLポインタに相当し、システムが適切なアドレスを選択することを意味します。PROT_READ | PROT_WRITE
: マッピングされたメモリ領域が読み取りと書き込みの両方でアクセス可能であることを示します。MAP_ANON | MAP_PRIVATE
: 匿名(ファイルに関連付けられていない)かつプライベート(他のプロセスと共有されない)なメモリマッピングを作成することを示します。-1
: ファイルディスクリプタ。匿名マッピングの場合は-1を指定します。0
: オフセット。匿名マッピングの場合は0を指定します。
munmap
(memory unmap):mmap
でマッピングされたメモリ領域をアンマッピング(解放)するためのシステムコールです。uintptr
: ポインタを保持できる符号なし整数型です。Goランタイムの低レベルコードで、アドレスやサイズを表現するのに使われます。uint64
: 64ビットの符号なし整数型です。runtime·xadd64
: Goランタイム内部で使用されるアトミック操作関数の一つです。xadd
は「exchange and add」の略で、指定されたメモリ位置の値にアトミックに値を加算し、その結果を返す(あるいは元の値を返す)操作を行います。ここでは、uint64
型のポインタが指す値に対してアトミックな加算(または減算)を行います。これにより、複数のCPUコアやゴルーチンから同時にアクセスされても、データの整合性が保たれます。mstats
: Goランタイムのメモリ統計情報が格納される構造体です。mstats.sys
は、システムから取得したメモリの総量(システムメモリ)を追跡するために使用されます。
技術的詳細
このコミットの主要な変更点は、Goランタイムのメモリ管理関数であるruntime·SysAlloc
、runtime·SysFree
、runtime·SysMap
のシグネチャと実装の変更です。
以前のバージョンでは、これらの関数は直接mstats.sys
グローバル変数を更新していました。例えば、runtime·SysAlloc
は確保したメモリサイズをmstats.sys
に加算し、runtime·SysFree
は解放したメモリサイズをmstats.sys
から減算していました。
// 変更前 (SysAllocの例)
void*
runtime·SysAlloc(uintptr n)
{
void *v;
mstats.sys += n; // 直接mstats.sysを更新
v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
// ...
return v;
}
このコミットでは、これらの関数にuint64 *stat
という新しい引数が追加されました。このstat
ポインタは、更新すべきメモリ統計カウンタを指します。そして、mstats.sys
への直接的なアクセスは削除され、代わりにruntime·xadd64(stat, n)
(またはruntime·xadd64(stat, -(uint64)n)
)が使用されるようになりました。
// 変更後 (SysAllocの例)
void*
runtime·SysAlloc(uintptr n, uint64 *stat) // 新しい引数: stat
{
void *v;
// mstats.sys += n; // 削除
v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
if(v < (void*)4096)
return nil;
runtime·xadd64(stat, n); // アトミック操作でstatが指す値を更新
return v;
}
この変更の技術的な意味合いは以下の通りです。
- アトミック操作による安全性向上:
mstats.sys
への直接アクセスは、複数のゴルーチンが同時にメモリを確保・解放しようとした場合に競合状態(race condition)を引き起こす可能性がありました。runtime·xadd64
はアトミックな操作を提供するため、このような競合状態を防ぎ、メモリ統計の整合性を保証します。 - 抽象化と柔軟性:
stat
ポインタを導入することで、メモリ統計の更新ロジックがより抽象化されました。これにより、SysAlloc
などの関数は、どの特定の統計カウンタを更新すべきかを知る必要がなくなり、呼び出し元が適切なカウンタを渡す責任を持つようになります。これは、将来的に異なる種類のメモリ統計(例えば、ヒープメモリ、スタックメモリなど)をより細かく追跡する際に、コードの変更を最小限に抑えることにつながります。 - ビルドの修正: DragonFly BSDのビルドが壊れていたのは、おそらくGoランタイムの他の部分で、これらのメモリ管理関数を呼び出す際に
stat
引数を渡すように変更されたにもかかわらず、mem_dragonfly.c
内の関数シグネチャが更新されていなかったためと考えられます。このコミットは、シグネチャを一致させることでビルドエラーを解消しました。
コアとなるコードの変更箇所
diff --git a/src/pkg/runtime/mem_dragonfly.c b/src/pkg/runtime/mem_dragonfly.c
index cc45cc96c1..025b62ea67 100644
--- a/src/pkg/runtime/mem_dragonfly.c
+++ b/src/pkg/runtime/mem_dragonfly.c
@@ -14,14 +14,14 @@ enum
};
void*
-runtime·SysAlloc(uintptr n)\n+runtime·SysAlloc(uintptr n, uint64 *stat)
{\n void *v;\n \n-\tmstats.sys += n;\n \tv = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);\n \tif(v < (void*)4096)\n \t\treturn nil;\n+\truntime·xadd64(stat, n);\n \treturn v;\n }\n \n@@ -39,9 +39,9 @@ runtime·SysUsed(void *v, uintptr n)\n }\n \n void\n-runtime·SysFree(void *v, uintptr n)\n+runtime·SysFree(void *v, uintptr n, uint64 *stat)
{\n-\tmstats.sys -= n;\n+\truntime·xadd64(stat, -(uint64)n);\n \truntime·munmap(v, n);\n }\n \n@@ -63,11 +63,11 @@ runtime·SysReserve(void *v, uintptr n)\n }\n \n void\n-runtime·SysMap(void *v, uintptr n)\n+runtime·SysMap(void *v, uintptr n, uint64 *stat)
{\n void *p;\n \n-\tmstats.sys += n;\n+\truntime·xadd64(stat, n);\n \n \t// On 64-bit, we don\'t actually have v reserved, so tread carefully.\n \tif(sizeof(void*) == 8) {\n```
## コアとなるコードの解説
変更は`src/pkg/runtime/mem_dragonfly.c`ファイル内の以下の3つの関数に集中しています。
1. **`runtime·SysAlloc(uintptr n)` から `runtime·SysAlloc(uintptr n, uint64 *stat)` へ**
* **変更点**: 関数シグネチャに`uint64 *stat`という新しい引数が追加されました。
* **削除された行**: `mstats.sys += n;`
* **追加された行**: `runtime·xadd64(stat, n);`
* **解説**: メモリをシステムから確保する関数です。以前は確保したメモリサイズ`n`を直接`mstats.sys`に加算していましたが、変更後は`stat`ポインタが指すメモリ統計カウンタに`n`をアトミックに加算するようになりました。これにより、メモリ確保時のシステムメモリ統計の更新が、より安全かつ汎用的な方法で行われます。
2. **`runtime·SysFree(void *v, uintptr n)` から `runtime·SysFree(void *v, uintptr n, uint64 *stat)` へ**
* **変更点**: 関数シグネチャに`uint64 *stat`という新しい引数が追加されました。
* **削除された行**: `mstats.sys -= n;`
* **追加された行**: `runtime·xadd64(stat, -(uint64)n);`
* **解説**: システムにメモリを解放する関数です。以前は解放したメモリサイズ`n`を直接`mstats.sys`から減算していましたが、変更後は`stat`ポインタが指すメモリ統計カウンタから`n`をアトミックに減算するようになりました。これにより、メモリ解放時のシステムメモリ統計の更新も、安全かつ汎用的な方法で行われます。
3. **`runtime·SysMap(void *v, uintptr n)` から `runtime·SysMap(void *v, uintptr n, uint64 *stat)` へ**
* **変更点**: 関数シグネチャに`uint64 *stat`という新しい引数が追加されました。
* **削除された行**: `mstats.sys += n;`
* **追加された行**: `runtime·xadd64(stat, n);`
* **解説**: 予約されたメモリ領域を実際にマッピングする関数です。以前はマッピングされたメモリサイズ`n`を直接`mstats.sys`に加算していましたが、変更後は`stat`ポインタが指すメモリ統計カウンタに`n`をアトミックに加算するようになりました。これは、`SysAlloc`と同様に、メモリマッピング時のシステムメモリ統計の更新を安全に行うための変更です。
これらの変更は、Goランタイム全体のメモリ統計収集メカニズムの統一と、並行処理環境下でのデータ整合性確保に向けた重要なステップを示しています。
## 関連リンク
* Go CL 13615043: [https://golang.org/cl/13615043](https://golang.org/cl/13615043)
## 参考にした情報源リンク
* Go言語の公式ドキュメント (Go Runtime, Memory Managementに関するセクション)
* Unix/Linux man pages (mmap, munmap)
* アトミック操作に関する一般的な情報 (xadd命令など)
* DragonFly BSDのドキュメント (必要に応じて)
* Goのソースコード (runtimeパッケージの他のファイル、特にメモリ統計関連のコード)
* GoのメーリングリストやIssueトラッカー (関連する議論や背景情報)