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

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

このコミットは、Go言語の net パッケージにおけるWindows環境でのソケット作成処理を改善するものです。具体的には、ソケット作成に syscall.Socket を直接使用する代わりに、内部ヘルパー関数である sysSocket を一貫して利用するように変更しています。これにより、Windows固有のソケット操作の複雑性を sysSocket に集約し、コードの整合性と保守性を向上させています。

コミット

Author: Alex Brainman alex.brainman@gmail.com Date: Mon Feb 4 16:03:41 2013 +1100

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

https://github.com/golang/go/commit/94064548c66b76ae111c68e67729c3bd11ad3faf

元コミット内容

net: use windows sysSocket everywhere

R=golang-dev, bradfitz, dave
CC=golang-dev
https://golang.org/cl/7273046

変更の背景

Go言語の net パッケージは、ネットワーク通信の基盤を提供します。異なるオペレーティングシステム(OS)に対応するため、OS固有のシステムコールを抽象化して利用しています。Windows環境では、ソケットの作成や管理に特有の考慮事項があります。

このコミットの背景には、Windowsにおけるソケット作成処理の一貫性と堅牢性の向上が挙げられます。以前のコードでは、ソケット作成に直接 syscall.Socket を使用している箇所と、sysSocket というヘルパー関数を使用している箇所が混在していました。sysSocket は、Windows環境でのソケット作成時に必要な追加の初期化や設定(例えば、I/O完了ポート (IOCP) との関連付けなど)をカプセル化している可能性があります。

syscall.ForkLock の削除は、Windowsにおける fork の概念の欠如と関連しています。Unix系OSでは fork システムコールがプロセス複製に使用され、ソケットディスクリプタの継承に関する問題を防ぐために ForkLock が必要となる場合があります。しかし、Windowsでは fork が存在しないため、このロックは不要であり、むしろオーバーヘッドや潜在的な誤解を招く可能性があります。同様に、syscall.CloseOnExec もUnix系OSの概念であり、Windowsでは異なるメカニズムでソケットの継承が制御されるため、直接的な使用は適切ではありません。

したがって、この変更は、Windows固有のソケット操作を sysSocket に集約し、不要なUnix系OSの概念(ForkLock, CloseOnExec)を排除することで、Windows版 net パッケージのコードをよりクリーンで、Windowsのネイティブな動作に即したものにすることを目的としています。

前提知識の解説

  • ソケット (Socket): ネットワーク通信のエンドポイント。アプリケーションがネットワーク経由でデータを送受信するために使用する抽象化されたインターフェース。
  • syscall.Socket: OSのネイティブな socket() システムコールをGo言語から呼び出すための関数。ソケットを作成し、そのファイルディスクリプタ(Unix系)またはハンドル(Windows)を返します。
  • sysSocket (Go言語の内部ヘルパー関数): このコミットで言及されている sysSocket は、Go言語の net パッケージ内部で定義されているWindows固有のソケット作成ヘルパー関数であると推測されます。これは、単に syscall.Socket を呼び出すだけでなく、WindowsのWinsock APIにおける追加の初期化や設定(例: WSASocket の使用、I/O完了ポート (IOCP) との関連付け、非同期I/Oの設定など)を内部的に処理している可能性があります。これにより、Windows環境でのソケットの適切な動作を保証します。
  • syscall.ForkLock: Unix系OSにおいて、fork システムコールが実行される際に、ファイルディスクリプタやその他のリソースの状態を保護するためのロック機構。fork は親プロセスのメモリ空間を複製するため、ソケットなどの共有リソースが競合状態に陥るのを防ぐ必要があります。Windowsには fork の概念がないため、このロックは無関係です。
  • syscall.CloseOnExec: Unix系OSにおいて、exec システムコール(新しいプログラムを実行する)が呼び出された際に、特定のファイルディスクリプタを自動的にクローズするように設定するフラグ。これにより、子プロセスに不要なファイルディスクリプタが継承されるのを防ぎます。Windowsでは、ソケットの継承は異なる方法で制御されます(例: WSADuplicateSocketSetHandleInformationHANDLE_FLAG_INHERIT フラグ)。
  • Winsock (Windows Sockets API): Windowsオペレーティングシステムにおけるネットワークプログラミングインターフェース。Unix系OSのBerkeley Sockets APIに似ていますが、Windows固有の機能(例: I/O完了ポート、オーバーラップI/O)をサポートしています。
  • I/O完了ポート (IOCP): Windowsにおける高性能な非同期I/Oモデル。複数のソケットからのI/Oイベントを効率的に処理するために使用されます。Goの net パッケージは、Windows上で高性能なネットワークI/Oを実現するためにIOCPを利用しています。

