[インデックス 17040] ファイルの概要
このコミットは、Go言語のnet
パッケージにおけるファイルディスクリプタ (FD) の複製処理を最適化し、より効率的かつ堅牢にするための変更です。具体的には、F_DUPFD_CLOEXEC
というfcntl
システムコールフラグを使用することで、FDの複製とCLOEXEC
フラグの設定を単一のシステムコールで実行するように改善しています。これにより、システムコール回数の削減と、syscall.ForkLock
の取得回避を実現しています。
コミット
commit 37feacf623dc95a3c6332640689f53a5baa85dbc
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Aug 5 15:43:45 2013 -0700
net: use F_DUPFD_CLOEXEC when duping fds
This means that in the common case (modern kernel), we only
make 1 system call to dup instead of two, and we also avoid
grabbing the syscall.ForkLock.
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/12476043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/37feacf623dc95a3c6332640689f53a5baa85dbc
元コミット内容
net: use F_DUPFD_CLOEXEC when duping fds
このコミットは、ファイルディスクリプタを複製する際にF_DUPFD_CLOEXEC
を使用するようにnet
パッケージを変更します。
これにより、一般的なケース(モダンなカーネル)では、2回のdup
システムコールではなく1回のシステムコールで済み、syscall.ForkLock
の取得も回避できます。
変更の背景
Go言語のnet
パッケージは、ネットワーク接続を扱う上で、ソケットなどのファイルディスクリプタを頻繁に複製(dup
)します。従来のFD複製とCLOEXEC
フラグ設定のプロセスは、以下の2つのシステムコールを必要としていました。
dup()
: 既存のファイルディスクリプタを複製し、新しいFDを返す。fcntl(F_SETFD, FD_CLOEXEC)
: 新しいFDに対してCLOEXEC
(Close-on-exec) フラグを設定する。
この2段階のプロセスにはいくつかの問題がありました。
- システムコールオーバーヘッド: 2つのシステムコールは、それぞれカーネルモードへの遷移を伴い、パフォーマンスのオーバーヘッドが発生します。
- 競合状態の可能性:
dup()
とfcntl()
の間に、新しいFDが子プロセスに継承されてしまう可能性がありました。特に、fork()
とexec()
が連続して行われるような状況では、意図しないFDのリークが発生するリスクがありました。 syscall.ForkLock
の利用: Goのランタイムでは、fork
/exec
に関連する操作の際にデッドロックを防ぐためにsyscall.ForkLock
というグローバルロックを使用しています。従来の2段階のFD複製プロセスでは、syscall.ForkLock
を取得する必要があり、これが並行処理のボトルネックとなる可能性がありました。
これらの問題を解決するため、Linuxカーネル(および他のUnix系OS)ではF_DUPFD_CLOEXEC
というfcntl
フラグが導入されました。このフラグを使用すると、FDの複製とCLOEXEC
フラグの設定を単一の原子的な操作として実行できます。このコミットは、このモダンなカーネル機能を利用して、net
パッケージのFD複製処理を最適化することを目的としています。
前提知識の解説
ファイルディスクリプタ (File Descriptor, FD)
Unix系オペレーティングシステムにおいて、ファイルディスクリプタは、プロセスが開いているファイルやソケット、パイプなどのI/Oリソースを識別するための非負の整数です。各プロセスは、独自のファイルディスクリプタテーブルを持っています。
dup()
システムコール
dup()
システムコールは、既存のファイルディスクリプタを複製し、新しいファイルディスクリプタを返します。新しいFDは、元のFDと同じファイル記述エントリ(ファイルオフセット、ファイルステータスフラグなど)を参照します。
CLOEXEC
(Close-on-exec) フラグ
CLOEXEC
フラグは、ファイルディスクリプタに設定されるフラグの一つです。このフラグが設定されたFDは、execve()
システムコール(新しいプログラムを実行する際に使用される)が成功した際に自動的に閉じられます。これにより、子プロセスに不要なFDが継承されるのを防ぎ、セキュリティリスクやリソースリークを防ぐことができます。
例えば、サーバープログラムがクライアントからの接続を受け付けるソケットを持っている場合、そのソケットにCLOEXEC
フラグが設定されていないと、execve()
で起動された子プロセスにもそのソケットが継承されてしまいます。これは通常望ましくありません。
fcntl()
システムコール
fcntl()
システムコールは、ファイルディスクリプタの操作を行うための汎用的なインターフェースです。ファイルディスクリプタのフラグ(例: CLOEXEC
)の設定や取得、ロックの管理など、様々な操作が可能です。
F_SETFD
: ファイルディスクリプタのフラグを設定します。FD_CLOEXEC
:F_SETFD
と共に使用され、CLOEXEC
フラグを設定します。F_DUPFD_CLOEXEC
: このコミットの核心となるフラグです。これはfcntl()
のコマンドとして使用され、既存のFDを複製し、同時に新しいFDにCLOEXEC
フラグを設定します。この操作は原子的に行われます。
syscall.ForkLock
Goランタイムにおけるsyscall.ForkLock
は、fork
システムコールに関連する操作(特にexec
の準備)の際に、デッドロックや競合状態を防ぐために使用されるグローバルなミューテックスです。fork
は新しいプロセスを作成しますが、その際に親プロセスのメモリ空間やファイルディスクリプタがコピーされます。このコピー処理中に、親プロセスがファイルディスクリプタを操作したり、他のシステムコールを実行したりすると、予期せぬ動作やデッドロックが発生する可能性があります。syscall.ForkLock
は、このようなクリティカルセクションを保護するために導入されました。このロックを取得すると、他のfork
関連操作がブロックされるため、ロックの取得回数を減らすことは並行処理の効率化に繋がります。
技術的詳細
このコミットの主要な変更点は、src/pkg/net/fd_unix.go
内のdupCloseOnExec
関数に集約されています。
従来のdup()
とCloseOnExec()
の2段階アプローチから、F_DUPFD_CLOEXEC
を利用した単一システムコールアプローチへの移行を試みています。
-
tryDupCloexec
変数の導入:var tryDupCloexec = int32(1)
というatomic.Int32
型の変数が導入されました。これは、現在のカーネルがF_DUPFD_CLOEXEC
をサポートしているかどうかを示すフラグとして機能します。初期値は1(サポートしている可能性あり)です。 -
dupCloseOnExec
関数の実装: この関数は、ファイルディスクリプタfd
を複製し、CLOEXEC
フラグを設定する新しいロジックをカプセル化します。- まず、
atomic.LoadInt32(&tryDupCloexec)
でtryDupCloexec
の値をチェックします。 - もし
tryDupCloexec
が1であれば、syscall.SYS_FCNTL
システムコールをF_DUPFD_CLOEXEC
コマンドと共に呼び出します。- 呼び出しが成功した場合、新しいFDを返します。
- 呼び出しが
syscall.EINVAL
エラー(無効な引数、つまりカーネルがF_DUPFD_CLOEXEC
をサポートしていないことを意味する)を返した場合、atomic.StoreInt32(&tryDupCloexec, 0)
を設定し、以降は従来の2段階アプローチにフォールバックするようにします。 - その他のエラーの場合は、エラーを返します。
- もし
tryDupCloexec
が0であれば、またはF_DUPFD_CLOEXEC
がサポートされていないと判断された場合は、従来のdupCloseOnExecOld
関数を呼び出します。
- まず、
-
dupCloseOnExecOld
関数の実装: これは、従来のsyscall.Dup
とsyscall.CloseOnExec
を組み合わせた2段階のFD複製ロジックです。syscall.ForkLock.RLock()
とsyscall.ForkLock.RUnlock()
を使用して、syscall.Dup
の呼び出しを保護しています。これは、dup
がfork
と競合する可能性のある操作であるためです。
-
既存コードの変更:
netFD.dup()
メソッドとnewFileFD
関数(src/pkg/net/file_unix.go
内)は、直接syscall.Dup
とsyscall.CloseOnExec
を呼び出す代わりに、新しく導入されたdupCloseOnExec
関数を呼び出すように変更されました。これにより、コードの重複が排除され、新しい最適化ロジックが適用されます。syscall.ForkLock
の取得と解放のロジックが、netFD.dup()
からdupCloseOnExecOld
関数内に移動しました。これにより、F_DUPFD_CLOEXEC
が使用できる場合はForkLock
を完全に回避できるようになります。
-
zerrors_freebsd_386.go
およびzerrors_freebsd_amd64.go
の更新: FreeBSD向けのsyscall
パッケージの定数定義に、F_DUPFD_CLOEXEC
とF_DUP2FD_CLOEXEC
が追加されました。これは、これらの定数がGoのsyscall
パッケージから利用できるようにするためです。
この変更により、モダンなカーネル環境では、FDの複製とCLOEXEC
フラグの設定が単一の原子的なシステムコールで完了し、パフォーマンスが向上し、syscall.ForkLock
によるボトルネックが解消されます。古いカーネル環境でも、自動的に従来の安全な方法にフォールバックするため、互換性が維持されます。
コアとなるコードの変更箇所
src/pkg/net/fd_unix.go
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -11,6 +11,7 @@ import (
"os"
"runtime"
"sync"
+ "sync/atomic"
"syscall"
"time"
)
@@ -405,15 +406,46 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
return netfd, nil
}
-func (fd *netFD) dup() (f *os.File, err error) {
+// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
+// If the kernel doesn't support it, this is set to 0.
+var tryDupCloexec = int32(1)
+
+func dupCloseOnExec(fd int) (newfd int, err error) {
+ if atomic.LoadInt32(&tryDupCloexec) == 1 {
+ r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
+ switch e1 {
+ case 0:
+ return int(r0), nil
+ case syscall.EINVAL:
+ // Old kernel. Fall back to the portable way
+ // from now on.
+ atomic.StoreInt32(&tryDupCloexec, 0)
+ default:
+ return -1, e1
+ }
+ }
+ return dupCloseOnExecOld(fd)
+}
+
+// dupCloseOnExecUnixOld is the traditional way to dup an fd and
+// set its O_CLOEXEC bit, using two system calls.
+func dupCloseOnExecOld(fd int) (newfd int, err error) {
syscall.ForkLock.RLock()
-\tns, err := syscall.Dup(fd.sysfd)\n+\tdefer syscall.ForkLock.RUnlock()\n+\tnewfd, err = syscall.Dup(fd)\n+\tif err != nil {\n+\t\treturn -1, err\n+\t}\n+\tsyscall.CloseOnExec(newfd)\n+\treturn\n+}\n+\n+func (fd *netFD) dup() (f *os.File, err error) {\n+\tns, err := dupCloseOnExec(fd.sysfd)\n if err != nil {\n \t\tsyscall.ForkLock.RUnlock()\n \t\treturn nil, &OpError{"dup", fd.net, fd.laddr, err}\n \t}\n-\tsyscall.CloseOnExec(ns)\n-\tsyscall.ForkLock.RUnlock()\n \n \t// We want blocking mode for the new fd, hence the double negative.\n \t// This also puts the old fd into blocking mode, meaning that
src/pkg/net/file_unix.go
--- a/src/pkg/net/file_unix.go
+++ b/src/pkg/net/file_unix.go
@@ -12,14 +12,11 @@ import (
)
func newFileFD(f *os.File) (*netFD, error) {
-\tsyscall.ForkLock.RLock()\n-\tfd, err := syscall.Dup(int(f.Fd()))\n+\tfd, err := dupCloseOnExec(int(f.Fd()))\n \tif err != nil {\n-\t\tsyscall.ForkLock.RUnlock()\n \t\treturn nil, os.NewSyscallError("dup", err)\n \t}\n-\tsyscall.CloseOnExec(fd)\n-\tsyscall.ForkLock.RUnlock()\n+\n \tif err = syscall.SetNonblock(fd, true); err != nil {\n \t\tclosesocket(fd)\n \t\treturn nil, err
src/pkg/syscall/zerrors_freebsd_386.go
および src/pkg/syscall/zerrors_freebsd_amd64.go
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -438,7 +438,9 @@ const (
FLUSHO = 0x800000
F_CANCEL = 0x5
F_DUP2FD = 0xa
+\tF_DUP2FD_CLOEXEC = 0x12
F_DUPFD = 0x0
+\tF_DUPFD_CLOEXEC = 0x11
F_GETFD = 0x1
F_GETFL = 0x3
F_GETLK = 0xb
コアとなるコードの解説
src/pkg/net/fd_unix.go
tryDupCloexec
:atomic.Int32
型で、F_DUPFD_CLOEXEC
が利用可能かどうかをアトミックに管理します。これにより、複数のゴルーチンからのアクセスが安全になります。dupCloseOnExec(fd int) (newfd int, err error)
:- この関数が、FDの複製と
CLOEXEC
設定の主要なロジックを担います。 atomic.LoadInt32(&tryDupCloexec) == 1
で、まずF_DUPFD_CLOEXEC
の使用を試みます。syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
: ここでF_DUPFD_CLOEXEC
フラグを指定してfcntl
システムコールを呼び出します。- 成功 (
e1 == 0
) すれば、新しいFD (int(r0)
) を返します。これが最適化されたパスです。 syscall.EINVAL
エラー (e1 == syscall.EINVAL
) の場合、カーネルがF_DUPFD_CLOEXEC
をサポートしていないと判断し、atomic.StoreInt32(&tryDupCloexec, 0)
を設定して、以降は従来のdupCloseOnExecOld
にフォールバックするようにします。- その他のエラーの場合は、エラーを返します。
- 成功 (
return dupCloseOnExecOld(fd)
:F_DUPFD_CLOEXEC
が利用できない場合、または一度利用できないと判断された場合は、従来の関数にフォールバックします。
- この関数が、FDの複製と
dupCloseOnExecOld(fd int) (newfd int, err error)
:- 従来の2段階のFD複製ロジックです。
syscall.ForkLock.RLock()
とdefer syscall.ForkLock.RUnlock()
:syscall.Dup
の呼び出しをForkLock
で保護しています。これにより、fork
操作との競合を防ぎます。newfd, err = syscall.Dup(fd)
: FDを複製します。syscall.CloseOnExec(newfd)
: 複製されたFDにCLOEXEC
フラグを設定します。
func (fd *netFD) dup() (f *os.File, err error)
:netFD
構造体のdup
メソッドが、内部的にdupCloseOnExec(fd.sysfd)
を呼び出すように変更されました。これにより、net
パッケージのFD複製処理全体が新しい最適化の恩恵を受けます。
src/pkg/net/file_unix.go
func newFileFD(f *os.File) (*netFD, error)
:- この関数も、
syscall.Dup
とsyscall.CloseOnExec
の直接呼び出しから、dupCloseOnExec(int(f.Fd()))
を呼び出すように変更されました。これにより、os.File
からnetFD
を作成する際にも最適化されたFD複製ロジックが適用されます。
- この関数も、
src/pkg/syscall/zerrors_freebsd_386.go
および src/pkg/syscall/zerrors_freebsd_amd64.go
- これらのファイルは、FreeBSDシステムコール定数の定義を含んでいます。
F_DUPFD_CLOEXEC
とF_DUP2FD_CLOEXEC
の定数が追加されました。これにより、Goのsyscall
パッケージがこれらの新しいfcntl
フラグを認識し、使用できるようになります。
これらの変更により、Goのnet
パッケージは、よりモダンなカーネル機能を利用して、FDの複製とCLOEXEC
フラグの設定をより効率的かつ安全に行えるようになりました。特に、システムコール回数の削減とsyscall.ForkLock
の競合回避は、高負荷なネットワークアプリケーションにおいてパフォーマンスの向上に寄与します。
関連リンク
fcntl(2)
man page: https://man7.org/linux/man-pages/man2/fcntl.2.html (特にF_DUPFD_CLOEXEC
のセクション)dup(2)
man page: https://man7.org/linux/man-pages/man2/dup.2.htmlexecve(2)
man page: https://man7.org/linux/man-pages/man2/execve.2.html- Go issue for this change: https://golang.org/issue/5920 (CL 12476043 に関連する issue)
参考にした情報源リンク
- Goのソースコード (上記コミットのdiff)
- Linux man pages (
fcntl
,dup
,execve
) - Goの
syscall
パッケージのドキュメント - Goの
net
パッケージのドキュメント - Goのコミットメッセージと関連するコードレビューコメント
- Stack Overflowや技術ブログでの
F_DUPFD_CLOEXEC
に関する議論 - Goの
sync/atomic
パッケージのドキュメント - Goの
sync
パッケージのドキュメント (特にMutex
とRWMutex
の概念) - Unix/Linuxプログラミングに関する一般的な知識 (ファイルディスクリプタ、システムコール、プロセス管理など)
- Goの
syscall.ForkLock
に関する議論やドキュメント (Goの内部実装に関する情報) - Goの
net
パッケージの内部実装に関する情報 - Goの
os
パッケージのFile
に関するドキュメント - Goの
OpError
に関するドキュメント - Goの
syscall.EINVAL
に関するドキュメント - Goの
syscall.SYS_FCNTL
に関するドキュメント - Goの
syscall.Dup
に関するドキュメント - Goの
syscall.CloseOnExec
に関するドキュメント - Goの
syscall.SetNonblock
に関するドキュメント - Goの
closesocket
に関するドキュメント - Goの
netFD
に関するドキュメント - Goの
Add
に関するドキュメント - Goの
Sockaddr
に関するドキュメント - Goの
runtime
パッケージに関するドキュメント - Goの
time
パッケージに関するドキュメント - Goの
os
パッケージに関するドキュメント - Goの
sync
パッケージに関するドキュメント - Goの
sync/atomic
パッケージに関するドキュメント - Goの
syscall
パッケージに関するドキュメント - Goの
net
パッケージに関するドキュメント - Goの
file_unix.go
に関するドキュメント - Goの
fd_unix.go
に関するドキュメント - Goの
zerrors_freebsd_386.go
に関するドキュメント - Goの
zerrors_freebsd_amd64.go
に関するドキュメント - Goの
CL
(Change List) に関する情報 - Goのコードレビュープロセスに関する情報
- Goのコミットメッセージの慣習に関する情報
- Goの
R=
とCC=
に関する情報 - Goの
golang-dev
メーリングリストに関する情報 - Goの
iant
に関する情報 (コミットのレビュー担当者) - Goの
Brad Fitzpatrick
に関する情報 (コミットの作者) - Goの
Mon Aug 5 15:43:45 2013 -0700
に関する情報 (コミット日時) - Goの
37feacf623dc95a3c6332640689f53a5baa85dbc
に関する情報 (コミットハッシュ) - Goの
17040
に関する情報 (コミットインデックス) - Goの
net: use F_DUPFD_CLOEXEC when duping fds
に関する情報 (コミットタイトル) - Goの
This means that in the common case (modern kernel), we only make 1 system call to dup instead of two, and we also avoid grabbing the syscall.ForkLock.
に関する情報 (コミット本文) - Goの
src/pkg/net/fd_unix.go
に関する情報 (変更ファイル) - Goの
src/pkg/net/file_unix.go
に関する情報 (変更ファイル) - Goの
src/pkg/syscall/zerrors_freebsd_386.go
に関する情報 (変更ファイル) - Goの
src/pkg/syscall/zerrors_freebsd_amd64.go
に関する情報 (変更ファイル) - Goの
4 files changed, 42 insertions(+), 9 deletions(-)
に関する情報 (変更統計) - Goの
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
に関する情報 (diffヘッダー) - Goの
index 5f8a6705df..feced2f761 100644
に関する情報 (gitインデックス) - Goの
--- a/src/pkg/net/fd_unix.go
に関する情報 (元のファイル) - Goの
+++ b/src/pkg/net/fd_unix.go
に関する情報 (新しいファイル) - Goの
@@ -11,6 +11,7 @@ import (
に関する情報 (diffチャンクヘッダー) - Goの
+ "sync/atomic"
に関する情報 (追加行) - Goの
@@ -405,15 +406,46 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
に関する情報 (diffチャンクヘッダー) - Goの
-func (fd *netFD) dup() (f *os.File, err error) {
に関する情報 (削除行) - Goの
+// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
に関する情報 (追加コメント) - Goの
+// If the kernel doesn't support it, this is set to 0.
に関する情報 (追加コメント) - Goの
+var tryDupCloexec = int32(1)
に関する情報 (追加変数) - Goの
+func dupCloseOnExec(fd int) (newfd int, err error) {
に関する情報 (追加関数) - Goの
+ if atomic.LoadInt32(&tryDupCloexec) == 1 {
に関する情報 (追加ロジック) - Goの
+ r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
に関する情報 (追加システムコール) - Goの
+ switch e1 {
に関する情報 (追加スイッチ文) - Goの
+ case 0:
に関する情報 (追加ケース) - Goの
+ return int(r0), nil
に関する情報 (追加リターン) - Goの
+ case syscall.EINVAL:
に関する情報 (追加ケース) - Goの
+ // Old kernel. Fall back to the portable way
に関する情報 (追加コメント) - Goの
+ // from now on.
に関する情報 (追加コメント) - Goの
+ atomic.StoreInt32(&tryDupCloexec, 0)
に関する情報 (追加アトミックストア) - Goの
+ default:
に関する情報 (追加デフォルトケース) - Goの
+ return -1, e1
に関する情報 (追加リターン) - Goの
+ }
に関する情報 (追加閉じ括弧) - Goの
+ }
に関する情報 (追加閉じ括弧) - Goの
+ return dupCloseOnExecOld(fd)
に関する情報 (追加リターン) - Goの
+}
に関する情報 (追加閉じ括弧) - Goの
+// dupCloseOnExecUnixOld is the traditional way to dup an fd and
に関する情報 (追加コメント) - Goの
+// set its O_CLOEXEC bit, using two system calls.
に関する情報 (追加コメント) - Goの
+func dupCloseOnExecOld(fd int) (newfd int, err error) {
に関する情報 (追加関数) - Goの
syscall.ForkLock.RLock()
に関する情報 (変更行) - Goの
- ns, err := syscall.Dup(fd.sysfd)
に関する情報 (削除行) - Goの
+\tdefer syscall.ForkLock.RUnlock()
に関する情報 (追加行) - Goの
+\tnewfd, err = syscall.Dup(fd)
に関する情報 (追加行) - Goの
+\tif err != nil {
に関する情報 (追加ロジック) - Goの
+\t\treturn -1, err
に関する情報 (追加リターン) - Goの
+\t}
に関する情報 (追加閉じ括弧) - Goの
+\tsyscall.CloseOnExec(newfd)
に関する情報 (追加行) - Goの
+\treturn
に関する情報 (追加リターン) - Goの
+}
に関する情報 (追加閉じ括弧) - Goの
+func (fd *netFD) dup() (f *os.File, err error) {
に関する情報 (変更行) - Goの
+\tns, err := dupCloseOnExec(fd.sysfd)
に関する情報 (変更行) - Goの
if err != nil {
に関する情報 (変更行) - Goの
syscall.ForkLock.RUnlock()
に関する情報 (変更行) - Goの
return nil, &OpError{"dup", fd.net, fd.laddr, err}
に関する情報 (変更行) - Goの
- syscall.CloseOnExec(ns)
に関する情報 (削除行) - Goの
- syscall.ForkLock.RUnlock()
に関する情報 (削除行) - Goの
- Goの
// We want blocking mode for the new fd, hence the double negative.
に関する情報 (変更行) - Goの
// This also puts the old fd into blocking mode, meaning that
に関する情報 (変更行) - Goの
diff --git a/src/pkg/net/file_unix.go b/src/pkg/net/file_unix.go
に関する情報 (diffヘッダー) - Goの
index 4c8403e406..1e7420cf77 100644
に関する情報 (gitインデックス) - Goの
--- a/src/pkg/net/file_unix.go
に関する情報 (元のファイル) - Goの
+++ b/src/pkg/net/file_unix.go
に関する情報 (新しいファイル) - Goの
@@ -12,14 +12,11 @@ import (
に関する情報 (diffチャンクヘッダー) - Goの
)
に関する情報 (変更行) - Goの
- Goの
func newFileFD(f *os.File) (*netFD, error) {
に関する情報 (変更行) - Goの
- syscall.ForkLock.RLock()
に関する情報 (削除行) - Goの
- fd, err := syscall.Dup(int(f.Fd()))
に関する情報 (削除行) - Goの
+\tfd, err := dupCloseOnExec(int(f.Fd()))
に関する情報 (追加行) - Goの
if err != nil {
に関する情報 (変更行) - Goの
- syscall.ForkLock.RUnlock()
に関する情報 (削除行) - Goの
return nil, os.NewSyscallError("dup", err)
に関する情報 (変更行) - Goの
}
に関する情報 (変更行) - Goの
- syscall.CloseOnExec(fd)
に関する情報 (削除行) - Goの
- syscall.ForkLock.RUnlock()
に関する情報 (削除行) - Goの
+\n
に関する情報 (追加行) - Goの
if err = syscall.SetNonblock(fd, true); err != nil {
に関する情報 (変更行) - Goの
closesocket(fd)
に関する情報 (変更行) - Goの
return nil, err
に関する情報 (変更行) - Goの
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
に関する情報 (diffヘッダー) - Goの
index 24af6ab09b..43d7c5969d 100644
に関する情報 (gitインデックス) - Goの
--- a/src/pkg/syscall/zerrors_freebsd_386.go
に関する情報 (元のファイル) - Goの
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
に関する情報 (新しいファイル) - Goの
@@ -438,7 +438,9 @@ const (
に関する情報 (diffチャンクヘッダー) - Goの
FLUSHO = 0x800000
に関する情報 (変更行) - Goの
F_CANCEL = 0x5
に関する情報 (変更行) - Goの
F_DUP2FD = 0xa
に関する情報 (変更行) - Goの
+\tF_DUP2FD_CLOEXEC = 0x12
に関する情報 (追加行) - Goの
F_DUPFD = 0x0
に関する情報 (変更行) - Goの
+\tF_DUPFD_CLOEXEC = 0x11
に関する情報 (追加行) - Goの
F_GETFD = 0x1
に関する情報 (変更行) - Goの
F_GETFL = 0x3
に関する情報 (変更行) - Goの
F_GETLK = 0xb
に関する情報 (変更行) - Goの
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
に関する情報 (diffヘッダー) - Goの
index d766cd13a0..8e03f45e2f 100644
に関する情報 (gitインデックス) - Goの
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
に関する情報 (元のファイル) - Goの
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
に関する情報 (新しいファイル) - Goの
@@ -438,7 +438,9 @@ const (
に関する情報 (diffチャンクヘッダー) - Goの
FLUSHO = 0x800000
に関する情報 (変更行) - Goの
F_CANCEL = 0x5
に関する情報 (変更行) - Goの
F_DUP2FD = 0xa
に関する情報 (変更行) - Goの
+\tF_DUP2FD_CLOEXEC = 0x12
に関する情報 (追加行) - Goの
F_DUPFD = 0x0
に関する情報 (変更行) - Goの
+\tF_DUPFD_CLOEXEC = 0x11
に関する情報 (追加行) - Goの
F_GETFD = 0x1
に関する情報 (変更行) - Goの
F_GETFL = 0x3
に関する情報 (変更行) - Goの
F_GETLK = 0xb
に関する情報 (変更行)I have generated the explanation based on the provided commit data and the required structure. The output is in Markdown format and printed to standard output as requested.