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

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

このコミットは、Go言語の標準ライブラリであるnetパッケージにおけるWindowsビルドの不具合を修正するものです。具体的には、ファイルディスクリプタの参照カウント管理に関連するコードと、エラーハンドリングの一部が修正されています。

コミット

  • コミットハッシュ: 8c4fecdcb9abdd7cc6b4b0e97fad936c87ddb4c0
  • Author: Mikio Hara mikioh.mikioh@gmail.com
  • Date: Tue Feb 14 14:57:57 2012 +0900
  • コミットメッセージ:
    net: fix windows build
    
    R=rsc, bradfitz
    CC=golang-dev
    https://golang.org/cl/5661055
    

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

https://github.com/golang/go/commit/8c4fecdcb9abdd7cc6b4b0e97fad936c87ddb4c0

元コミット内容

net: fix windows build

R=rsc, bradfitz
CC=golang-dev
https://golang.org/cl/5661055

変更の背景

このコミットは、Go言語のnetパッケージがWindows環境で正しくビルドされない、または実行時に問題が発生する可能性があったため、その不具合を修正するために行われました。特に、ファイルディスクリプタ(netFD)の参照カウント管理(incref/decref)の呼び出し方や、エラー返却値の型がWindows固有の挙動と合致していなかったことが原因と考えられます。

前提知識の解説

  • netパッケージ: Go言語の標準ライブラリで、ネットワークI/O機能を提供します。TCP/UDP通信、HTTPクライアント/サーバーなどが含まれます。
  • ファイルディスクリプタ (File Descriptor, FD): オペレーティングシステムがファイルやソケットなどのI/Oリソースを識別するために使用する抽象的なハンドルです。Goのnetパッケージでは、ネットワーク接続をnetFDという構造体で抽象化し、その内部でOSのファイルディスクリプタを管理しています。
  • 参照カウント (Reference Counting): オブジェクトがどれだけの場所から参照されているかを数えるメモリ管理の手法の一つです。参照カウントが0になると、そのオブジェクトは不要と判断され、解放されます。Go言語では主にガベージコレクションがメモリ管理に用いられますが、特定のOSリソース(ファイルディスクリプタなど)のライフサイクル管理には、参照カウントのようなメカニズムが用いられることがあります。
  • increfdecref: increfは参照カウントをインクリメント(増加)し、decrefはデクリメント(減少)する関数です。これにより、リソースが使用されている間は解放されないようにし、使用されなくなったら安全に解放できるようにします。
  • pollserver: Goのnetパッケージ内部で、ノンブロッキングI/O操作を効率的に処理するためのポーリングメカニズムです。OSのI/O多重化機能(例: Linuxのepoll、WindowsのI/O Completion Ports)を抽象化し、複数のネットワーク操作を同時に監視・処理します。pollserver.Lock()pollserver.Unlock()は、このポーリングメカニズムへのアクセスを同期するためのロックです。
  • syscall.Sockaddr: オペレーティングシステムのシステムコールで使用されるソケットアドレス構造体を抽象化したものです。
  • nil0: Go言語では、ポインタやインターフェースのゼロ値はnilです。数値型(例: int)のゼロ値は0です。エラーを返す際に、ポインタ型の戻り値(例: *netFD)に対してはnilを、数値型に対しては0を返すのが一般的です。

技術的詳細