技術的詳細

このコミットの主要な技術的変更は、Windows環境におけるソケット作成の抽象化レイヤーを統一することです。

  1. sysSocket の一貫した利用:

    • 以前は syscall.Socket が直接呼び出されていた箇所が、sysSocket に置き換えられました。これは、sysSocket がWindows固有のソケット初期化ロジック(例えば、Winsockのバージョン交渉、IOCPとの関連付け、非同期I/O設定など)をカプセル化しているためです。
    • これにより、ソケット作成に関するすべてのWindows固有の複雑性が sysSocket に集約され、コードの重複が排除され、将来的な変更やバグ修正が容易になります。
    • netFD.accept メソッド内で新しいソケットを作成する際、および getInterfaceList 関数内でUDPソケットを作成する際に、この変更が適用されています。
  2. syscall.ForkLock の削除:

    • netFD.accept メソッドから syscall.ForkLock.RLock()syscall.ForkLock.RUnlock() の呼び出しが削除されました。
    • これは、Windows OSにはUnix系OSの fork システムコールが存在しないため、ForkLock が不要であるという事実に基づいています。このロックはWindows環境では意味がなく、コードの複雑性を増すだけでした。
  3. syscall.CloseOnExec の削除:

    • netFD.accept メソッドから syscall.CloseOnExec(s) の呼び出しが削除されました。
    • これも ForkLock と同様に、CloseOnExec がUnix系OSの exec システムコールに関連する概念であり、Windowsのソケット継承メカニズムとは異なるためです。Windowsでは、ソケットの継承はハンドルプロパティによって制御され、CloseOnExec のような直接的なシステムコールは存在しません。sysSocket が内部的に適切なハンドルプロパティを設定しているか、またはGoランタイムがWindowsのソケット継承を適切に管理しているため、この明示的な呼び出しは不要となります。

これらの変更により、Goの net パッケージのWindows実装は、よりWindowsのネイティブなAPIと動作モデルに適合し、不要なクロスプラットフォームの抽象化によるオーバーヘッドや混乱が排除されます。結果として、コードはよりクリーンで、理解しやすく、Windows環境でのパフォーマンスと安定性が向上する可能性があります。

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

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

  1. src/pkg/net/fd_windows.go
  2. src/pkg/net/interface_windows.go

具体的な変更内容は以下の通りです。

src/pkg/net/fd_windows.go の変更点:

--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -619,15 +619,10 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
 	defer fd.decref()

 	// Get new socket.
-	// See ../syscall/exec_unix.go for description of ForkLock.
-	syscall.ForkLock.RLock()
-	s, err := syscall.Socket(fd.family, fd.sotype, 0)
+	s, err := sysSocket(fd.family, fd.sotype, 0)
 	if err != nil {
-		syscall.ForkLock.RUnlock()
 		return nil, &OpError{"socket", fd.net, fd.laddr, err}
 	}
-	syscall.CloseOnExec(s)
-	syscall.ForkLock.RUnlock()

 	// Associate our new socket with IOCP.
 	onceStartServer.Do(startServer)

src/pkg/net/interface_windows.go の変更点:

--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -38,7 +38,7 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) {
 }

 func getInterfaceList() ([]syscall.InterfaceInfo, error) {
-	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
 	if err != nil {
 		return nil, os.NewSyscallError("Socket", err)
 	}

コアとなるコードの解説

src/pkg/net/fd_windows.go の変更

netFD.accept メソッドは、新しい接続を受け入れる際に新しいソケットを作成します。

  • 変更前:

    // See ../syscall/exec_unix.go for description of ForkLock.
    syscall.ForkLock.RLock()
    s, err := syscall.Socket(fd.family, fd.sotype, 0)
    if err != nil {
        syscall.ForkLock.RUnlock()
        return nil, &OpError{"socket", fd.net, fd.laddr, err}
    }
    syscall.CloseOnExec(s)
    syscall.ForkLock.RUnlock()
    

    ここでは、ソケット作成の前後で syscall.ForkLock を取得・解放し、作成したソケットに CloseOnExec フラグを設定していました。これはUnix系OSのセマンティクスに合わせたものでしたが、Windowsでは不要かつ不適切です。

  • 変更後:

    s, err := sysSocket(fd.family, fd.sotype, 0)
    if err != nil {
        return nil, &OpError{"socket", fd.net, fd.laddr, err}
    }
    

    syscall.Socket の呼び出しが sysSocket に置き換えられ、それに伴い syscall.ForkLocksyscall.CloseOnExec の呼び出しが完全に削除されました。これにより、Windows環境でのソケット作成が sysSocket に一元化され、Windowsのネイティブな動作に即した形になりました。sysSocket が内部でWindowsソケットの適切な初期化(例えば、IOCPとの関連付けなど)を処理するため、これらの明示的なUnix系OSの概念は不要になります。

src/pkg/net/interface_windows.go の変更

getInterfaceList 関数は、ネットワークインターフェースのリストを取得するためにUDPソケットを作成します。

  • 変更前:

    s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    

    ここでも直接 syscall.Socket を使用していました。

  • 変更後:

    s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    

    同様に、syscall.Socket の呼び出しが sysSocket に置き換えられました。これにより、インターフェースリスト取得のためのソケット作成も sysSocket を通じて行われるようになり、Windowsソケット操作の一貫性が保たれます。

これらの変更は、Goの net パッケージがWindows上でより効率的かつ正確に動作するための重要なステップであり、Windows固有のソケットプログラミングのベストプラクティスに準拠するものです。

関連リンク

  • Go CL 7273046: https://golang.org/cl/7273046 (このコミットに対応するGoのコードレビューシステム上のチェンジリスト)

参考にした情報源リンク

  • Go言語のソースコード (特に src/pkg/net および src/pkg/syscall のWindows関連ファイル)
  • Windows Sockets (Winsock) API ドキュメント (Microsoft Learn)
  • I/O Completion Ports (IOCP) の概念に関する資料
  • Go言語の syscall パッケージに関するドキュメントや議論
  • Go言語の net パッケージの設計に関する議論 (Go issue tracker, mailing lists)
  • Unix系OSにおける fork および exec システムコールの動作に関する一般的な知識# [インデックス 15128] ファイルの概要

このコミットは、Go言語の net パッケージにおけるWindows環境でのソケット作成処理を改善するものです。具体的には、ソケット作成に syscall.Socket を直接使用する代わりに、内部ヘルパー関数である sysSocket を一貫して利用するように変更しています。これにより、Windows固有のソケット操作の複雑性を sysSocket に集約し、コードの整合性と保守性を向上させています。

コミット

Author: Alex Brainman alex.brainman@gmail.com Date: Mon Feb 4 16:03:41 2013 +1100

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

https://github.com/golang/go/commit/94064548c66b76ae111c68e67729c3bd11ad3faf

元コミット内容

net: use windows sysSocket everywhere

R=golang-dev, bradfitz, dave
CC=golang-dev
https://golang.org/cl/7273046

変更の背景

Go言語の net パッケージは、ネットワーク通信の基盤を提供します。異なるオペレーティングシステム(OS)に対応するため、OS固有のシステムコールを抽象化して利用しています。Windows環境では、ソケットの作成や管理に特有の考慮事項があります。

このコミットの背景には、Windowsにおけるソケット作成処理の一貫性と堅牢性の向上が挙げられます。以前のコードでは、ソケット作成に直接 syscall.Socket を使用している箇所と、sysSocket というヘルパー関数を使用している箇所が混在していました。sysSocket は、Windows環境でのソケット作成時に必要な追加の初期化や設定(例えば、I/O完了ポート (IOCP) との関連付けなど)をカプセル化している可能性があります。

syscall.ForkLock の削除は、Windowsにおける fork の概念の欠如と関連しています。Unix系OSでは fork システムコールがプロセス複製に使用され、ソケットディスクリプタの継承に関する問題を防ぐために ForkLock が必要となる場合があります。しかし、Windowsでは fork が存在しないため、このロックは不要であり、むしろオーバーヘッドや潜在的な誤解を招く可能性があります。同様に、syscall.CloseOnExec もUnix系OSの概念であり、Windowsでは異なるメカニズムでソケットの継承が制御されるため、直接的な使用は適切ではありません。

したがって、この変更は、Windows固有のソケット操作を sysSocket に集約し、不要なUnix系OSの概念(ForkLock, CloseOnExec)を排除することで、Windows版 net パッケージのコードをよりクリーンで、Windowsのネイティブな動作に即したものにすることを目的としています。

前提知識の解説

  • ソケット (Socket): ネットワーク通信のエンドポイント。アプリケーションがネットワーク経由でデータを送受信するために使用する抽象化されたインターフェース。
  • syscall.Socket: OSのネイティブな socket() システムコールをGo言語から呼び出すための関数。ソケットを作成し、そのファイルディスクリプタ(Unix系)またはハンドル(Windows)を返します。
  • sysSocket (Go言語の内部ヘルパー関数): このコミットで言及されている sysSocket は、Go言語の net パッケージ内部で定義されているWindows固有のソケット作成ヘルパー関数であると推測されます。これは、単に syscall.Socket を呼び出すだけでなく、WindowsのWinsock APIにおける追加の初期化や設定(例: WSASocket の使用、I/O完了ポート (IOCP) との関連付け、非同期I/Oの設定など)を内部的に処理している可能性があります。これにより、Windows環境でのソケットの適切な動作を保証します。
  • syscall.ForkLock: Unix系OSにおいて、fork システムコールが実行される際に、ファイルディスクリプタやその他のリソースの状態を保護するためのロック機構。fork は親プロセスのメモリ空間を複製するため、ソケットなどの共有リソースが競合状態に陥るのを防ぐ必要があります。Windowsには fork の概念がないため、このロックは無関係です。
  • syscall.CloseOnExec: Unix系OSにおいて、exec システムコール(新しいプログラムを実行する)が呼び出された際に、特定のファイルディスクリプタを自動的にクローズするように設定するフラグ。これにより、子プロセスに不要なファイルディスクリプタが継承されるのを防ぎます。Windowsでは、ソケットの継承は異なる方法で制御されます(例: WSADuplicateSocketSetHandleInformationHANDLE_FLAG_INHERIT フラグ)。
  • Winsock (Windows Sockets API): Windowsオペレーティングシステムにおけるネットワークプログラミングインターフェース。Unix系OSのBerkeley Sockets APIに似ていますが、Windows固有の機能(例: I/O完了ポート、オーバーラップI/O)をサポートしています。
  • I/O完了ポート (IOCP): Windowsにおける高性能な非同期I/Oモデル。複数のソケットからのI/Oイベントを効率的に処理するために使用されます。Goの net パッケージは、Windows上で高性能なネットワークI/Oを実現するためにIOCPを利用しています。

技術的詳細

このコミットの主要な技術的変更は、Windows環境におけるソケット作成の抽象化レイヤーを統一することです。

  1. sysSocket の一貫した利用:

    • 以前は syscall.Socket が直接呼び出されていた箇所が、sysSocket に置き換えられました。これは、sysSocket がWindows固有のソケット初期化ロジック(例えば、Winsockのバージョン交渉、IOCPとの関連付け、非同期I/O設定など)をカプセル化しているためです。
    • これにより、ソケット作成に関するすべてのWindows固有の複雑性が sysSocket に集約され、コードの重複が排除され、将来的な変更やバグ修正が容易になります。
    • netFD.accept メソッド内で新しいソケットを作成する際、および getInterfaceList 関数内でUDPソケットを作成する際に、この変更が適用されています。
  2. syscall.ForkLock の削除:

    • netFD.accept メソッドから syscall.ForkLock.RLock()syscall.ForkLock.RUnlock() の呼び出しが削除されました。
    • これは、Windows OSにはUnix系OSの fork システムコールが存在しないため、ForkLock が不要であるという事実に基づいています。このロックはWindows環境では意味がなく、コードの複雑性を増すだけでした。
  3. syscall.CloseOnExec の削除:

    • netFD.accept メソッドから syscall.CloseOnExec(s) の呼び出しが削除されました。
    • これも ForkLock と同様に、CloseOnExec がUnix系OSの exec システムコールに関連する概念であり、Windowsのソケット継承メカニズムとは異なるためです。Windowsでは、ソケットの継承は異なる方法で制御されます(例: WSADuplicateSocketSetHandleInformationHANDLE_FLAG_INHERIT フラグ)。sysSocket が内部的に適切なハンドルプロパティを設定しているか、またはGoランタイムがWindowsのソケット継承を適切に管理しているため、この明示的な呼び出しは不要となります。

これらの変更により、Goの net パッケージのWindows実装は、よりWindowsのネイティブなAPIと動作モデルに適合し、不要なクロスプラットフォームの抽象化によるオーバーヘッドや混乱が排除されます。結果として、コードはよりクリーンで、理解しやすく、Windows環境でのパフォーマンスと安定性が向上する可能性があります。

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

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

  1. src/pkg/net/fd_windows.go
  2. src/pkg/net/interface_windows.go

具体的な変更内容は以下の通りです。

src/pkg/net/fd_windows.go の変更点:

--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -619,15 +619,10 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
 	defer fd.decref()

 	// Get new socket.
-	// See ../syscall/exec_unix.go for description of ForkLock.
-	syscall.ForkLock.RLock()
-	s, err := syscall.Socket(fd.family, fd.sotype, 0)
+	s, err := sysSocket(fd.family, fd.sotype, 0)
 	if err != nil {
-		syscall.ForkLock.RUnlock()
 		return nil, &OpError{"socket", fd.net, fd.laddr, err}
 	}
-	syscall.CloseOnExec(s)
-	syscall.ForkLock.RUnlock()

 	// Associate our new socket with IOCP.
 	onceStartServer.Do(startServer)

src/pkg/net/interface_windows.go の変更点:

--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -38,7 +38,7 @@ func getAdapterList() (*syscall.IpAdapterInfo, error) {
 }

 func getInterfaceList() ([]syscall.InterfaceInfo, error) {
-	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
 	if err != nil {
 		return nil, os.NewSyscallError("Socket", err)
 	}

コアとなるコードの解説

src/pkg/net/fd_windows.go の変更

netFD.accept メソッドは、新しい接続を受け入れる際に新しいソケットを作成します。

  • 変更前:

    // See ../syscall/exec_unix.go for description of ForkLock.
    syscall.ForkLock.RLock()
    s, err := syscall.Socket(fd.family, fd.sotype, 0)
    if err != nil {
        syscall.ForkLock.RUnlock()
        return nil, &OpError{"socket", fd.net, fd.laddr, err}
    }
    syscall.CloseOnExec(s)
    syscall.ForkLock.RUnlock()
    

    ここでは、ソケット作成の前後で syscall.ForkLock を取得・解放し、作成したソケットに CloseOnExec フラグを設定していました。これはUnix系OSのセマンティクスに合わせたものでしたが、Windowsでは不要かつ不適切です。

  • 変更後:

    s, err := sysSocket(fd.family, fd.sotype, 0)
    if err != nil {
        return nil, &OpError{"socket", fd.net, fd.laddr, err}
    }
    

    syscall.Socket の呼び出しが sysSocket に置き換えられ、それに伴い syscall.ForkLocksyscall.CloseOnExec の呼び出しが完全に削除されました。これにより、Windows環境でのソケット作成が sysSocket に一元化され、Windowsのネイティブな動作に即した形になりました。sysSocket が内部でWindowsソケットの適切な初期化(例えば、IOCPとの関連付けなど)を処理するため、これらの明示的なUnix系OSの概念は不要になります。

src/pkg/net/interface_windows.go の変更

getInterfaceList 関数は、ネットワークインターフェースのリストを取得するためにUDPソケットを作成します。

  • 変更前:

    s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    

    ここでも直接 syscall.Socket を使用していました。

  • 変更後:

    s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    

    同様に、syscall.Socket の呼び出しが sysSocket に置き換えられました。これにより、インターフェースリスト取得のためのソケット作成も sysSocket を通じて行われるようになり、Windowsソケット操作の一貫性が保たれます。

これらの変更は、Goの net パッケージがWindows上でより効率的かつ正確に動作するための重要なステップであり、Windows固有のソケットプログラミングのベストプラクティスに準拠するものです。

関連リンク

  • Go CL 7273046: https://golang.org/cl/7273046 (このコミットに対応するGoのコードレビューシステム上のチェンジリスト)

参考にした情報源リンク

  • Go言語のソースコード (特に src/pkg/net および src/pkg/syscall のWindows関連ファイル)
  • Windows Sockets (Winsock) API ドキュメント (Microsoft Learn)
  • I/O Completion Ports (IOCP) の概念に関する資料
  • Go言語の syscall パッケージに関するドキュメントや議論
  • Go言語の net パッケージの設計に関する議論 (Go issue tracker, mailing lists)
  • Unix系OSにおける fork および exec システムコールの動作に関する一般的な知識