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

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

このコミットは、Go言語の標準ライブラリ net パッケージにおける変更です。具体的には、Unixドメインソケットのアドレスを表す UnixAddr 型が、ネットワークエンドポイントアドレスの共通インターフェースである sockaddr を実装するように修正されています。これにより、Goランタイムがネットワーク操作をより統一的に扱えるようになり、特にBSD系のシステムにおけるランタイム統合型ネットワークポーラーの準備が整えられました。

コミット

commit a64bea5c99a7d6b471655cdef44b8daec6fce1dc
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Sun Jul 28 16:15:07 2013 +0900

    net: make UnixAddr implement sockaddr interface
    
    This is in preparation for runtime-integrated network pollster for BSD
    variants.
    
    Update #5199
    
    R=golang-dev, dave
    CC=golang-dev
    https://golang.org/cl/11932044

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

https://github.com/golang/go/commit/a64bea5c99a7d6b471655cdef44b8daec6fce1dc

元コミット内容

net: make UnixAddr implement sockaddr interface

This is in preparation for runtime-integrated network pollster for BSD
variants.

Update #5199

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

変更の背景

この変更の主な背景は、GoランタイムがネットワークI/Oをより効率的かつ統一的に処理するための基盤を強化することにあります。特に、BSD系のオペレーティングシステム(FreeBSD, OpenBSD, NetBSDなど)では、ネットワークイベントの監視(ポーリング)メカニズムがLinuxなどとは異なる場合があります。Goのランタイムは、これらのシステムで最適なパフォーマンスを発揮するために、ネットワークポーラー(イベント通知メカニズム)をランタイムに統合する必要があります。

sockaddr インターフェースは、TCP、UDP、IPなどの様々なネットワークアドレス型を抽象化するためのものです。UnixAddr(Unixドメインソケットのアドレス)がこのインターフェースを実装することで、GoランタイムはUnixドメインソケットに対しても、他のネットワークソケットと同様の統一された方法でネットワークポーリングを適用できるようになります。これにより、コードの重複を避け、保守性を高め、異なるOS間でのネットワーク処理の互換性を向上させることが可能になります。

また、コミットメッセージにある Update #5199 は、関連するIssue(課題)の進捗を示しています。これは、Goのネットワークスタックにおける特定の改善やバグ修正に関連している可能性があります。

前提知識の解説

1. Go言語の net パッケージ

Go言語の net パッケージは、ネットワークI/Oプリミティブを提供します。TCP/IP、UDP、Unixドメインソケットなど、様々なネットワークプロトコルを扱うための型や関数が含まれています。

2. sockaddr インターフェース

sockaddr は、Goの net パッケージ内部で定義されているインターフェースです。これは、ネットワークエンドポイントのアドレス(例: IPアドレスとポート番号、Unixドメインソケットのパス)を抽象化するために使用されます。このインターフェースを実装する型は、システムコール層で利用される syscall.Sockaddr 型に変換できる必要があります。

元の定義では、sockaddr はTCP、UDP、IPネットワークエンドポイントアドレスを対象としていましたが、このコミットでUnixネットワークエンドポイントも対象に含めるようにコメントが更新されています。

// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
// address that can be converted into a syscall.Sockaddr.
type sockaddr interface {
    Addr
    family() int
    sockaddr(family int) (syscall.Sockaddr, error)
    toAddr() sockaddr
}

(注: コミット時点の sockaddr インターフェースの定義は、family() メソッドのみを持つシンプルなものでしたが、後のコミットで sockaddr()toAddr() メソッドが追加され、より汎用的なインターフェースになっています。このコミットは、UnixAddr がこのインターフェースを実装するための最初のステップです。)

3. UnixAddr

UnixAddr は、Unixドメインソケットのアドレスを表すGoの型です。Unixドメインソケットは、同じホスト上のプロセス間通信(IPC)に使用されるソケットで、ファイルシステム上のパス名に関連付けられます。

type UnixAddr struct {
    Net  string // "unix", "unixgram" or "unixpacket"
    Name string // path name
}

4. syscall.Sockaddr

syscall パッケージは、オペレーティングシステムの低レベルなシステムコールへのアクセスを提供します。syscall.Sockaddr は、C言語の struct sockaddr に対応する型で、OSのネットワーク関連システムコール(例: bind, connect)に渡されるソケットアドレス情報を保持します。

5. ネットワークポーラー (Network Pollster)

ネットワークポーラーは、複数のネットワークI/O操作(ソケットの読み書きなど)を効率的に監視し、準備ができたイベントを通知するメカニズムです。OSによって epoll (Linux), kqueue (BSD), IOCP (Windows) など、様々な実装があります。Goランタイムは、これらのOS固有のポーリングメカニズムを抽象化し、Goのゴルーチンと連携して非同期I/Oを実現しています。

