[インデックス 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
インターフェースの要件を満たすように変更された点にあります。
具体的には、以下の変更が行われました。
-
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
-
UnixAddr
へのメソッド追加:src/pkg/net/unixsock_posix.go
に、UnixAddr
がsockaddr
インターフェースを実装するために必要なメソッドが追加されました。func (a *UnixAddr) family() int
:syscall.AF_UNIX
を返します。これはUnixドメインソケットのアドレスファミリーを示します。func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error)
:UnixAddr
をsyscall.SockaddrUnix
型に変換して返します。これはOSのシステムコールに渡すための形式です。func (a *UnixAddr) toAddr() sockaddr
:UnixAddr
自体をsockaddr
インターフェースとして返します。これにより、UnixAddr
がsockaddr
インターフェースの要件を満たします。
-
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()
が使用されるように更新されました。 -
不要な
toAddr()
メソッドの削除:src/pkg/net/unixsock.go
から、UnixAddr
のtoAddr()
メソッドが削除されました。これは、UnixAddr
が直接sockaddr
インターフェースを実装するようになったため、以前のAddr
インターフェースへの変換ロジックが不要になったためです。
これらの変更により、UnixAddr
は net
パッケージ内の他のネットワークアドレス型(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
インターフェースを完全に実装するようにした点です。
-
sockaddr
インターフェースの定義拡張(コメントのみ):src/pkg/net/sock_posix.go
では、sockaddr
インターフェースの目的を説明するコメントが更新され、Unixネットワークエンドポイントもこのインターフェースの対象であることが明示されました。これは、UnixAddr
がこのインターフェースを実装する意図を明確にするものです。 -
UnixAddr
へのfamily()
,isWildcard()
,sockaddr()
,toAddr()
メソッドの追加:src/pkg/net/unixsock_posix.go
に追加されたこれらのメソッドが、UnixAddr
をsockaddr
インターフェースに適合させます。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
型として扱うことが可能になり、ポリモーフィックな処理が実現されます。
-
unixSocket
関数でのisWildcard()
の利用:unixSocket
関数は、Unixドメインソケットを作成する内部関数です。この関数内で、アドレスがワイルドカードであるかどうかのチェックに、新しく定義されたisWildcard()
メソッドが使用されるようになりました。これにより、コードの一貫性が保たれます。 -
src/pkg/net/unixsock.go
からのtoAddr()
の削除: 以前のUnixAddr
には、Addr
インターフェースを返すtoAddr()
メソッドがありましたが、UnixAddr
が直接sockaddr
インターフェース(Addr
を埋め込んでいる)を実装するようになったため、この古いメソッドは不要となり削除されました。
これらの変更により、Goのネットワークスタックは、Unixドメインソケットを他のネットワークソケット(TCP/IPなど)と統一された方法で扱えるようになり、特にBSD系のシステムにおけるランタイム統合型ネットワークポーラーの実装が容易になりました。これは、Goのクロスプラットフォーム対応とネットワークI/O効率化に向けた重要な基盤整備の一環です。
関連リンク
- Go Issue 5199: https://github.com/golang/go/issues/5199 (このコミットが
Update #5199
と関連しているため) - Go CL 11932044: https://golang.org/cl/11932044 (このコミットのChangeListページ)
参考にした情報源リンク
- 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のランタイムとスケジューラに関する一般的な情報