Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12681] ファイルの概要

このコミットは、Go言語の標準ライブラリsrc/pkg/syscallディレクトリからpassfd_test.goというテストファイルを削除するものです。このテストファイルは、Unixドメインソケットを介したファイルディスクリプタの受け渡し機能(passfd)を検証するために使用されていました。コミットメッセージによると、Go 1.0のリリース後にsyscallパッケージにおけるテストの問題を再検討するという方針のもと、一時的に削除されました。

コミット

commit 4161dfc4feafa08870e347c5ca7da155a9790867
Author: Rob Pike <r@golang.org>
Date:   Mon Mar 19 11:12:32 2012 +1100

    syscall: delete passfd_test.go
    
    We can revisit the issue of testing in syscall after Go 1.
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/5844057

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/4161dfc4feafa08870e347c5ca7da155a9790867

元コミット内容

このコミットは、src/pkg/syscall/passfd_test.goというファイルを削除しました。このファイルは、Go言語のsyscallパッケージが提供するUnixドメインソケットを介したファイルディスクリプタの受け渡し機能(SCM_RIGHTSメッセージ)が正しく動作するかを検証するためのテストコードを含んでいました。具体的には、親プロセスが子プロセスにソケットを介してファイルディスクリプタを渡し、子プロセスがそのディスクリプタを使ってファイルの内容を読み書きできることを確認するテストでした。

変更の背景

この変更の背景には、Go言語の最初の安定版リリースであるGo 1.0の準備段階における開発方針があります。コミットメッセージ「We can revisit the issue of testing in syscall after Go 1.」が示すように、Go 1.0のリリースでは、言語と標準ライブラリの安定性と互換性の確保が最優先事項でした。

syscallパッケージは、OS固有のシステムコールをGoから直接呼び出すための低レベルなインターフェースを提供します。ファイルディスクリプタの受け渡しのような機能は、OSや環境に依存する複雑な側面を持つため、テストの安定性や移植性に課題があった可能性があります。Go 1.0のリリース前に、このような複雑なテストケースが全体の安定性を損なうリスクを避けるため、あるいはより広範なテスト戦略が確立されるまで、一時的に削除するという判断がなされたと考えられます。Go 1.0リリース後、より成熟したテストインフラや知見が蓄積された段階で、この種のテストを再導入することが計画されていました。

前提知識の解説

Go言語のsyscallパッケージ

Go言語のsyscallパッケージは、オペレーティングシステム(OS)のシステムコールに直接アクセスするための低レベルなインターフェースを提供します。これにより、GoプログラムからOSのカーネル機能(ファイル操作、プロセス管理、ネットワーク通信など)を直接呼び出すことが可能になります。osnetパッケージのような高レベルな抽象化された機能の多くは、内部でこのsyscallパッケージを利用しています。

ファイルディスクリプタ (File Descriptor, FD)

ファイルディスクリプタ(FD)は、Unix系OSにおいて、プロセスが開いているファイル、ソケット、パイプなどのI/Oリソースを識別するためにカーネルが割り当てる非負の整数値です。プロセスは、このFDを使って対応するリソースに対して読み書きなどの操作を行います。

Unixドメインソケット (Unix Domain Socket)

Unixドメインソケットは、同一ホスト上のプロセス間通信(IPC: Inter-Process Communication)のためのメカニズムです。ネットワークソケット(TCP/IPなど)とは異なり、ネットワークスタックを介さずに直接カーネル内で通信が行われるため、効率的です。Unixドメインソケットの特筆すべき機能の一つに、**ファイルディスクリプタの受け渡し(Passing File Descriptors)**があります。これは、あるプロセスが別のプロセスに、開いているファイルディスクリプタをソケットを介して安全に渡すことができる機能です。これにより、例えば特権プロセスがファイルをオープンし、そのFDを非特権プロセスに渡して操作させるといった、セキュリティやリソース管理のシナリオで利用されます。

SCM_RIGHTSメッセージ

Unixドメインソケットを介してファイルディスクリプタを渡す際に使用されるのが、SCM_RIGHTSという制御メッセージです。sendmsgシステムコールでSCM_RIGHTSを指定してFDを送信し、recvmsgシステムコールで受信します。Go言語のsyscallパッケージでは、UnixRights関数でFDのリストからSCM_RIGHTsメッセージを生成し、ParseUnixRights関数で受信したSCM_RIGHTSメッセージからFDを抽出します。

Go 1.0

Go 1.0は、2012年3月28日にリリースされたGo言語の最初の安定版です。このリリースは、Go言語の仕様と標準ライブラリのAPIを安定させ、将来のバージョンとの互換性を保証することを目的としていました。Go 1.0のリリース以降、Go言語は急速に普及し、多くのプロジェクトで利用されるようになりました。このコミットが行われたのはGo 1.0リリース直前の時期であり、安定性確保のための最終調整が行われていたことが伺えます。

技術的詳細

削除されたpassfd_test.goファイルは、TestPassFDTestPassFDChildという2つのテスト関数を含んでいました。これらは、Go言語でUnixドメインソケットを介してファイルディスクリプタを安全に受け渡す機能が正しく動作するかを検証するためのものです。

TestPassFD (親プロセス側のテスト)