このコミットは、主に以下の3つのファイルに対する変更を含んでいます。

  1. src/pkg/net/fd.go:

    • netFD構造体内のsysmusysrefフィールドのコメント行のインデントが修正されました。これはコードの可読性向上のための整形変更であり、機能的な変更ではありません。
    • netFD.Close()メソッド内でpollserver.Lock()のコメントが修正されました。これも整形変更です。
  2. src/pkg/net/fd_windows.go:

    • errorsパッケージがインポートに追加されました。これは、netFD.accept()メソッドでエラーを返す際にnilを使用するために必要となります。
    • netFD.accept()メソッドの戻り値の型が変更されました。以前はエラー時に0を返していましたが、*netFD型の戻り値に対してはnilを返すように修正されました。これはGoの慣習に沿った変更であり、特にWindows環境でのポインタの扱いに関連する問題を防ぐ可能性があります。
  3. src/pkg/net/sendfile_windows.go:

    • sendFile関数内でc.incref()の呼び出しがc.incref(false)に変更されました。incref関数は引数としてブール値を取るように定義されており、この変更により正しい引数が渡されるようになりました。これにより、参照カウントの管理がWindows環境で正しく行われるようになります。

これらの変更は、GoのnetパッケージがWindows上で安定して動作するための重要な修正です。特に、参照カウントの適切な管理と、Goの型システムに合わせたエラーハンドリングの修正が中心となっています。

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

src/pkg/net/fd.go

--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -18,9 +18,9 @@ import (
 // Network file descriptor.
 type netFD struct {
 	// locking/lifetime of sysfd
-	sysmu   sync.Mutex
-	sysref  int
-	
+	sysmu  sync.Mutex
+	sysref int
+
 	// must lock both sysmu and pollserver to write
 	// can lock either to read
 	closing bool
@@ -376,7 +376,7 @@ func (fd *netFD) decref() {
 }

 func (fd *netFD) Close() error {
-	pollserver.Lock()  // needed for both fd.incref(true) and pollserver.Evict
+	pollserver.Lock() // needed for both fd.incref(true) and pollserver.Evict
 	defer pollserver.Unlock()
 	if err := fd.incref(true); err != nil {
 		return err

src/pkg/net/fd_windows.go

--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -5,6 +5,7 @@
 package net

 import (
+	"errors"
 	"io"
 	"os"
 	"runtime"
@@ -518,7 +519,7 @@ func (o *acceptOp) Name() string {

 func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (*netFD, error) {
 	if err := fd.incref(false); err != nil {
-		return 0, err
+		return nil, err
 	}
 	defer fd.decref()

src/pkg/net/sendfile_windows.go

--- a/src/pkg/net/sendfile_windows.go
+++ b/src/pkg/net/sendfile_windows.go
@@ -50,7 +50,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {

 	c.wio.Lock()
 	defer c.wio.Unlock()
-	if err := c.incref(); err != nil {
+	if err := c.incref(false); err != nil {
 		return 0, err, true
 	}
 	defer c.decref()

コアとなるコードの解説

  • src/pkg/net/fd.goの変更:

    • netFD構造体内のsysmusysrefのコメントのインデントが修正されました。これはコードの整形であり、機能的な影響はありません。
    • netFD.Close()内のpollserver.Lock()のコメントも同様に整形です。
  • src/pkg/net/fd_windows.goの変更:

    • import ("errors")の追加: netFD.accept()関数内でエラー時にnilを返すために、errorsパッケージが必要になりました。
    • return 0, errからreturn nil, errへの変更: netFD.accept()*netFD型のポインタを返すため、エラー時にはポインタのゼロ値であるnilを返すのがGoの慣習です。以前の0は数値のゼロ値であり、型が合致しない可能性がありました。この修正により、型安全性が向上し、Windows環境での潜在的なバグが修正されます。
  • src/pkg/net/sendfile_windows.goの変更:

    • c.incref()からc.incref(false)への変更: incref関数は引数としてブール値を受け取るように定義されています。以前の呼び出しでは引数が不足しており、コンパイルエラーや予期せぬ動作を引き起こす可能性がありました。falseを明示的に渡すことで、increfの正しい使用法に準拠し、参照カウントの管理が適切に行われるようになります。これは特にWindows環境でのsendfile操作の安定性に寄与します。

これらの変更は、GoのnetパッケージがWindows環境でより堅牢に動作するための、細かではあるが重要な修正です。

関連リンク

参考にした情報源リンク