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

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

このコミットは、Go言語のsyscallパッケージにおけるSolarisビルドの問題を修正するものです。具体的には、Solaris環境ではsyscall.Mmapおよびsyscall.Munmapが定義されていないため、これらのシステムコールを使用するテストコードをSolarisビルドから除外するように変更されています。

コミット

commit f9b384f554143901ddf771214bfacf8041862f0c
Author: Dave Cheney <dave@cheney.net>
Date:   Wed Feb 26 07:56:41 2014 +1100

    syscall: fix solaris build
    
    Solaris does not define syscall.{Mmap,Munmap}. Move the Mmap test to a new file and exclude solaris as discussed.
    
    LGTM=aram
    R=aram, mikioh.mikioh, iant
    CC=golang-codereviews
    https://golang.org/cl/68720043

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

https://github.com/golang/go/commit/f9b384f554143901ddf771214bfacf8041862f0c

元コミット内容

このコミットの元の内容は、syscallパッケージのSolarisビルドに関する修正です。Solarisがsyscall.Mmapsyscall.Munmapを定義していないため、Mmapテストを新しいファイルに移動し、Solarisをそのテストのビルドから除外しています。

変更の背景

Go言語の標準ライブラリ、特にsyscallパッケージは、オペレーティングシステム(OS)のシステムコールをGoプログラムから直接呼び出すためのインターフェースを提供します。システムコールはOSカーネルが提供する低レベルの機能であり、メモリ管理、ファイルI/O、プロセス制御など多岐にわたります。しかし、システムコールの具体的な実装や利用可能なシステムコールの種類は、OSによって大きく異なります。

このコミットの背景には、GoのsyscallパッケージがSolarisオペレーティングシステム上でビルドされる際に発生した問題があります。syscall.Mmapsyscall.Munmapは、メモリマップドファイル(memory-mapped file)や匿名メモリ領域を扱うためのシステムコールであり、Unix系OSでは一般的に利用されます。しかし、Solarisの特定のバージョンや構成では、Goのsyscallパッケージが期待する形でこれらの関数が提供されていないか、あるいは異なるシグネチャやセマンティクスを持っている可能性がありました。

結果として、syscall_unix_test.goファイルに含まれていたTestMmap関数がSolaris環境でビルドエラーを引き起こしていました。Goのビルドシステムは、特定のOSやアーキテクチャに特化したコードをコンパイルするために「ビルドタグ(build tags)」を使用します。この問題は、TestMmapがSolarisを含むUnix系OS全般を対象とするビルドタグでコンパイルされていたために顕在化しました。

この修正は、Goのクロスプラットフォーム対応を維持しつつ、特定のOSの差異に起因するビルド問題を解決するための典型的なアプローチを示しています。

前提知識の解説

1. Go言語のsyscallパッケージ

syscallパッケージは、GoプログラムからOSのシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、Goのランタイムや標準ライブラリは、OS固有の機能にアクセスし、高性能なI/O、ネットワーク通信、プロセス管理などを実現しています。このパッケージはOSに強く依存するため、各OS(Linux, macOS, Windows, FreeBSD, Solarisなど)ごとに異なる実装を持っています。

2. mmapmunmapシステムコール

mmap(memory map)は、ファイルやデバイスのメモリ領域をプロセスのアドレス空間にマッピングするためのシステムコールです。これにより、ファイルの内容を通常のメモリとしてアクセスできるようになり、ファイルI/Oの効率化や、プロセス間通信(IPC)の手段として利用されます。 munmapは、mmapによってマッピングされたメモリ領域をアンマッピング(解放)するためのシステムコールです。

これらのシステムコールは、Unix系OSにおいてメモリ管理の重要な要素であり、特に大規模なデータ処理や、共有メモリを必要とするアプリケーションで頻繁に利用されます。

3. Go言語のビルドタグ(Build Tags)

Go言語には、特定のファイルが特定の環境でのみコンパイルされるように制御するための「ビルドタグ」という仕組みがあります。これは、ソースファイルの先頭に// +build tag_nameのようなコメント行を記述することで実現されます。例えば、// +build linuxと書かれたファイルはLinux環境でのみコンパイルされ、// +build darwin dragonfly freebsd linux netbsd openbsdと書かれたファイルはこれらのOSでのみコンパイルされます。

ビルドタグは、クロスプラットフォーム開発においてOS固有のコードを分離し、各プラットフォームに最適化されたバイナリを生成するために不可欠な機能です。

4. Solarisオペレーティングシステム

Solarisは、Sun Microsystems(現在はOracleが所有)によって開発されたUnix系のオペレーティングシステムです。高性能なサーバー環境やエンタープライズシステムで広く利用されてきました。他のUnix系OS(Linux, FreeBSDなど)と多くの共通点を持つ一方で、システムコールの実装やライブラリの提供方法には独自の差異が存在します。この差異が、Goのsyscallパッケージのような低レベルなコードで問題を引き起こすことがあります。

技術的詳細