この関数は、テストの親プロセスとして動作します。

  1. ソケットペアの作成: syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)を呼び出して、Unixドメインソケットのペアを作成します。これにより、親プロセスと子プロセスが通信するための双方向のソケットが用意されます。fds[0]fds[1]の2つのファイルディスクリプタが返されます。
  2. 子プロセスの起動: os/exec.Commandを使用して、現在のテストバイナリ自身を子プロセスとして起動します。この際、GO_WANT_HELPER_PROCESS=1という環境変数を設定し、TestPassFDChild関数を実行するように引数を渡します。
  3. ファイルディスクリプタの受け渡し準備: writeFile := os.NewFile(uintptr(fds[0]), "child-writes")として、ソケットペアの一方のFDをos.Fileとしてラップし、cmd.ExtraFiles = []*os.File{writeFile}を通じて子プロセスに渡します。これにより、子プロセスは親プロセスから渡されたソケットを通じて通信できるようになります。
  4. 子プロセスの実行と出力の確認: cmd.CombinedOutput()で子プロセスを実行し、その出力やエラーを確認します。
  5. ソケット接続の確立: net.FileConn(readFile)を使って、ソケットペアのもう一方のFD(親プロセス側)からnet.Connインターフェースを取得します。これは、net.UnixConn型にキャストされます。
  6. ファイルディスクリプタの受信: uc.ReadMsgUnix(buf, oob)を呼び出して、子プロセスから送信されるメッセージと制御メッセージ(oob)を受信します。このoobバッファには、子プロセスが送信したファイルディスクリプタが含まれるSCM_RIGHTSメッセージが格納されます。
  7. 受信したFDの解析:
    • syscall.ParseSocketControlMessage(oob[:oobn])で制御メッセージを解析し、syscall.SocketControlMessageのリストを取得します。
    • syscall.ParseUnixRights(&scm)で、取得した制御メッセージからファイルディスクリプタのリスト(gotFds)を抽出します。
  8. 受信したFDの検証: 抽出されたFDが期待通り1つであり、そのFDを使ってファイルの内容を読み込み、「Hello from child process!」という文字列が正しく読み取れることを検証します。

TestPassFDChild (子プロセス側のテストヘルパー)

この関数は、TestPassFDによって子プロセスとして起動された際に実行されます。

  1. ヘルパープロセスの識別: os.Getenv("GO_WANT_HELPER_PROCESS") != "1"で、自身がヘルパープロセスとして起動されたかどうかを確認します。
  2. 親プロセスから渡されたソケットの特定: 子プロセスは、親プロセスからExtraFilesを通じて渡されたソケットのファイルディスクリプタを特定します。通常はFD 3以降に割り当てられますが、Goのバグ(issue 2603)を回避するために、FD 3から10までをループしてnet.UnixConnとして開けるFDを探します。
  3. 送信するファイルの準備: ioutil.TempFileで一時ファイルを作成し、「Hello from child process!」という文字列を書き込みます。この一時ファイルのファイルディスクリプタを親プロセスに送信します。
  4. ファイルディスクリプタの送信:
    • syscall.UnixRights(int(f.Fd()))で、送信したいファイルディスクリプタからSCM_RIGHTSメッセージを生成します。
    • uc.WriteMsgUnix(dummyByte, rights, nil)を呼び出して、ダミーのデータ(dummyByte)と、生成したSCM_RIGHTSメッセージ(rights)を親プロセスに送信します。

このテストは、Go言語のsyscallパッケージが提供する低レベルな機能が、異なるプロセス間でどのように連携して動作するかを示す良い例でした。しかし、このようなテストはOSの挙動や環境に強く依存するため、Go 1.0の安定性確保の観点から、一時的に削除されたと考えられます。

コアとなるコードの変更箇所

このコミットによるコアとなるコードの変更は、以下のファイルの削除のみです。

  • src/pkg/syscall/passfd_test.go

コアとなるコードの解説

削除されたpassfd_test.goは、Go言語のsyscallパッケージにおけるファイルディスクリプタの受け渡し機能のテストを担っていました。このテストは、親プロセスと子プロセスがUnixドメインソケットを介して通信し、親プロセスが子プロセスにファイルディスクリプタを渡し、子プロセスがそのディスクリプタを使ってファイルの内容を読み書きできることを検証するものでした。

具体的には、TestPassFD関数が親プロセスとしてソケットペアを作成し、子プロセス(TestPassFDChild関数)を起動します。親プロセスはソケットの一端を子プロセスに渡し、子プロセスはもう一方のソケットを通じて親プロセスにファイルディスクリプタを送信します。親プロセスは受信したファイルディスクリプタが有効であることを確認し、そのディスクリプタを使ってファイルの内容を読み込み、期待される結果と比較します。

このテストは、syscall.Socketpairnet.FileConnnet.UnixConnReadMsgUnixWriteMsgUnixParseSocketControlMessageParseUnixRightsといったsyscallパッケージの主要な関数を組み合わせて使用しており、ファイルディスクリプタの受け渡しという高度なIPCメカニズムのGo言語での実装と利用方法を示す貴重な例でした。

削除の理由は、Go 1.0のリリースに向けた安定性確保と、syscallパッケージのテスト戦略の再検討という方針によるものです。これは、この種の低レベルなテストがOSや環境に依存しやすく、当時のGoのテストインフラでは安定したテスト実行が困難であった可能性を示唆しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のソースコード(削除されたpassfd_test.goの内容)
  • Unixドメインソケットとファイルディスクリプタの受け渡しに関する一般的な技術情報
  • Go 1.0リリースに関する情報