6. ランタイム統合 (Runtime-integrated)

Goのランタイムは、ゴルーチンのスケジューリング、ガベージコレクション、ネットワークI/Oの非同期処理など、Goプログラムの実行を管理する重要なコンポーネントです。ネットワークポーラーが「ランタイム統合」されるとは、ネットワークI/OイベントがGoのスケジューラと密接に連携し、I/Oブロッキングを最小限に抑えながら、多数の同時接続を効率的に処理できるように設計されていることを意味します。

技術的詳細

このコミットの技術的な核心は、UnixAddr 型が sockaddr インターフェースの要件を満たすように変更された点にあります。

具体的には、以下の変更が行われました。

  1. sockaddr インターフェースのコメント更新: src/pkg/net/sock_posix.go 内の sockaddr インターフェースのコメントが更新され、Unixネットワークエンドポイントもこのインターフェースの対象であることが明示されました。

    --- a/src/pkg/net/sock_posix.go
    +++ b/src/pkg/net/sock_posix.go
    @@ -11,8 +11,8 @@ import (
     	"time"
     )
     
    -// A sockaddr represents a TCP, UDP, IP network endpoint address that
    -// can be converted into a syscall.Sockaddr.
    +// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
    +// address that can be converted into a syscall.Sockaddr.
     type sockaddr interface {
     	Addr
     	family() int
    
  2. UnixAddr へのメソッド追加: src/pkg/net/unixsock_posix.go に、UnixAddrsockaddr インターフェースを実装するために必要なメソッドが追加されました。

    • func (a *UnixAddr) family() int: syscall.AF_UNIX を返します。これはUnixドメインソケットのアドレスファミリーを示します。
    • func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error): UnixAddrsyscall.SockaddrUnix 型に変換して返します。これはOSのシステムコールに渡すための形式です。
    • func (a *UnixAddr) toAddr() sockaddr: UnixAddr 自体を sockaddr インターフェースとして返します。これにより、UnixAddrsockaddr インターフェースの要件を満たします。
  3. isUnnamed() から isWildcard() への変更: src/pkg/net/unixsock_posix.go で、isUnnamed() メソッドが isWildcard() に名称変更されました。機能的には同じで、アドレスが指定されていない(ワイルドカード)状態を判定します。これは、より一般的な「ワイルドカードアドレス」という概念に合わせた命名変更と考えられます。

    // isWildcard reports whether a is a wildcard address.
    func (a *UnixAddr) isWildcard() bool {
        return a == nil || a.Name == ""
    }
    

    そして、unixSocket 関数内で isUnnamed() の代わりに isWildcard() が使用されるように更新されました。

  4. 不要な toAddr() メソッドの削除: src/pkg/net/unixsock.go から、UnixAddrtoAddr() メソッドが削除されました。これは、UnixAddr が直接 sockaddr インターフェースを実装するようになったため、以前の Addr インターフェースへの変換ロジックが不要になったためです。

これらの変更により、UnixAddrnet パッケージ内の他のネットワークアドレス型(TCPAddr, UDPAddr, IPAddr など)と同様に、sockaddr インターフェースを通じて統一的に扱えるようになりました。これは、Goのネットワークスタックが、異なるソケットタイプやOSの特性を抽象化し、より堅牢で効率的なI/O処理を実現するための重要なステップです。特に、BSD系のシステムで kqueue などのポーリングメカニズムをGoランタイムに統合する際に、この統一されたインターフェースが役立ちます。

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

src/pkg/net/sock_posix.go

--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -11,8 +11,8 @@ import (
 	"time"
 )
 