このコミットの技術的詳細は、GoのビルドシステムとOS固有のシステムコール実装の差異をどのように吸収するかという点に集約されます。

  1. 問題の特定: syscall_unix_test.go内のTestMmap関数がSolaris環境でビルドエラーを引き起こしていました。これは、SolarisがGoのsyscallパッケージが期待するMmapおよびMunmapシステムコールを定義していないためです。

  2. 既存のビルドタグ: syscall_unix_test.goは、以下のビルドタグを持っていました。

    // +build freebsd dragonfly darwin linux netbsd openbsd solaris
    

    このタグは、このファイルがFreeBSD, Dragonfly BSD, Darwin (macOS), Linux, NetBSD, OpenBSD, そしてSolarisの各OSでコンパイルされるべきであることを示しています。TestMmapがSolarisで問題を起こすにもかかわらず、このタグによってSolarisでもコンパイル対象となっていたことが問題の根源です。

  3. 解決策:

    • テストの分離: TestMmap関数をsyscall_unix_test.goから切り離し、mmap_unix_test.goという新しいファイルに移動しました。
    • 新しいビルドタグの適用: 新しいファイルmmap_unix_test.goには、Solarisを除外したビルドタグを適用しました。
      // +build darwin dragonfly freebsd linux netbsd openbsd
      
      これにより、TestMmapはSolaris環境ではコンパイルされなくなり、ビルドエラーが解消されます。
    • 既存ファイルのビルドタグの維持: syscall_unix_test.goのビルドタグは変更されず、引き続きSolarisを含むすべての指定されたUnix系OSでコンパイルされます。これは、TestMmap以外のテスト関数はSolarisでも問題なく動作するためです。

このアプローチにより、Goのテストスイートは、mmap/munmapをサポートするプラットフォームでは引き続きこれらのシステムコールのテストを実行しつつ、サポートしない(または異なる実装を持つ)Solarisではビルドエラーを回避できるようになります。これは、Goのクロスプラットフォーム開発における一般的なパターンであり、OS固有のAPIの差異を適切に管理するための効果的な方法です。

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

このコミットでは、以下の2つのファイルが変更されています。

  1. src/pkg/syscall/mmap_unix_test.go (新規作成)

    • TestMmap関数がこのファイルに移動されました。
    • ファイルの先頭に以下のビルドタグが追加されました。
      // +build darwin dragonfly freebsd linux netbsd openbsd
      
      これにより、このテストファイルはSolarisではコンパイルされなくなります。
  2. src/pkg/syscall/syscall_unix_test.go (変更)

    • 既存のTestMmap関数がこのファイルから削除されました。
    • ファイルのビルドタグは変更されていません。

コアとなるコードの解説

src/pkg/syscall/mmap_unix_test.go (新規作成)

// Copyright 2014 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.

// +build darwin dragonfly freebsd linux netbsd openbsd

package syscall_test

import (
	"syscall"
	"testing"
)

func TestMmap(t *testing.T) {
	// syscall.Mmapを呼び出して匿名メモリ領域をマップする
	// -1: ファイルディスクリプタ (匿名マップのため無視される)
	// 0: オフセット (匿名マップのため無視される)
	// syscall.Getpagesize(): マップするサイズ (OSのページサイズ)
	// syscall.PROT_NONE: メモリ保護 (アクセス不可)
	// syscall.MAP_ANON|syscall.MAP_PRIVATE: 匿名かつプライベートなマップ
	b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
	if err != nil {
		t.Fatalf("Mmap: %v", err) // エラーが発生したらテスト失敗
	}
	// マップしたメモリ領域を解放する
	if err := syscall.Munmap(b); err != nil {
		t.Fatalf("Munmap: %v", err) // エラーが発生したらテスト失敗
	}
}

この新しいファイルは、syscall.Mmapsyscall.Munmapの基本的な機能が期待通りに動作するかを検証するテストを含んでいます。重要なのは、ファイルの先頭にある+buildタグです。このタグにより、このテストファイルはdarwin, dragonfly, freebsd, linux, netbsd, openbsdの各OSでのみコンパイルされ、Solarisではコンパイル対象から外されます。これにより、SolarisでMmapMunmapが定義されていないことによるビルドエラーが回避されます。

src/pkg/syscall/syscall_unix_test.go (変更)

--- a/src/pkg/syscall/syscall_unix_test.go
+++ b/src/pkg/syscall/syscall_unix_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build freebsd dragonfly darwin linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package syscall_test
 
@@ -77,16 +77,6 @@ func TestFcntlFlock(t *testing.T) {
 	}\n }\n \n-func TestMmap(t *testing.T) {\n-\tb, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)\n-\tif err != nil {\n-\t\tt.Fatalf(\"Mmap: %v\", err)\n-\t}\n-\tif err := syscall.Munmap(b); err != nil {\n-\t\tt.Fatalf(\"Munmap: %v\", err)\n-\t}\n-}\n-\n // TestPassFD tests passing a file descriptor over a Unix socket.\n //

このファイルからはTestMmap関数が削除されました。これにより、このファイルはSolarisを含むすべての指定されたUnix系OSで引き続きコンパイルされますが、Mmap関連のテストは含まれなくなります。この変更は、テストコードの責任を分割し、OS固有の差異をビルドタグによって適切に管理するというGoの設計思想に沿ったものです。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Unix系OSのシステムコールに関する一般的な知識
  • Goのソースコードリポジトリ
  • Gerrit上のコードレビューコメント (コミットメッセージに記載のCLリンクからアクセス可能)
  • man mmapなどのシステムコールに関するmanページ