[インデックス 16734] ファイルの概要
コミット
commit 72faa4bc5100cc9845fac77e367adbbd10e64038
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Fri Jul 12 04:34:54 2013 +0800
syscall: implement Sendfile for Darwin.
Update #5847
Summary: syscall: implement Sendfile for OpenBSD and NetBSD
R=golang-dev, rsc, dave
CC=golang-dev
https://golang.org/cl/10980043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/72faa4bc5100cc9845fac77e367adbbd10e64038
元コミット内容
syscall: implement Sendfile for Darwin.
Update #5847
Summary: syscall: implement Sendfile for OpenBSD and NetBSD
変更の背景
このコミットは、Go言語のsyscall
パッケージにおいて、Darwin(macOS)プラットフォーム向けにSendfile
システムコールを実装することを目的としています。元のコミットメッセージには「Update #5847」とあり、これはGoのIssueトラッカーにおける特定の課題に関連しています。Issue #5847のサマリーが「syscall: implement Sendfile for OpenBSD and NetBSD」となっていることから、この機能は元々OpenBSDとNetBSD向けに計画されていたものですが、このコミットでDarwinにも拡張されたことが示唆されます。
sendfile
システムコールは、ファイルディスクリプタから別のファイルディスクリプタ(通常はソケット)へデータを直接転送するための効率的なメカニズムを提供します。これにより、ユーザー空間でのバッファリングを介さずにカーネル空間内でデータ転送が完結するため、「ゼロコピー」と呼ばれる高いパフォーマンスを実現できます。Webサーバーなどで静的ファイルを配信する際に特に有効であり、CPU使用率の削減とスループットの向上に寄与します。
Go言語の標準ライブラリが様々なオペレーティングシステムをサポートする上で、各OS固有の効率的なシステムコールを活用することは重要です。このコミットは、Darwin環境におけるネットワークI/Oパフォーマンスの改善を目指したものです。
前提知識の解説
システムコール (System Call)
システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で提供されるオペレーティングシステム(OS)のサービスを利用するためのインターフェースです。ファイルI/O、ネットワーク通信、プロセス管理、メモリ管理など、OSが提供するほとんどの機能はシステムコールを介して利用されます。Go言語のsyscall
パッケージは、これらの低レベルなOS機能へのアクセスを提供します。
sendfile
システムコール
sendfile
は、特定のOSで利用可能なシステムコールで、ファイルの内容を直接ネットワークソケットに送信する際に非常に効率的です。従来のファイル読み込み(read
)とソケット書き込み(write
)の組み合わせでは、データがカーネルバッファからユーザーバッファへ、そして再びカーネルバッファへとコピーされるため、複数回のデータコピーが発生します。これに対し、sendfile
はカーネル内で直接データ転送を行うため、ユーザー空間へのデータコピーを省略し、CPUオーバーヘッドとメモリ帯域幅の使用を削減します。
macOS(Darwin)におけるsendfile(2)
のシグネチャは以下のようになります(バージョンによって異なる場合がありますが、基本的な概念は同じです):
int sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);
ここで、fd
は入力ファイルディスクリプタ、s
は出力ソケットディスクリプタ、offset
はファイル内の開始オフセット、len
は転送するバイト数(入力と出力の両方)、hdtr
はヘッダ/トレーラ構造体、flags
は追加のオプションです。
Syscall
関数群 (Go言語のsyscall
パッケージ)
Go言語のsyscall
パッケージには、OSのシステムコールを直接呼び出すための低レベルな関数群が提供されています。これらは通常、Syscall
、Syscall6
、Syscall9
といった形式で、引数の数に応じて使い分けられます。これらの関数は、Goのランタイム内部でアセンブリコードによって実装されており、Goの実行環境からOSのカーネルまたはCライブラリへの遷移を処理します。
Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
: 3つまでの引数を持つシステムコールを呼び出す。Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
: 6つまでの引数を持つシステムコールを呼び出す。Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
: 9つまでの引数を持つシステムコールを呼び出す。
これらの関数は、システムコール番号(trap
)と、システムコールに渡す引数をuintptr
型で受け取ります。戻り値は、システムコールの結果(r1
, r2
)とエラーコード(err
)です。
Darwinにおける32-bit (i386) と 64-bit (amd64) アーキテクチャ
Darwin(macOS)は、Intelベースのプロセッサを搭載したMacで動作します。初期のIntel Macは32-bit(i386)アーキテクチャをサポートしていましたが、現代のMacは主に64-bit(amd64)アーキテクチャで動作します。システムコールの呼び出し規約や引数の渡し方は、アーキテクチャによって異なる場合があります。特に、レジスタの使用方法やポインタのサイズが異なるため、同じシステムコールでも32-bitと64-bitで異なる実装が必要になることがあります。
技術的詳細
このコミットは、Darwinにおけるsyscall.Sendfile
の実装に焦点を当てています。特に、32-bit (i386) と 64-bit (amd64) の両方のアーキテクチャに対応するために、それぞれのファイルでsendfile
関数が実装されています。
Darwinのsendfile
システムコールは、引数としてoff_t *len
(転送バイト数を指定し、実際に転送されたバイト数を返すポインタ)を取ります。GoのSyscall
関数群は、引数をuintptr
として受け取るため、ポインタを直接渡す必要があります。
src/pkg/syscall/syscall_darwin_386.go
の変更点
32-bitアーキテクチャ(i386)の場合、sendfile
システムコールは9つの引数を取るため、Syscall9
が使用されます。
Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
ここで注目すべきは、offset
引数がuintptr(*offset)
とuintptr(*offset>>32)
の2つのuintptr
に分割されている点です。これは、32-bitシステムにおいて64-bitのoffset
値を渡すための一般的な方法です。*offset
の下位32ビットが最初のuintptr
に、上位32ビットが2番目のuintptr
に渡されます。
また、length
変数はuint64
型で宣言され、そのポインタがunsafe.Pointer(&length)
としてuintptr
にキャストされて渡されます。これは、sendfile
システムコールがlen
引数をポインタとして受け取り、そのポインタが指すメモリ位置に実際に転送されたバイト数を書き込むためです。
src/pkg/syscall/syscall_darwin_amd64.go
の変更点
64-bitアーキテクチャ(amd64)の場合、sendfile
システムコールは6つの引数を取るため、Syscall6
が使用されます。
Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
64-bitシステムでは、offset
は単一のuintptr
として直接渡すことができます。length
の扱い方は32-bitの場合と同様で、unsafe.Pointer(&length)
を介してポインタが渡されます。
doc/go1.2.txt
の変更点
このファイルはGo 1.2のリリースノートの一部であり、syscall: implemented Sendfile for Darwin, added Syscall9 for Darwin/amd64 (CL 10980043).
という記述が追加されています。これは、このコミットによってDarwin向けのSendfile
が実装され、特にDarwin/amd64向けにSyscall9
が追加されたことを示しています。ただし、実際のコードではDarwin/amd64でSyscall6
が使われているため、このドキュメントの記述は少し不正確であるか、あるいはSyscall9
が他の目的で追加されたことを指している可能性があります。コミットの差分を見る限り、syscall_darwin_amd64.go
にはSyscall9
の宣言も追加されていますが、sendfile
の実装ではSyscall6
が使われています。これは、Syscall9
が汎用的なシステムコール呼び出しのために提供され、sendfile
がたまたま6引数で済んだ、という状況かもしれません。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルは以下の通りです。
doc/go1.2.txt
: Go 1.2のリリースノートに、Darwin向けSendfile
の実装とSyscall9
の追加が記載されました。src/pkg/syscall/syscall_darwin.go
: 既存のsendfile
のスタブ実装(常にエラーを返す)が削除されました。src/pkg/syscall/syscall_darwin_386.go
: Darwinの32-bit (i386) アーキテクチャ向けにsendfile
関数が実装されました。src/pkg/syscall/syscall_darwin_amd64.go
: Darwinの64-bit (amd64) アーキテクチャ向けにsendfile
関数が実装されました。
コアとなるコードの解説
src/pkg/syscall/syscall_darwin.go
(削除部分)
// TODO
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
この部分は、sendfile
が未実装であることを示すプレースホルダーでした。ENOSYS
は「Function not implemented」を意味するエラーコードです。このコミットにより、具体的な実装が提供されるため、このスタブは不要となり削除されました。
src/pkg/syscall/syscall_darwin_386.go
(追加部分)
+import "unsafe"
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ var length = uint64(count)
+
+ _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
+
+ written = int(length)
+
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
import "unsafe"
: ポインタをuintptr
に変換するために必要です。func sendfile(...)
: Goのsyscall.Sendfile
のインターフェースに合わせた関数シグネチャです。var length = uint64(count)
: 転送バイト数を保持するuint64
変数を宣言し、初期化します。これはsendfile
システムコールが転送バイト数をポインタで受け取るためです。Syscall9(...)
: 実際のsendfile
システムコールを呼び出します。SYS_SENDFILE
:sendfile
システムコールの番号。uintptr(infd)
,uintptr(outfd)
: 入力ファイルディスクリプタと出力ファイルディスクリプタ。uintptr(*offset)
,uintptr(*offset>>32)
: 64-bitのoffset
値を32-bitの2つのuintptr
に分割して渡します。uintptr(unsafe.Pointer(&length))
:length
変数のアドレスをuintptr
に変換して渡します。システムコールはこのアドレスに実際に転送されたバイト数を書き込みます。- 残りの引数(
0, 0, 0, 0
)は、Darwinのsendfile
システムコールの残りの引数(hdtr
,flags
など)に対応しますが、この実装では使用されていないためゼロが渡されています。
written = int(length)
: システムコールが書き込んだlength
の値をint
にキャストしてwritten
に戻します。- エラーハンドリング:
Syscall9
の戻り値e1
が非ゼロの場合、それをエラーとして返します。 func Syscall9(...)
:Syscall9
関数の宣言。これは、Goのランタイムが提供する低レベルなシステムコール呼び出し関数です。
src/pkg/syscall/syscall_darwin_amd64.go
(追加部分)
+import "unsafe"
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ var length = uint64(count)
+
+ _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
+
+ written = int(length)
+
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
import "unsafe"
: 同上。func sendfile(...)
: 同上。var length = uint64(count)
: 同上。Syscall6(...)
: 64-bitアーキテクチャでは、sendfile
システムコールは6つの引数で呼び出されます。uintptr(*offset)
: 64-bitシステムでは、offset
は単一のuintptr
として直接渡されます。uintptr(unsafe.Pointer(&length))
: 同上。- 残りの引数(
0, 0
)は、hdtr
,flags
に対応します。
written = int(length)
: 同上。- エラーハンドリング: 同上。
func Syscall9(...)
: ここでもSyscall9
の宣言が追加されていますが、sendfile
の実装自体はSyscall6
を使用しています。これは、Syscall9
がこのファイルで利用可能になったことを示している可能性があります。
関連リンク
- Go Issue 5847: https://github.com/golang/go/issues/5847 (このコミットが参照しているIssue)
- Go CL 10980043: https://golang.org/cl/10980043 (このコミットに対応するGerrit Change-ID)
sendfile(2)
man page (macOS):man 2 sendfile
(ターミナルで実行)
参考にした情報源リンク
- Go言語の
syscall.Sendfile
に関するドキュメント: https://pkg.go.dev/syscall#Sendfile - Go言語の
syscall
パッケージにおけるSyscall
関数群の解説: https://pkg.go.dev/syscall#Syscall - macOSの
sendfile
システムコールに関する情報 (Apple Developer Documentationなど) - Go言語のシステムコール呼び出しに関するQiita記事: https://qiita.com/tenntenn/items/5221712212212212212 (一般的なGoのシステムコール呼び出しの仕組みについて)
- Go言語の
syscall
パッケージの内部実装に関する情報 (Goのソースコードや関連するブログ記事など) - Go言語の
unsafe
パッケージに関するドキュメント: https://pkg.go.dev/unsafe# [インデックス 16734] ファイルの概要
コミット
commit 72faa4bc5100cc9845fac77e367adbbd10e64038
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Fri Jul 12 04:34:54 2013 +0800
syscall: implement Sendfile for Darwin.
Update #5847
Summary: syscall: implement Sendfile for OpenBSD and NetBSD
R=golang-dev, rsc, dave
CC=golang-dev
https://golang.org/cl/10980043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/72faa4bc5100cc9845fac77e367adbbd10e64038
元コミット内容
syscall: implement Sendfile for Darwin.
Update #5847
Summary: syscall: implement Sendfile for OpenBSD and NetBSD
変更の背景
このコミットは、Go言語のsyscall
パッケージにおいて、Darwin(macOS)プラットフォーム向けにSendfile
システムコールを実装することを目的としています。元のコミットメッセージには「Update #5847」とあり、これはGoのIssueトラッカーにおける特定の課題に関連しています。Issue #5847のサマリーが「syscall: implement Sendfile for OpenBSD and NetBSD」となっていることから、この機能は元々OpenBSDとNetBSD向けに計画されていたものですが、このコミットでDarwinにも拡張されたことが示唆されます。
sendfile
システムコールは、ファイルディスクリプタから別のファイルディスクリプタ(通常はソケット)へデータを直接転送するための効率的なメカニズムを提供します。これにより、ユーザー空間でのバッファリングを介さずにカーネル空間内でデータ転送が完結するため、「ゼロコピー」と呼ばれる高いパフォーマンスを実現できます。Webサーバーなどで静的ファイルを配信する際に特に有効であり、CPU使用率の削減とスループットの向上に寄与します。
Go言語の標準ライブラリが様々なオペレーティングシステムをサポートする上で、各OS固有の効率的なシステムコールを活用することは重要です。このコミットは、Darwin環境におけるネットワークI/Oパフォーマンスの改善を目指したものです。
前提知識の解説
システムコール (System Call)
システムコールは、ユーザー空間で動作するプログラムが、カーネル空間で提供されるオペレーティングシステム(OS)のサービスを利用するためのインターフェースです。ファイルI/O、ネットワーク通信、プロセス管理、メモリ管理など、OSが提供するほとんどの機能はシステムコールを介して利用されます。Go言語のsyscall
パッケージは、これらの低レベルなOS機能へのアクセスを提供します。
sendfile
システムコール
sendfile
は、特定のOSで利用可能なシステムコールで、ファイルの内容を直接ネットワークソケットに送信する際に非常に効率的です。従来のファイル読み込み(read
)とソケット書き込み(write
)の組み合わせでは、データがカーネルバッファからユーザーバッファへ、そして再びカーネルバッファへとコピーされるため、複数回のデータコピーが発生します。これに対し、sendfile
はカーネル内で直接データ転送を行うため、ユーザー空間へのデータコピーを省略し、CPUオーバーヘッドとメモリ帯域幅の使用を削減します。
macOS(Darwin)におけるsendfile(2)
のシグネチャは以下のようになります(バージョンによって異なる場合がありますが、基本的な概念は同じです):
int sendfile(int fd, int s, off_t offset, off_t *len, struct sf_hdtr *hdtr, int flags);
ここで、fd
は入力ファイルディスクリプタ、s
は出力ソケットディスクリプタ、offset
はファイル内の開始オフセット、len
は転送するバイト数(入力と出力の両方)、hdtr
はヘッダ/トレーラ構造体、flags
は追加のオプションです。
Syscall
関数群 (Go言語のsyscall
パッケージ)
Go言語のsyscall
パッケージには、OSのシステムコールを直接呼び出すための低レベルな関数群が提供されています。これらは通常、Syscall
、Syscall6
、Syscall9
といった形式で、引数の数に応じて使い分けられます。これらの関数は、Goのランタイム内部でアセンブリコードによって実装されており、Goの実行環境からOSのカーネルまたはCライブラリへの遷移を処理します。
Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
: 3つまでの引数を持つシステムコールを呼び出す。Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
: 6つまでの引数を持つシステムコールを呼び出す。Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
: 9つまでの引数を持つシステムコールを呼び出す。
これらの関数は、システムコール番号(trap
)と、システムコールに渡す引数をuintptr
型で受け取ります。戻り値は、システムコールの結果(r1
, r2
)とエラーコード(err
)です。
Darwinにおける32-bit (i386) と 64-bit (amd64) アーキテクチャ
Darwin(macOS)は、Intelベースのプロセッサを搭載したMacで動作します。初期のIntel Macは32-bit(i386)アーキテクチャをサポートしていましたが、現代のMacは主に64-bit(amd64)アーキテクチャで動作します。システムコールの呼び出し規約や引数の渡し方は、アーキテクチャによって異なる場合があります。特に、レジスタの使用方法やポインタのサイズが異なるため、同じシステムコールでも32-bitと64-bitで異なる実装が必要になることがあります。
技術的詳細
このコミットは、Darwinにおけるsyscall.Sendfile
の実装に焦点を当てています。特に、32-bit (i386) と 64-bit (amd64) の両方のアーキテクチャに対応するために、それぞれのファイルでsendfile
関数が実装されています。
Darwinのsendfile
システムコールは、引数としてoff_t *len
(転送バイト数を指定し、実際に転送されたバイト数を返すポインタ)を取ります。GoのSyscall
関数群は、引数をuintptr
として受け取るため、ポインタを直接渡す必要があります。
src/pkg/syscall/syscall_darwin_386.go
の変更点
32-bitアーキテクチャ(i386)の場合、sendfile
システムコールは9つの引数を取るため、Syscall9
が使用されます。
Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
ここで注目すべきは、offset
引数がuintptr(*offset)
とuintptr(*offset>>32)
の2つのuintptr
に分割されている点です。これは、32-bitシステムにおいて64-bitのoffset
値を渡すための一般的な方法です。*offset
の下位32ビットが最初のuintptr
に、上位32ビットが2番目のuintptr
に渡されます。
また、length
変数はuint64
型で宣言され、そのポインタがunsafe.Pointer(&length)
としてuintptr
にキャストされて渡されます。これは、sendfile
システムコールがlen
引数をポインタとして受け取り、そのポインタが指すメモリ位置に実際に転送されたバイト数を書き込むためです。
src/pkg/syscall/syscall_darwin_amd64.go
の変更点
64-bitアーキテクチャ(amd64)の場合、sendfile
システムコールは6つの引数を取るため、Syscall6
が使用されます。
Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
64-bitシステムでは、offset
は単一のuintptr
として直接渡すことができます。length
の扱い方は32-bitの場合と同様で、unsafe.Pointer(&length)
を介してポインタが渡されます。
doc/go1.2.txt
の変更点
このファイルはGo 1.2のリリースノートの一部であり、syscall: implemented Sendfile for Darwin, added Syscall9 for Darwin/amd64 (CL 10980043).
という記述が追加されています。これは、このコミットによってDarwin向けのSendfile
が実装され、特にDarwin/amd64向けにSyscall9
が追加されたことを示しています。ただし、実際のコードではDarwin/amd64でSyscall6
が使われているため、このドキュメントの記述は少し不正確であるか、あるいはSyscall9
が他の目的で追加されたことを指している可能性があります。コミットの差分を見る限り、syscall_darwin_amd64.go
にはSyscall9
の宣言も追加されていますが、sendfile
の実装ではSyscall6
が使われています。これは、Syscall9
が汎用的なシステムコール呼び出しのために提供され、sendfile
がたまたま6引数で済んだ、という状況かもしれません。
コアとなるコードの変更箇所
このコミットで変更された主要なファイルは以下の通りです。
doc/go1.2.txt
: Go 1.2のリリースノートに、Darwin向けSendfile
の実装とSyscall9
の追加が記載されました。src/pkg/syscall/syscall_darwin.go
: 既存のsendfile
のスタブ実装(常にエラーを返す)が削除されました。src/pkg/syscall/syscall_darwin_386.go
: Darwinの32-bit (i386) アーキテクチャ向けにsendfile
関数が実装されました。src/pkg/syscall/syscall_darwin_amd64.go
: Darwinの64-bit (amd64) アーキテクチャ向けにsendfile
関数が実装されました。
コアとなるコードの解説
src/pkg/syscall/syscall_darwin.go
(削除部分)
// TODO
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
return -1, ENOSYS
}
この部分は、sendfile
が未実装であることを示すプレースホルダーでした。ENOSYS
は「Function not implemented」を意味するエラーコードです。このコミットにより、具体的な実装が提供されるため、このスタブは不要となり削除されました。
src/pkg/syscall/syscall_darwin_386.go
(追加部分)
+import "unsafe"
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ var length = uint64(count)
+
+ _, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
+
+ written = int(length)
+
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
import "unsafe"
: ポインタをuintptr
に変換するために必要です。func sendfile(...)
: Goのsyscall.Sendfile
のインターフェースに合わせた関数シグネチャです。var length = uint64(count)
: 転送バイト数を保持するuint64
変数を宣言し、初期化します。これはsendfile
システムコールが転送バイト数をポインタで受け取るためです。Syscall9(...)
: 実際のsendfile
システムコールを呼び出します。SYS_SENDFILE
:sendfile
システムコールの番号。uintptr(infd)
,uintptr(outfd)
: 入力ファイルディスクリプタと出力ファイルディスクリプタ。uintptr(*offset)
,uintptr(*offset>>32)
: 64-bitのoffset
値を32-bitの2つのuintptr
に分割して渡します。uintptr(unsafe.Pointer(&length))
:length
変数のアドレスをuintptr
に変換して渡します。システムコールはこのアドレスに実際に転送されたバイト数を書き込みます。- 残りの引数(
0, 0, 0, 0
)は、Darwinのsendfile
システムコールの残りの引数(hdtr
,flags
など)に対応しますが、この実装では使用されていないためゼロが渡されています。
written = int(length)
: システムコールが書き込んだlength
の値をint
にキャストしてwritten
に戻します。- エラーハンドリング:
Syscall9
の戻り値e1
が非ゼロの場合、それをエラーとして返します。 func Syscall9(...)
:Syscall9
関数の宣言。これは、Goのランタイムが提供する低レベルなシステムコール呼び出し関数です。
src/pkg/syscall/syscall_darwin_amd64.go
(追加部分)
+import "unsafe"
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+ var length = uint64(count)
+
+ _, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
+
+ written = int(length)
+
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
import "unsafe"
: 同上。func sendfile(...)
: 同上。var length = uint64(count)
: 同上。Syscall6(...)
: 64-bitアーキテクチャでは、sendfile
システムコールは6つの引数で呼び出されます。uintptr(*offset)
: 64-bitシステムでは、offset
は単一のuintptr
として直接渡されます。uintptr(unsafe.Pointer(&length))
: 同上。- 残りの引数(
0, 0
)は、hdtr
,flags
に対応します。
written = int(length)
: 同上。- エラーハンドリング: 同上。
func Syscall9(...)
: ここでもSyscall9
の宣言が追加されていますが、sendfile
の実装自体はSyscall6
を使用しています。これは、Syscall9
がこのファイルで利用可能になったことを示している可能性があります。
関連リンク
- Go Issue 5847: https://github.com/golang/go/issues/5847 (このコミットが参照しているIssue)
- Go CL 10980043: https://golang.org/cl/10980043 (このコミットに対応するGerrit Change-ID)
sendfile(2)
man page (macOS):man 2 sendfile
(ターミナルで実行)
参考にした情報源リンク
- Go言語の
syscall.Sendfile
に関するドキュメント: https://pkg.go.dev/syscall#Sendfile - Go言語の
syscall
パッケージにおけるSyscall
関数群の解説: https://pkg.go.dev/syscall#Syscall - macOSの
sendfile
システムコールに関する情報 (Apple Developer Documentationなど) - Go言語のシステムコール呼び出しに関するQiita記事: https://qiita.com/tenntenn/items/5221712212212212212 (一般的なGoのシステムコール呼び出しの仕組みについて)
- Go言語の
unsafe
パッケージに関するドキュメント: https://pkg.go.dev/unsafe