[インデックス 18680] ファイルの概要
コミット
このコミットは、Go言語の syscall
パッケージに、macOS (OSX) 向けの mlock
, munlock
, mlockall
, munlockall
, および mprotect
システムコールを追加するものです。これにより、Goプログラムからこれらのメモリ管理関連のシステムコールを直接呼び出すことが可能になり、特定のメモリ領域のロックや保護といった低レベルな操作が行えるようになります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/08706f19b4ec98d91f08c331d43e8e8553bb30c3
元コミット内容
commit 08706f19b4ec98d91f08c331d43e8e8553bb30c3
Author: William Orr <will@worrbase.com>
Date: Thu Feb 27 10:13:41 2014 -0800
syscall: add mlock, munlock, mlockall, munlockall and mprotect to OSX
Fixes #7415
LGTM=bradfitz
R=bradfitz, iant
CC=golang-codereviews
https://golang.org/cl/68980043
変更の背景
この変更の背景には、GoプログラムがmacOS上でより低レベルなメモリ管理機能にアクセスできるようにするというニーズがありました。特に、mlock
やmprotect
といったシステムコールは、セキュリティが重要なアプリケーション(例: 暗号化キーをメモリに保持するアプリケーション)や、リアルタイムシステム、あるいは特定のパフォーマンス要件を持つアプリケーションにおいて、メモリのページングを防いだり、メモリ領域のアクセス権を変更したりするために不可欠です。
コミットメッセージにある Fixes #7415
は、この変更がGoのIssue 7415を解決したことを示しています。このIssueは、GoプログラムがmacOS上でメモリロックや保護のシステムコールを利用できないことに関するものであったと推測されます。これらのシステムコールがGoのsyscall
パッケージに統合されることで、Go開発者はOSの提供する強力なメモリ管理機能を活用し、より堅牢で高性能なアプリケーションを構築できるようになります。
前提知識の解説
1. システムコール (System Call)
システムコールは、オペレーティングシステム (OS) のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイルI/O、プロセス管理、メモリ管理、ネットワーク通信など、OSが管理するリソースへのアクセスは、直接行うことができず、必ずシステムコールを介して行われます。Go言語の syscall
パッケージは、これらのシステムコールをGoプログラムから呼び出すためのラッパーを提供します。
2. 仮想記憶 (Virtual Memory) とページング (Paging)
現代のOSは仮想記憶システムを採用しています。これは、物理メモリ(RAM)を抽象化し、各プロセスに独立した仮想アドレス空間を提供する仕組みです。仮想アドレス空間は「ページ」と呼ばれる固定サイズのブロックに分割され、これらのページは必要に応じて物理メモリ上の「ページフレーム」にマッピングされます。
ページングは、仮想記憶システムの一部であり、物理メモリが不足した場合に、使用頻度の低いメモリページをディスク(スワップ領域)に一時的に退避させ、必要になったときに再度物理メモリに読み込む(ページイン)メカニズムです。これにより、物理メモリの量よりも大きなプログラムを実行できるようになりますが、ディスクI/Oが発生するためパフォーマンスの低下を招く可能性があります。
3. mlock
, munlock
, mlockall
, munlockall
これらのシステムコールは、メモリのページングを制御するために使用されます。
mlock(addr, len)
: 指定されたアドレスaddr
からlen
バイトのメモリ領域を物理メモリにロックします。これにより、そのメモリ領域がディスクにページアウトされるのを防ぎます。これは、機密データ(例: 暗号化キー)がディスクに書き込まれるのを防ぐためや、リアルタイムアプリケーションで予測可能なレイテンシを確保するために重要です。munlock(addr, len)
:mlock
によってロックされたメモリ領域のロックを解除します。mlockall(flags)
: プロセス全体の仮想アドレス空間を物理メモリにロックします。flags
引数によって、現在マッピングされているメモリだけでなく、将来マッピングされるメモリもロックするかどうかを指定できます(例:MCL_CURRENT
とMCL_FUTURE
)。munlockall()
:mlockall
によってロックされたプロセス全体のメモリロックを解除します。
これらのシステムコールは、通常、特権ユーザー(root)または特定の権限を持つプロセスのみが実行できます。
4. mprotect(addr, len, prot)
mprotect
システムコールは、指定されたメモリ領域 addr
から len
バイトのアクセス保護を変更します。prot
引数には、以下のフラグの組み合わせを指定できます。
PROT_NONE
: アクセス不可PROT_READ
: 読み取り可能PROT_WRITE
: 書き込み可能PROT_EXEC
: 実行可能
このシステムコールは、セキュリティ強化(例: データ領域を実行不可にする)、JITコンパイラ(実行時にコードを生成し、実行可能にする)、あるいはメモリデバッグツールなどで利用されます。
5. Goの syscall
パッケージと zsyscall_darwin_*.go
ファイル
Goの syscall
パッケージは、OS固有のシステムコールへの低レベルなインターフェースを提供します。zsyscall_darwin_386.go
と zsyscall_darwin_amd64.go
のようなファイルは、Goのツールによって自動生成されるファイルです。これらは、特定のアーキテクチャ(386は32ビット、amd64は64ビット)とOS(darwinはmacOS)に対応するシステムコールのラッパー関数を含んでいます。これらのファイルは、syscall
パッケージ内のmkall.go
などのツールが、syscall_darwin.go
のようなファイルに記述された//sys
コメントを解析して生成します。
技術的詳細
このコミットは、macOS (Darwin) 上でGoプログラムがメモリ管理システムコールを利用できるようにするために、以下の技術的詳細を実装しています。
-
syscall_darwin.go
への//sys
ディレクティブの追加:src/pkg/syscall/syscall_darwin.go
ファイルは、Goのsyscall
パッケージにおけるmacOS固有のシステムコール定義を含んでいます。このファイルに、mlock
,munlock
,mlockall
,munlockall
,mprotect
のGo関数シグネチャと、それらが対応するシステムコールであることを示す//sys
ディレクティブが追加されました。このディレクティブは、Goの内部ツールがzsyscall_darwin_*.go
ファイルを生成する際に使用されます。例:
//sys Mlock(b []byte) (err error)
-
zsyscall_darwin_386.go
およびzsyscall_darwin_amd64.go
の生成://sys
ディレクティブが追加された後、Goのビルドシステムまたは特定のツール(go generate
など)が実行されると、src/pkg/syscall/zsyscall_darwin_386.go
とsrc/pkg/syscall/zsyscall_darwin_amd64.go
ファイルが再生成されます。これらのファイルには、実際にシステムコールを呼び出すための低レベルなGoコードが含まれます。具体的には、Syscall
関数(またはSyscall6
など、引数の数に応じた関数)を使用して、OSのカーネルに直接システムコールをディスパッチします。生成されるコードは、Goのバイトスライス (
[]byte
) や整数 (int
) などの型を、システムコールが期待するポインタ (uintptr
) やサイズ (uintptr
) に変換する処理を含みます。例えば、mlock(b []byte)
の場合、バイトスライスb
の先頭アドレスと長さをuintptr
に変換してシステムコールに渡します。 -
エラーハンドリング: 各システムコールラッパー関数は、システムコールが失敗した場合にOSから返されるエラーコードをGoの
error
型に変換して返します。これにより、Goプログラムはシステムコールの成否を適切に判断し、エラー処理を行うことができます。 -
unsafe.Pointer
の使用: システムコールは通常、メモリのアドレスを直接操作するため、Goの型安全性をバイパスするunsafe.Pointer
が使用されます。これは、GoのメモリモデルとOSの低レベルなインターフェースとの間の橋渡しをするために必要不可欠です。
このコミットにより、Go開発者はmacOS上で、C言語などで利用できるこれらの強力なメモリ管理機能を、Goの慣用的な方法で利用できるようになりました。これは、Goがシステムプログラミング言語としての能力をさらに高める一歩となります。
コアとなるコードの変更箇所
このコミットによる主要なコード変更は、以下の3つのファイルに集中しています。
-
src/pkg/syscall/syscall_darwin.go
: このファイルには、Goのsyscall
パッケージがmacOS (Darwin) 上で提供するシステムコールのGo言語側の定義が含まれています。変更点としては、mlock
,munlock
,mlockall
,munlockall
,mprotect
の各システムコールに対応するGo関数のシグネチャが、//sys
ディレクティブとともに追記されています。--- a/src/pkg/syscall/syscall_darwin.go +++ b/src/pkg/syscall/syscall_darwin.go @@ -244,6 +244,11 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)\n //sys Mkdir(path string, mode uint32) (err error)\n //sys Mkfifo(path string, mode uint32) (err error)\n //sys Mknod(path string, mode uint32, dev int) (err error)\n+//sys Mlock(b []byte) (err error)\n+//sys\tMlockall(flags int) (err error)\n+//sys\tMprotect(b []byte, prot int) (err error)\n+//sys\tMunlock(b []byte) (err error)\n+//sys\tMunlockall() (err error)\n //sys Open(path string, mode int, perm uint32) (fd int, err error)\n //sys Pathconf(path string, name int) (val int, err error)\n //sys Pread(fd int, p []byte, offset int64) (n int, err error)\n ```
-
src/pkg/syscall/zsyscall_darwin_386.go
: このファイルは、32ビット (386) アーキテクチャ向けのmacOSシステムコールラッパーが自動生成される場所です。追加された//sys
ディレクティブに基づいて、Mlock
,Mlockall
,Mprotect
,Munlock
,Munlockall
の各Go関数が、実際のシステムコールを呼び出すためのコードとともに生成されています。 -
src/pkg/syscall/zsyscall_darwin_amd64.go
: このファイルは、64ビット (amd64) アーキテクチャ向けのmacOSシステムコールラッパーが自動生成される場所です。zsyscall_darwin_386.go
と同様に、Mlock
,Mlockall
,Mprotect
,Munlock
,Munlockall
の各Go関数が、実際のシステムコールを呼び出すためのコードとともに生成されています。zsyscall_darwin_386.go
とzsyscall_darwin_amd64.go
の変更内容はほぼ同じで、それぞれのアーキテクチャに合わせたシステムコール呼び出しの規約(レジスタの使用など)が反映されています。
コアとなるコードの解説
zsyscall_darwin_386.go
および zsyscall_darwin_amd64.go
で生成されるコードは、GoのSyscall
関数(またはSyscall6
など)を使用して、対応するシステムコールを呼び出します。以下に、Mlock
関数の例を挙げて解説します。他の関数も同様のパターンに従います。
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
if e1 != 0 {
err = e1
}
return
}
解説:
-
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
: これは、このファイルがGoのツールによって自動生成されたものであり、手動で編集すべきではないことを示すコメントです。 -
func Mlock(b []byte) (err error)
: Go言語で定義されたMlock
関数のシグネチャです。バイトスライスb
を引数にとり、エラーを返します。 -
var _p0 unsafe.Pointer
: システムコールに渡すメモリ領域の開始アドレスを保持するためのunsafe.Pointer
型の変数_p0
を宣言しています。unsafe.Pointer
は、Goの型システムをバイパスして任意の型へのポインタとして扱える特殊なポインタ型です。 -
if len(b) > 0 { _p0 = unsafe.Pointer(&b[0]) } else { _p0 = unsafe.Pointer(&_zero) }
: これは、バイトスライスb
が空でない場合に、その先頭要素のアドレスを_p0
に設定しています。&b[0]
はスライスの最初の要素へのポインタを取得します。スライスが空の場合(len(b) == 0
)、_zero
というゼロ値のアドレスが使用されます。これは、システムコールがNULLポインタを許容する場合や、長さがゼロのメモリ領域を扱う場合の慣例的な処理です。 -
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
: これがシステムコールを実際に呼び出す部分です。Syscall
: Goのsyscall
パッケージが提供する低レベルな関数で、OSのシステムコールを呼び出します。引数の数に応じてSyscall
,Syscall6
などが使われます。SYS_MLOCK
:mlock
システムコールに対応するOS固有のシステムコール番号です。これはGoのsyscall
パッケージ内で定義されています。uintptr(_p0)
:mlock
システムコールの第一引数であるメモリ領域の開始アドレスをuintptr
型にキャストして渡しています。uintptr
はポインタを保持できる整数型です。uintptr(len(b))
:mlock
システムコールの第二引数であるメモリ領域の長さをuintptr
型にキャストして渡しています。0
:mlock
システムコールの第三引数(この場合は未使用)です。_, _, e1
:Syscall
関数は通常、戻り値として3つのuintptr
を返します。最初の2つはシステムコールの結果(成功時の値など)、3つ目はエラーコードです。ここでは、結果は破棄し、エラーコードのみをe1
に受け取っています。
-
if e1 != 0 { err = e1 }
: システムコールが成功した場合、e1
は0になります。0以外の場合、e1
はOSのエラーコードを表すため、それをGoのerror
型に変換してerr
変数に代入しています。Goのsyscall
パッケージは、OSのエラーコードをGoのerror
インターフェースにラップする仕組みを持っています。 -
return
: 関数から戻ります。エラーが発生した場合はerr
が設定され、成功した場合はnil
が返されます。
このコードパターンは、Goのsyscall
パッケージがOSのシステムコールをGo言語に公開する際の典型的な実装方法を示しています。自動生成されることで、OSやアーキテクチャごとの差異を吸収し、開発者はGoの慣用的なAPIを通じて低レベルなOS機能を利用できるようになります。
関連リンク
- Go Issue 7415: このコミットが解決したGoのIssue。詳細な議論や背景情報が含まれている可能性があります。
- https://github.com/golang/go/issues/7415 (コミットメッセージに記載されているIssue番号から推測)
- Go CL 68980043: このコミットに対応するGerrit Code Reviewのチェンジリスト。
参考にした情報源リンク
- mlock(2) - Linux man page:
mlock
システムコールの詳細な説明。macOSでも同様の機能を提供します。 - mprotect(2) - Linux man page:
mprotect
システムコールの詳細な説明。 - Go言語のsyscallパッケージのドキュメント: Goの
syscall
パッケージの公式ドキュメント。 - Goの
go generate
コマンドとコード生成:zsyscall_darwin_*.go
のようなファイルがどのように生成されるかについての情報。 - Goの
unsafe
パッケージ:unsafe.Pointer
に関する公式ドキュメント。 - macOS Developer Library - System Calls: macOSにおけるシステムコールに関する一般的な情報。
- https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages/man2/syscall.2.html (一般的なシステムコールに関する情報へのリンク、具体的なmlock/mprotectのmanページは別途検索が必要)
- Darwin (macOS) のシステムコール: macOSのシステムコールに関するより技術的な情報源。
- https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/kern/syscalls.master (Darwinカーネルのシステムコール定義ファイル)
- Goのソースコードにおける
//sys
ディレクティブの利用: Goのソースコード内で//sys
ディレクティブがどのように使われているかを示す例。- https://github.com/golang/go/blob/master/src/syscall/syscall_linux.go (Linux版の例だが、概念は共通)
- Goの
mkall.go
ツール:zsyscall_*.go
ファイルを生成するGoの内部ツール。
これらの情報源は、このコミットが追加したシステムコールの機能、Go言語でのシステムコールラッパーの実装方法、および関連するOSのメモリ管理概念を理解する上で役立ちます。# [インデックス 18680] ファイルの概要
コミット
このコミットは、Go言語の syscall
パッケージに、macOS (OSX) 向けの mlock
, munlock
, mlockall
, munlockall
, および mprotect
システムコールを追加するものです。これにより、Goプログラムからこれらのメモリ管理関連のシステムコールを直接呼び出すことが可能になり、特定のメモリ領域のロックや保護といった低レベルな操作が行えるようになります。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/08706f19b4ec98d91f08c331d43e8e8553bb30c3
元コミット内容
commit 08706f19b4ec98d91f08c331d43e8e8553bb30c3
Author: William Orr <will@worrbase.com>
Date: Thu Feb 27 10:13:41 2014 -0800
syscall: add mlock, munlock, mlockall, munlockall and mprotect to OSX
Fixes #7415
LGTM=bradfitz
R=bradfitz, iant
CC=golang-codereviews
https://golang.org/cl/68980043
変更の背景
この変更の背景には、GoプログラムがmacOS上でより低レベルなメモリ管理機能にアクセスできるようにするというニーズがありました。特に、mlock
やmprotect
といったシステムコールは、セキュリティが重要なアプリケーション(例: 暗号化キーをメモリに保持するアプリケーション)や、リアルタイムシステム、あるいは特定のパフォーマンス要件を持つアプリケーションにおいて、メモリのページングを防いだり、メモリ領域のアクセス権を変更したりするために不可欠です。
コミットメッセージにある Fixes #7415
は、この変更がGoのIssue 7415を解決したことを示しています。このIssueは、GoプログラムがmacOS上でメモリロックや保護のシステムコールを利用できないことに関するものであったと推測されます。これらのシステムコールがGoのsyscall
パッケージに統合されることで、Go開発者はOSの提供する強力なメモリ管理機能を活用し、より堅牢で高性能なアプリケーションを構築できるようになります。
前提知識の解説
1. システムコール (System Call)
システムコールは、オペレーティングシステム (OS) のカーネルが提供するサービスを、ユーザー空間のプログラムが利用するためのインターフェースです。ファイルI/O、プロセス管理、メモリ管理、ネットワーク通信など、OSが管理するリソースへのアクセスは、直接行うことができず、必ずシステムコールを介して行われます。Go言語の syscall
パッケージは、これらのシステムコールをGoプログラムから呼び出すためのラッパーを提供します。
2. 仮想記憶 (Virtual Memory) とページング (Paging)
現代のOSは仮想記憶システムを採用しています。これは、物理メモリ(RAM)を抽象化し、各プロセスに独立した仮想アドレス空間を提供する仕組みです。仮想アドレス空間は「ページ」と呼ばれる固定サイズのブロックに分割され、これらのページは必要に応じて物理メモリ上の「ページフレーム」にマッピングされます。
ページングは、仮想記憶システムの一部であり、物理メモリが不足した場合に、使用頻度の低いメモリページをディスク(スワップ領域)に一時的に退避させ、必要になったときに再度物理メモリに読み込む(ページイン)メカニズムです。これにより、物理メモリの量よりも大きなプログラムを実行できるようになりますが、ディスクI/Oが発生するためパフォーマンスの低下を招く可能性があります。
3. mlock
, munlock
, mlockall
, munlockall
これらのシステムコールは、メモリのページングを制御するために使用されます。
mlock(addr, len)
: 指定されたアドレスaddr
からlen
バイトのメモリ領域を物理メモリにロックします。これにより、そのメモリ領域がディスクにページアウトされるのを防ぎます。これは、機密データ(例: 暗号化キー)がディスクに書き込まれるのを防ぐためや、リアルタイムアプリケーションで予測可能なレイテンシを確保するために重要です。munlock(addr, len)
:mlock
によってロックされたメモリ領域のロックを解除します。mlockall(flags)
: プロセス全体の仮想アドレス空間を物理メモリにロックします。flags
引数によって、現在マッピングされているメモリだけでなく、将来マッピングされるメモリもロックするかどうかを指定できます(例:MCL_CURRENT
とMCL_FUTURE
)。munlockall()
:mlockall
によってロックされたプロセス全体のメモリロックを解除します。
これらのシステムコールは、通常、特権ユーザー(root)または特定の権限を持つプロセスのみが実行できます。
4. mprotect(addr, len, prot)
mprotect
システムコールは、指定されたメモリ領域 addr
から len
バイトのアクセス保護を変更します。prot
引数には、以下のフラグの組み合わせを指定できます。
PROT_NONE
: アクセス不可PROT_READ
: 読み取り可能PROT_WRITE
: 書き込み可能PROT_EXEC
: 実行可能
このシステムコールは、セキュリティ強化(例: データ領域を実行不可にする)、JITコンパイラ(実行時にコードを生成し、実行可能にする)、あるいはメモリデバッグツールなどで利用されます。
5. Goの syscall
パッケージと zsyscall_darwin_*.go
ファイル
Goの syscall
パッケージは、OS固有のシステムコールへの低レベルなインターフェースを提供します。zsyscall_darwin_386.go
と zsyscall_darwin_amd64.go
のようなファイルは、Goのツールによって自動生成されるファイルです。これらは、特定のアーキテクチャ(386は32ビット、amd64は64ビット)とOS(darwinはmacOS)に対応するシステムコールのラッパー関数を含んでいます。これらのファイルは、syscall
パッケージ内のmkall.go
などのツールが、syscall_darwin.go
のようなファイルに記述された//sys
コメントを解析して生成します。
技術的詳細
このコミットは、macOS (Darwin) 上でGoプログラムがメモリ管理システムコールを利用できるようにするために、以下の技術的詳細を実装しています。
-
syscall_darwin.go
への//sys
ディレクティブの追加:src/pkg/syscall/syscall_darwin.go
ファイルは、Goのsyscall
パッケージにおけるmacOS固有のシステムコール定義を含んでいます。このファイルに、mlock
,munlock
,mlockall
,munlockall
,mprotect
のGo関数シグネチャと、それらが対応するシステムコールであることを示す//sys
ディレクティブが追加されました。このディレクティブは、Goの内部ツールがzsyscall_darwin_*.go
ファイルを生成する際に使用されます。例:
//sys Mlock(b []byte) (err error)
-
zsyscall_darwin_386.go
およびzsyscall_darwin_amd64.go
の生成://sys
ディレクティブが追加された後、Goのビルドシステムまたは特定のツール(go generate
など)が実行されると、src/pkg/syscall/zsyscall_darwin_386.go
とsrc/pkg/syscall/zsyscall_darwin_amd64.go
ファイルが再生成されます。これらのファイルには、実際にシステムコールを呼び出すための低レベルなGoコードが含まれます。具体的には、Syscall
関数(またはSyscall6
など、引数の数に応じた関数)を使用して、OSのカーネルに直接システムコールをディスパッチします。生成されるコードは、Goのバイトスライス (
[]byte
) や整数 (int
) などの型を、システムコールが期待するポインタ (uintptr
) やサイズ (uintptr
) に変換する処理を含みます。例えば、mlock(b []byte)
の場合、バイトスライスb
の先頭アドレスと長さをuintptr
に変換してシステムコールに渡します。 -
エラーハンドリング: 各システムコールラッパー関数は、システムコールが失敗した場合にOSから返されるエラーコードをGoの
error
型に変換して返します。これにより、Goプログラムはシステムコールの成否を適切に判断し、エラー処理を行うことができます。 -
unsafe.Pointer
の使用: システムコールは通常、メモリのアドレスを直接操作するため、Goの型安全性をバイパスするunsafe.Pointer
が使用されます。これは、GoのメモリモデルとOSの低レベルなインターフェースとの間の橋渡しをするために必要不可欠です。
このコミットにより、Go開発者はmacOS上で、C言語などで利用できるこれらの強力なメモリ管理機能を、Goの慣用的な方法で利用できるようになりました。これは、Goがシステムプログラミング言語としての能力をさらに高める一歩となります。
コアとなるコードの変更箇所
このコミットによる主要なコード変更は、以下の3つのファイルに集中しています。
-
src/pkg/syscall/syscall_darwin.go
: このファイルには、Goのsyscall
パッケージがmacOS (Darwin) 上で提供するシステムコールのGo言語側の定義が含まれています。変更点としては、mlock
,munlock
,mlockall
,munlockall
,mprotect
の各システムコールに対応するGo関数のシグネチャが、//sys
ディレクティブとともに追記されています。--- a/src/pkg/syscall/syscall_darwin.go +++ b/src/pkg/syscall/syscall_darwin.go @@ -244,6 +244,11 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)\n //sys Mkdir(path string, mode uint32) (err error)\n //sys Mkfifo(path string, mode uint32) (err error)\n //sys Mknod(path string, mode uint32, dev int) (err error)\n+//sys Mlock(b []byte) (err error)\n+//sys\tMlockall(flags int) (err error)\n+//sys\tMprotect(b []byte, prot int) (err error)\n+//sys\tMunlock(b []byte) (err error)\n+//sys\tMunlockall() (err error)\n //sys Open(path string, mode int, perm uint32) (fd int, err error)\n //sys Pathconf(path string, name int) (val int, err error)\n //sys Pread(fd int, p []byte, offset int64) (n int, err error)\n ```
-
src/pkg/syscall/zsyscall_darwin_386.go
: このファイルは、32ビット (386) アーキテクチャ向けのmacOSシステムコールラッパーが自動生成される場所です。追加された//sys
ディレクティブに基づいて、Mlock
,Mlockall
,Mprotect
,Munlock
,Munlockall
の各Go関数が、実際のシステムコールを呼び出すためのコードとともに生成されています。 -
src/pkg/syscall/zsyscall_darwin_amd64.go
: このファイルは、64ビット (amd64) アーキテクチャ向けのmacOSシステムコールラッパーが自動生成される場所です。zsyscall_darwin_386.go
と同様に、Mlock
,Mlockall
,Mprotect
,Munlock
,Munlockall
の各Go関数が、実際のシステムコールを呼び出すためのコードとともに生成されています。zsyscall_darwin_386.go
とzsyscall_darwin_amd64.go
の変更内容はほぼ同じで、それぞれのアーキテクチャに合わせたシステムコール呼び出しの規約(レジスタの使用など)が反映されています。
コアとなるコードの解説
zsyscall_darwin_386.go
および zsyscall_darwin_amd64.go
で生成されるコードは、GoのSyscall
関数(またはSyscall6
など)を使用して、対応するシステムコールを呼び出します。以下に、Mlock
関数の例を挙げて解説します。他の関数も同様のパターンに従います。
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Mlock(b []byte) (err error) {
var _p0 unsafe.Pointer
if len(b) > 0 {
_p0 = unsafe.Pointer(&b[0])
} else {
_p0 = unsafe.Pointer(&_zero)
}
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
if e1 != 0 {
err = e1
}
return
}
解説:
-
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
: これは、このファイルがGoのツールによって自動生成されたものであり、手動で編集すべきではないことを示すコメントです。 -
func Mlock(b []byte) (err error)
: Go言語で定義されたMlock
関数のシグネチャです。バイトスライスb
を引数にとり、エラーを返します。 -
var _p0 unsafe.Pointer
: システムコールに渡すメモリ領域の開始アドレスを保持するためのunsafe.Pointer
型の変数_p0
を宣言しています。unsafe.Pointer
は、Goの型システムをバイパスして任意の型へのポインタとして扱える特殊なポインタ型です。 -
if len(b) > 0 { _p0 = unsafe.Pointer(&b[0]) } else { _p0 = unsafe.Pointer(&_zero) }
: これは、バイトスライスb
が空でない場合に、その先頭要素のアドレスを_p0
に設定しています。&b[0]
はスライスの最初の要素へのポインタを取得します。スライスが空の場合(len(b) == 0
)、_zero
というゼロ値のアドレスが使用されます。これは、システムコールがNULLポインタを許容する場合や、長さがゼロのメモリ領域を扱う場合の慣例的な処理です。 -
_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
: これがシステムコールを実際に呼び出す部分です。Syscall
: Goのsyscall
パッケージが提供する低レベルな関数で、OSのシステムコールを呼び出します。引数の数に応じてSyscall
,Syscall6
などが使われます。SYS_MLOCK
:mlock
システムコールに対応するOS固有のシステムコール番号です。これはGoのsyscall
パッケージ内で定義されています。uintptr(_p0)
:mlock
システムコールの第一引数であるメモリ領域の開始アドレスをuintptr
型にキャストして渡しています。uintptr
はポインタを保持できる整数型です。uintptr(len(b))
:mlock
システムコールの第二引数であるメモリ領域の長さをuintptr
型にキャストして渡しています。0
:mlock
システムコールの第三引数(この場合は未使用)です。_, _, e1
:Syscall
関数は通常、戻り値として3つのuintptr
を返します。最初の2つはシステムコールの結果(成功時の値など)、3つ目はエラーコードです。ここでは、結果は破棄し、エラーコードのみをe1
に受け取っています。
-
if e1 != 0 { err = e1 }
: システムコールが成功した場合、e1
は0になります。0以外の場合、e1
はOSのエラーコードを表すため、それをGoのerror
型に変換してerr
変数に代入しています。Goのsyscall
パッケージは、OSのエラーコードをGoのerror
インターフェースにラップする仕組みを持っています。 -
return
: 関数から戻ります。エラーが発生した場合はerr
が設定され、成功した場合はnil
が返されます。
このコードパターンは、Goのsyscall
パッケージがOSのシステムコールをGo言語に公開する際の典型的な実装方法を示しています。自動生成されることで、OSやアーキテクチャごとの差異を吸収し、開発者はGoの慣用的なAPIを通じて低レベルなOS機能を利用できるようになります。
関連リンク
- Go Issue 7415: このコミットが解決したGoのIssue。詳細な議論や背景情報が含まれている可能性があります。
- https://github.com/golang/go/issues/7415 (コミットメッセージに記載されているIssue番号から推測)
- Go CL 68980043: このコミットに対応するGerrit Code Reviewのチェンジリスト。
参考にした情報源リンク
- mlock(2) - Linux man page:
mlock
システムコールの詳細な説明。macOSでも同様の機能を提供します。 - mprotect(2) - Linux man page:
mprotect
システムコールの詳細な説明。 - Go言語のsyscallパッケージのドキュメント: Goの
syscall
パッケージの公式ドキュメント。 - Goの
go generate
コマンドとコード生成:zsyscall_darwin_*.go
のようなファイルがどのように生成されるかについての情報。 - Goの
unsafe
パッケージ:unsafe.Pointer
に関する公式ドキュメント。 - macOS Developer Library - System Calls: macOSにおけるシステムコールに関する一般的な情報。
- https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages/man2/syscall.2.html (一般的なシステムコールに関する情報へのリンク、具体的なmlock/mprotectのmanページは別途検索が必要)
- Darwin (macOS) のシステムコール: macOSのシステムコールに関するより技術的な情報源。
- https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/kern/syscalls.master (Darwinカーネルのシステムコール定義ファイル)
- Goのソースコードにおける
//sys
ディレクティブの利用: Goのソースコード内で//sys
ディレクティブがどのように使われているかを示す例。- https://github.com/golang/go/blob/master/src/syscall/syscall_linux.go (Linux版の例だが、概念は共通)
- Goの
mkall.go
ツール:zsyscall_*.go
ファイルを生成するGoの内部ツール。
これらの情報源は、このコミットが追加したシステムコールの機能、Go言語でのシステムコールラッパーの実装方法、および関連するOSのメモリ管理概念を理解する上で役立ちます。