-// A sockaddr represents a TCP, UDP, IP network endpoint address that
-// can be converted into a syscall.Sockaddr.
+// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
+// address that can be converted into a syscall.Sockaddr.
 type sockaddr interface {
 	Addr
 	family() int

src/pkg/net/unixsock.go

--- a/src/pkg/net/unixsock.go
+++ b/src/pkg/net/unixsock.go
@@ -23,13 +23,6 @@ func (a *UnixAddr) String() string {
 	return a.Name
 }
 
-func (a *UnixAddr) toAddr() Addr {
-	if a == nil { // nil *UnixAddr
-		return nil // nil interface
-	}
-	return a
-}
-
 // ResolveUnixAddr parses addr as a Unix domain socket address.
 // The string net gives the network name, "unix", "unixgram" or
 // "unixpacket".

src/pkg/net/unixsock_posix.go

--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -13,13 +13,6 @@ import (
 	"time"
 )
 
-func (a *UnixAddr) isUnnamed() bool {
-	if a == nil || a.Name == "" {
-		return true
-	}
-	return false
-}
-
 func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.Time) (*netFD, error) {
 	var sotype int
 	switch net {
@@ -36,12 +29,12 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T
 	var la, ra syscall.Sockaddr
 	switch mode {
 	case "dial":
-		if !laddr.isUnnamed() {
+		if !laddr.isWildcard() {
 			la = &syscall.SockaddrUnix{Name: laddr.Name}
 		}
 		if raddr != nil {
 			ra = &syscall.SockaddrUnix{Name: raddr.Name}
-		} else if sotype != syscall.SOCK_DGRAM || laddr.isUnnamed() {
+		} else if sotype != syscall.SOCK_DGRAM || laddr.isWildcard() {
 			return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress}
 		}
 	case "listen":
@@ -106,6 +99,29 @@ func sotypeToNet(sotype int) string {
 	}
 }
 
+func (a *UnixAddr) family() int {
+	return syscall.AF_UNIX
+}
+
+// isWildcard reports whether a is a wildcard address.
+func (a *UnixAddr) isWildcard() bool {
+	return a == nil || a.Name == ""
+}
+
+func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
+	if a == nil {
+		return nil, nil
+	}
+	return &syscall.SockaddrUnix{Name: a.Name}, nil
+}
+
+func (a *UnixAddr) toAddr() sockaddr {
+	if a == nil {
+		return nil
+	}
+	return a
+}
+
 // UnixConn is an implementation of the Conn interface for connections
 // to Unix domain sockets.
 type UnixConn struct {

コアとなるコードの解説

このコミットの主要な変更は、UnixAddr 型が sockaddr インターフェースを完全に実装するようにした点です。

  1. sockaddr インターフェースの定義拡張(コメントのみ): src/pkg/net/sock_posix.go では、sockaddr インターフェースの目的を説明するコメントが更新され、Unixネットワークエンドポイントもこのインターフェースの対象であることが明示されました。これは、UnixAddr がこのインターフェースを実装する意図を明確にするものです。

  2. UnixAddr への family(), isWildcard(), sockaddr(), toAddr() メソッドの追加: src/pkg/net/unixsock_posix.go に追加されたこれらのメソッドが、UnixAddrsockaddr インターフェースに適合させます。

    • family() int: Unixドメインソケットのアドレスファミリーである syscall.AF_UNIX を返します。これにより、ソケットの種類を識別できます。
    • isWildcard() bool: アドレスがワイルドカード(未指定)であるかを判定します。これは、ソケットのバインドや接続時に特定のアドレスが指定されているかを確認するために使用されます。以前の isUnnamed() と同じロジックですが、より汎用的な命名になりました。
    • sockaddr(family int) (syscall.Sockaddr, error): UnixAddr の情報をOSのシステムコールが理解できる syscall.SockaddrUnix 型に変換します。これは、bind()connect() などのシステムコールにアドレス情報を渡す際に不可欠です。
    • toAddr() sockaddr: UnixAddr 自体を sockaddr インターフェースとして返します。これにより、UnixAddr のインスタンスを sockaddr 型として扱うことが可能になり、ポリモーフィックな処理が実現されます。
  3. unixSocket 関数での isWildcard() の利用: unixSocket 関数は、Unixドメインソケットを作成する内部関数です。この関数内で、アドレスがワイルドカードであるかどうかのチェックに、新しく定義された isWildcard() メソッドが使用されるようになりました。これにより、コードの一貫性が保たれます。

  4. src/pkg/net/unixsock.go からの toAddr() の削除: 以前の UnixAddr には、Addr インターフェースを返す toAddr() メソッドがありましたが、UnixAddr が直接 sockaddr インターフェース(Addr を埋め込んでいる)を実装するようになったため、この古いメソッドは不要となり削除されました。

これらの変更により、Goのネットワークスタックは、Unixドメインソケットを他のネットワークソケット(TCP/IPなど)と統一された方法で扱えるようになり、特にBSD系のシステムにおけるランタイム統合型ネットワークポーラーの実装が容易になりました。これは、Goのクロスプラットフォーム対応とネットワークI/O効率化に向けた重要な基盤整備の一環です。

関連リンク

参考にした情報源リンク

  • Go言語の net パッケージのドキュメント: https://pkg.go.dev/net
  • Go言語の syscall パッケージのドキュメント: https://pkg.go.dev/syscall
  • Unixドメインソケットに関する一般的な情報 (例: Wikipediaなど)
  • Goのネットワークポーラーに関する情報 (Goのソースコードや関連する設計ドキュメント)
    • GoのネットワークI/Oの内部動作に関するブログ記事やプレゼンテーション (例: "Go's netpoller" などで検索)
    • Goのランタイムとスケジューラに関する一般的な情報