[インデックス 11531] ファイルの概要
このコミットは、Go言語のランタイムが利用するlibmach
ライブラリに、Plan 9オペレーティングシステム向けのスタブ(stub)実装を追加するものです。具体的には、src/libmach/plan9.c
という新しいファイルが作成され、Plan 9環境でプロセス制御やスレッド情報取得、時間操作などを行うための関数が、一時的に未実装であることを示すsysfatal
呼び出しを含む形で定義されています。
コミット
libmach: add stubs for Plan 9
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5576080
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/82555d7b40c9523504e5eec418022a254b6b50ae
元コミット内容
commit 82555d7b40c9523504e5eec418022a254b6b50ae
Author: Anthony Martin <ality@pbrane.org>
Date: Tue Jan 31 18:13:17 2012 -0800
libmach: add stubs for Plan 9
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5576080
---
src/libmach/plan9.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 72 insertions(+)
diff --git a/src/libmach/plan9.c b/src/libmach/plan9.c
new file mode 100644
index 0000000000..59e2649d0a
--- /dev/null
+++ b/src/libmach/plan9.c
@@ -0,0 +1,72 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>\n#include <bio.h>\n#include <mach.h>\n+\n+int\n+ctlproc(int pid, char *msg)\n+{\n+\tUSED(pid);\n+\tUSED(msg);\n+\n+\tsysfatal(\"ctlproc unimplemented on Plan 9\");\n+\treturn -1;\n+}\n+\n+char*\n+proctextfile(int pid)\n+{\n+\tUSED(pid);\n+\n+\tsysfatal(\"proctextfile unimplemented on Plan 9\");\n+\treturn nil;\n+}\n+\n+char*\n+procstatus(int pid)\n+{\n+\tUSED(pid);\n+\n+\tsysfatal(\"procstatus unimplemented on Plan 9\");\n+\treturn nil;\n+}\n+\n+Map*\n+attachproc(int pid, Fhdr *fp)\n+{\n+\tUSED(pid);\n+\tUSED(fp);\n+\n+\tsysfatal(\"attachproc unimplemented on Plan 9\");\n+\treturn nil;\n+}\n+\n+void\n+detachproc(Map *m)\n+{\n+\tUSED(m);\n+\n+\tsysfatal(\"detachproc unimplemented on Plan 9\");\n+}\n+\n+int\n+procthreadpids(int pid, int *p, int np)\n+{\n+\tUSED(pid);\n+\tUSED(p);\n+\tUSED(np);\n+\n+\tsysfatal(\"procthreadpids unimplemented on Plan 9\");\n+\treturn -1;\n+}\n+\n+int \n+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)\n+{\n+\tUSED(rqtp);\n+\tUSED(rmtp);\n+\n+\tsysfatal(\"nanosleep unimplemented on Plan 9\");\n+\treturn -1;\n+}\n```
## 変更の背景
このコミットは、Go言語がPlan 9オペレーティングシステムをサポートする過程の一部として行われました。Go言語は、その設計思想や開発者のルーツがBell LabsのPlan 9に深く関連しているため、初期からPlan 9への移植が重要な目標の一つでした。
`libmach`は、Goのデバッガやプロファイラなどのツールが、実行中のプロセス(特にGoプログラム)のメモリレイアウト、シンボル情報、スレッド状態などを検査するために使用する低レベルのライブラリです。これらのツールは、OS固有のシステムコールやデータ構造に依存するため、各OSプラットフォーム向けに`libmach`の実装が必要となります。
このコミットの時点では、Plan 9向けの`libmach`の完全な実装はまだ準備ができていませんでした。しかし、ビルドシステムや他のコンポーネントがPlan 9環境でコンパイルできるようにするためには、`libmach`が提供する特定の関数が存在している必要がありました。そこで、一時的な措置として、これらの関数を「スタブ」として追加し、呼び出された場合には未実装であることを示すエラーを発生させるようにしました。これにより、Plan 9向けのGoのビルドが進行できるようになり、将来的にこれらの関数が本格的に実装されるまでのプレースホルダーとしての役割を果たしました。
## 前提知識の解説
### Plan 9 from Bell Labs
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Unixの後継として設計され、Unixの「すべてはファイルである」という哲学をさらに推し進め、「すべてはファイルシステムである」という概念を導入しました。ネットワーク上のすべてのリソース(プロセス、デバイス、サービスなど)がファイルシステムとして表現され、標準的なファイル操作(`open`, `read`, `write`, `close`)を通じてアクセスできるのが特徴です。
Plan 9は、そのクリーンな設計、UTF-8の採用、`9P`プロトコルによる分散コンピューティングの実現など、多くの革新的なアイデアを導入しましたが、広く普及することはありませんでした。しかし、その設計思想は、Go言語を含む多くの現代のシステムやプログラミング言語に影響を与えています。
### libmach
`libmach`は、Go言語のツールチェインの一部として存在するライブラリで、主にデバッガ(`gdb`など)やプロファイラが、実行中のGoプログラムの内部状態を検査するために使用します。これは、特定のプロセスのアドレス空間を読み取ったり、レジスタの状態を取得したり、スレッド情報を列挙したりといった、OSに依存する低レベルな操作を抽象化する役割を担っています。
`libmach`は、各オペレーティングシステム(Linux, macOS, Windows, Plan 9など)向けに異なる実装を持ち、それぞれのOSのプロセス管理やメモリ管理のメカニズムに適応しています。
### スタブ (Stub)
プログラミングにおけるスタブとは、まだ完全に実装されていない関数やモジュールのための、最小限の機能を持つプレースホルダーのことです。スタブは通常、以下のような目的で使用されます。
1. **ビルドの成功**: 開発中のシステムで、まだ実装されていない部分に依存するコードがある場合、スタブを置くことでコンパイルエラーを防ぎ、全体のビルドを成功させることができます。
2. **インターフェースの定義**: 将来的に実装される機能のAPI(関数名、引数、戻り値など)を事前に定義し、他の開発者がそのAPIに依存するコードを書き始めることを可能にします。
3. **エラーハンドリング**: 未実装のスタブが呼び出された場合に、適切なエラーメッセージを出力したり、プログラムを終了させたりすることで、開発者に問題の発生を知らせます。
このコミットでは、Plan 9向けの`libmach`関数がまだ実装されていないため、`sysfatal`(Plan 9における致命的なエラーを報告する関数)を呼び出すスタブが用意されています。これにより、GoのツールチェインがPlan 9上でビルドできるようになり、将来の完全な実装への道が開かれました。
## 技術的詳細
このコミットで追加された`src/libmach/plan9.c`ファイルは、Plan 9環境における`libmach`の基本的なインターフェースを定義していますが、その実装はすべてスタブとなっています。各関数は、対応する操作がPlan 9上で未実装であることを示すメッセージとともに`sysfatal`を呼び出し、プログラムを終了させます。
含まれる関数は以下の通りです。
* `ctlproc(int pid, char *msg)`: プロセスを制御するための関数。デバッガがプロセスを一時停止したり、再開したりする際に使用される可能性があります。
* `proctextfile(int pid)`: プロセスの実行可能ファイル(テキストセグメント)のパスを取得する関数。
* `procstatus(int pid)`: プロセスの状態(実行中、停止中など)に関する情報を取得する関数。
* `attachproc(int pid, Fhdr *fp)`: 特定のプロセスにアタッチし、そのメモリ空間を検査するためのマップ(`Map`構造体)を確立する関数。デバッガがプロセスのメモリを読み書きする際に必要です。
* `detachproc(Map *m)`: `attachproc`で確立したプロセスへのアタッチを解除する関数。
* `procthreadpids(int pid, int *p, int np)`: 特定のプロセスに属するスレッドのPID(プロセスID)のリストを取得する関数。GoのランタイムはゴルーチンをOSスレッドにマッピングするため、デバッガがスレッド情報を扱う際に重要です。
* `nanosleep(const struct timespec *rqtp, struct timespec *rmtp)`: ナノ秒単位でスリープする関数。これはPOSIX標準の関数であり、Plan 9には直接対応するシステムコールがないため、スタブとして追加されています。Goのランタイムやライブラリが時間精度を要求する際に使用される可能性があります。
これらの関数は、GoのデバッガやプロファイラがPlan 9上で動作するために不可欠な低レベルのOSインタラクションを抽象化するものです。スタブ実装は、これらの機能がまだ利用できないことを明確に示しつつ、コンパイルエラーを防ぐ役割を果たします。
コードには`USED(variable);`というマクロが多用されています。これは、Plan 9のCコンパイラ(`8c`, `6c`など)が、使用されていない引数や変数を警告するのを抑制するための慣用的な方法です。引数が実際には使用されない(`sysfatal`を呼び出すだけなので)スタブ関数において、このマクロはコンパイラの警告を回避するために必要となります。
## コアとなるコードの変更箇所
このコミットでは、`src/libmach/plan9.c`という新しいファイルが追加されています。
```diff
--- /dev/null
+++ b/src/libmach/plan9.c
@@ -0,0 +1,72 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+ USED(pid);
+ USED(msg);
+
+ sysfatal("ctlproc unimplemented on Plan 9");
+ return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+ USED(pid);
+
+ sysfatal("proctextfile unimplemented on Plan 9");
+ return nil;
+}
+
+char*
+procstatus(int pid)
+{
+ USED(pid);
+
+ sysfatal("procstatus unimplemented on Plan 9");
+ return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ USED(pid);
+ USED(fp);
+
+ sysfatal("attachproc unimplemented on Plan 9");
+ return nil;
+}
+
+void
+detachproc(Map *m)
+{
+ USED(m);
+
+ sysfatal("detachproc unimplemented on Plan 9");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ USED(pid);
+ USED(p);
+ USED(np);
+
+ sysfatal("procthreadpids unimplemented on Plan 9");
+ return -1;
+}
+
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ USED(rqtp);
+ USED(rmtp);
+
+ sysfatal("nanosleep unimplemented on Plan 9");
+ return -1;
+}
コアとなるコードの解説
追加されたplan9.c
ファイルは、Plan 9環境でGoのlibmach
が依存するであろう関数群のスタブ実装を含んでいます。
-
ヘッダーファイルのインクルード:
<u.h>
,<libc.h>
,<bio.h>
: これらはPlan 9の標準的なCライブラリのヘッダーファイルです。u.h
は基本的な型定義やユーティリティ、libc.h
は標準Cライブラリ関数、bio.h
はバッファリングされたI/Oに関連します。<mach.h>
: これはlibmach
自体が提供するヘッダーファイルで、Map
構造体など、libmach
のAPIに必要な定義が含まれています。
-
スタブ関数の定義:
- 各関数(
ctlproc
,proctextfile
,procstatus
,attachproc
,detachproc
,procthreadpids
,nanosleep
)は、それぞれのシグネチャ(引数と戻り値の型)に従って定義されています。 USED(variable);
: このマクロは、Plan 9のCコンパイラが未使用の変数や引数に対して警告を出すのを抑制するために使用されます。スタブ関数では引数が実際には使用されないため、このマクロが必須となります。sysfatal("message");
: これはPlan 9のシステムコールで、致命的なエラーを報告し、プログラムを終了させます。スタブ関数が呼び出された際に、その機能がまだ実装されていないことを明確に伝えるために使用されています。例えば、ctlproc
が呼び出されると、「ctlproc unimplemented on Plan 9
」というメッセージとともにプログラムが終了します。- 戻り値: 各関数は、その戻り値の型に応じたダミーの値(
-1
やnil
)を返しています。これは、sysfatal
が呼び出された後に到達することはないコードパスですが、コンパイラが関数の戻り値を期待するため形式的に記述されています。
- 各関数(
このコードの目的は、Plan 9環境でGoのツールチェインをビルドする際に、libmach
の依存関係を満たすことです。これにより、開発者はPlan 9向けのGoのビルドプロセスを進めることができ、後からこれらのスタブ関数を実際のPlan 9固有の実装に置き換えることが可能になります。
関連リンク
- Go Change List 5576080: https://golang.org/cl/5576080
- GitHub Commit: https://github.com/golang/go/commit/82555d7b40c9523504e5eec418022a254b6b50ae
参考にした情報源リンク
- Plan 9 from Bell Labs Official Site: https://9p.io/plan9/
- Go and Plan 9: https://go.dev/doc/go_plan9.html (Go公式ドキュメントのPlan 9に関する記述)
sysfatal
in Plan 9: https://man.cat-v.org/plan9/2/sysfatalUSED
macro in Plan 9: https://man.cat-v.org/plan9/2/usedlibmach
in Go source code (general context): https://github.com/golang/go/tree/master/src/libmach (現在のlibmach
のディレクトリ構造)nanosleep
(POSIX): https://man7.org/linux/man-pages/man2/nanosleep.2.html