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

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

このコミットは、Go言語の標準ライブラリであるsyscallパッケージ内のソケットコントロールメッセージ(Socket Control Messages、またはAncillary Data)を扱うコードの簡素化を目的としています。具体的には、src/pkg/syscall/sockcmsg_linux.gosrc/pkg/syscall/sockcmsg_unix.goの2つのファイルが変更されています。これらのファイルは、LinuxおよびUnix系システムにおけるソケットを介した補助データの送受信、特にプロセス間でファイルディスクリプタや認証情報をやり取りする機能を提供します。

コミット

このコミットは、ソケットコントロールメッセージを扱うコードの可読性とGo言語のイディオムへの準拠を向上させるためのリファクタリングです。機能的な変更は含まれておらず、主に変数名の短縮とコードの記述方法の簡素化が行われています。

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

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

元コミット内容

commit c241f696f87a1d0aaf1cc28eb6383e73184ef837
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Tue Jan 15 08:52:22 2013 +0900

    syscall: simplify socket control messages
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/7016044

変更の背景

この変更の背景には、Go言語のコードベース全体における一貫性と可読性の向上という一般的な目標があります。特に、syscallパッケージのような低レベルで複雑なコードにおいては、簡潔でイディオムに沿った記述が重要になります。

このコミットは、以下の点を改善するために行われました。

  1. 変数名の簡素化: bufbに、cmsghに、msgmに短縮することで、Go言語の慣習(短い変数名を好む傾向)に合わせ、コードの視覚的なノイズを減らしています。これにより、コードがより簡潔になり、一目で何が行われているかを把握しやすくなります。
  2. 冗長なインポートの削除: unsafeパッケージのインポートが重複していた箇所が削除されました。これは、Goのツールが自動的にインポートを管理するようになったり、コンパイラが不要なインポートを検出するようになったりした結果として行われる一般的なクリーンアップです。
  3. 構造体初期化の簡潔化: SocketControlMessage構造体の初期化が、より直接的なリテラル形式で行われるようになりました。これにより、コードの行数が減り、意図が明確になります。

これらの変更は、機能的な振る舞いを一切変更することなく、コードの保守性と理解しやすさを向上させるための純粋なリファクタリングです。

前提知識の解説

Go言語のsyscallパッケージ

syscallパッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、ファイル操作、プロセス管理、ネットワーク通信など、OSカーネルが提供する基本的な機能にアクセスできます。このパッケージは、Goの標準ライブラリの他の高レベルなパッケージ(例: netos)の基盤としても機能します。低レベルな操作のため、unsafeパッケージと組み合わせてC言語の構造体やメモリレイアウトを直接扱うことがよくあります。

ソケットコントロールメッセージ (Socket Control Messages / Ancillary Data)

ソケットコントロールメッセージは、Unixドメインソケット(または一部の他のソケットタイプ)を介して、通常のデータストリームとは別に補助的な情報を送受信するためのメカニズムです。これはsendmsg()およびrecvmsg()システムコールによって処理されます。主な用途は以下の通りです。

  • ファイルディスクリプタの受け渡し (SCM_RIGHTS): プロセス間でオープンされたファイルディスクリプタ(ソケット、ファイル、パイプなど)を安全に受け渡すことができます。これにより、子プロセスが親プロセスからリソースを継承したり、異なるプロセス間でリソースを共有したりすることが可能になります。
  • 認証情報の受け渡し (SCM_CREDENTIALS): 送信元のプロセスのユーザーID、グループID、プロセスIDなどの認証情報を相手プロセスに渡すことができます。これは、Unixドメインソケットを介したローカルな認証メカニズムとして利用されます。

これらのメッセージは、Cmsghdr構造体とそれに続くデータで構成されます。

Cmsghdr構造体

Cmsghdrは、ソケットコントロールメッセージのヘッダを定義する構造体です。主要なフィールドは以下の通りです。

  • cmsg_len: コントロールメッセージ全体の長さ(ヘッダとデータを含む)。
  • cmsg_level: メッセージのプロトコルレベル(例: SOL_SOCKET)。
  • cmsg_type: メッセージのタイプ(例: SCM_RIGHTSSCM_CREDENTIALS)。

この構造体は、C言語のAPIと直接やり取りするために、Goのunsafeパッケージを使ってメモリ上で直接操作されることが一般的です。

unsafeパッケージとポインタ操作

Go言語は通常、ポインタ演算を制限し、メモリ安全性を重視します。しかし、unsafeパッケージを使用すると、Goの型システムを迂回して、C言語のようにポインタを直接操作したり、異なる型のポインタ間で変換したりすることが可能になります。syscallパッケージのようにOSの低レベルなAPIと連携する場合、C言語の構造体とGoのバイトスライス間でデータを効率的にやり取りするために、unsafe.Pointeruintptrを用いたポインタ演算が不可欠となります。

  • unsafe.Pointer: 任意の型のポインタを保持できる汎用ポインタ。型チェックを無効にする。
  • uintptr: ポインタの値を整数として表現する型。ポインタ演算を行う際に使用される。

Goのイディオムとコードスタイル

Go言語には、公式のスタイルガイドやコミュニティで広く受け入れられているコーディング慣習(イディオム)があります。

  • 短い変数名: 特にスコープが狭い、または型が明確な変数には、ijb(バイトスライス)、r(リーダー)、w(ライター)、err(エラー)などの短い変数名が好まれます。これにより、コードが簡潔になり、読みやすくなります。
  • エラーハンドリング: Goはエラーを戻り値として明示的に返すことを推奨しており、if err != nilパターンが一般的です。
  • 構造体リテラル: 構造体の初期化には、フィールド名を明示的に指定する構造体リテラルがよく使われます。

このコミットは、これらのGoのイディオムに沿ってコードを改善しています。

技術的詳細

このコミットで行われた変更は、主に以下の3つのカテゴリに分類されます。

  1. 変数名の変更:

    • buf (buffer) -> b
    • cmsg (control message header) -> h
    • msg (socket control message) -> m
    • e (error) -> err (これはParseSocketControlMessage関数内のみ) これらの変更は、Go言語の慣習に従い、スコープが限定的で型が明確な変数に対して短い名前を使用するという原則を適用したものです。これにより、コードの行が短くなり、視覚的なノイズが減少し、コードの意図がより迅速に把握できるようになります。
  2. 冗長なimport "unsafe"の削除: src/pkg/syscall/sockcmsg_linux.gosrc/pkg/syscall/sockcmsg_unix.goの両方で、import ("unsafe")という行が削除されています。これは、Goのビルドシステムやリンターが、実際に使用されているパッケージのみをインポートするように最適化された結果、あるいは以前のコードで明示的にインポートされていたものが、Goのバージョンアップに伴い不要になったためと考えられます。unsafeパッケージは、unsafe.Pointeruintptrがコード内で使用されている限り、自動的にインポートされるため、明示的なインポート文は冗長になります。

  3. ParseSocketControlMessage関数内の構造体初期化の簡潔化: src/pkg/syscall/sockcmsg_unix.goParseSocketControlMessage関数内で、SocketControlMessage構造体の初期化方法が変更されました。

    変更前:

    m := SocketControlMessage{}
    m.Header = *h
    m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
    cmsgs = append(cmsgs, m)
    

    変更後:

    m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]}
    msgs = append(msgs, m)
    

    これは、Goの構造体リテラルを使用して、構造体のフィールドを一度に初期化する、より簡潔な方法です。これにより、コードの行数が減り、mがどのように構築されるかがより明確になります。また、エラー変数名もeからerrに変更され、Goの標準的なエラー変数名に統一されています。

これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のベストプラクティスとスタイルガイドに沿ってコードベースを改善するためのものです。

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

src/pkg/syscall/sockcmsg_linux.go

--- a/src/pkg/syscall/sockcmsg_linux.go
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -6,33 +6,31 @@
 
  package syscall
  
 -import (
 -	"unsafe"
 -)
 +import "unsafe"
  
  // UnixCredentials encodes credentials into a socket control message
  // for sending to another process. This can be used for
  // authentication.
  func UnixCredentials(ucred *Ucred) []byte {
 --	buf := make([]byte, CmsgSpace(SizeofUcred))
 --	cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
 --	cmsg.Level = SOL_SOCKET
 --	cmsg.Type = SCM_CREDENTIALS
 --	cmsg.SetLen(CmsgLen(SizeofUcred))
 --	*((*Ucred)(cmsgData(cmsg))) = *ucred
 --	return buf
 -+	b := make([]byte, CmsgSpace(SizeofUcred))
 -+	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
 -+	h.Level = SOL_SOCKET
 -+	h.Type = SCM_CREDENTIALS
 -+	h.SetLen(CmsgLen(SizeofUcred))
 -+	*((*Ucred)(cmsgData(h))) = *ucred
 -+	return b
  }
  
  // ParseUnixCredentials decodes a socket control message that contains
  // credentials in a Ucred structure. To receive such a message, the
  // SO_PASSCRED option must be enabled on the socket.
 -func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, error) {
 --	if msg.Header.Level != SOL_SOCKET {
 -+func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
 -+	if m.Header.Level != SOL_SOCKET {
  		return nil, EINVAL
  	}
 --	if msg.Header.Type != SCM_CREDENTIALS {
 -+	if m.Header.Type != SCM_CREDENTIALS {
  		return nil, EINVAL
  	}
 --	ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
 -+	ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
  	return &ucred, nil
  }

src/pkg/syscall/sockcmsg_unix.go

--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -8,9 +8,7 @@
 
  package syscall
  
 -import (
 -	"unsafe"
 -)
 +import "unsafe"
  
  // Round the length of a raw sockaddr up to align it propery.
  func cmsgAlignOf(salen int) int {
@@ -38,77 +36,69 @@ func CmsgSpace(datalen int) int {
  	return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
  }
  
 -func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
 --	return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
 -+func cmsgData(h *Cmsghdr) unsafe.Pointer {
 -+	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
  }
  
 -// SocketControlMessage represents a socket control message.
  type SocketControlMessage struct {
  	Header Cmsghdr
  	Data   []byte
  }
  
 -func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
 --	var (
 --		h     *Cmsghdr
 --		dbuf  []byte
 --		e     error
 --		cmsgs []SocketControlMessage
 --	)
 --
 --	for len(buf) >= CmsgLen(0) {
 --		h, dbuf, e = socketControlMessageHeaderAndData(buf)
 --		if e != nil {
 --			break
 --		}
 --		m := SocketControlMessage{}
 --		m.Header = *h
 --		m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
 --		cmsgs = append(cmsgs, m)
 --		buf = buf[cmsgAlignOf(int(h.Len)):]
 -+func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
 -+	var msgs []SocketControlMessage
 -+	for len(b) >= CmsgLen(0) {
 -+		h, dbuf, err := socketControlMessageHeaderAndData(b)
 -+		if err != nil {
 -+			return nil, err
 -+		}
 -+		m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]}
 -+		msgs = append(msgs, m)
 -+		b = b[cmsgAlignOf(int(h.Len)):]
  	}
 --
 --	return cmsgs, e
 -+	return msgs, nil
  }
  
 -func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
 --	h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
 --	if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
 -+func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
 -+	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
 -+	if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
  		return nil, nil, EINVAL
  	}
 --	return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
 -+	return h, b[cmsgAlignOf(SizeofCmsghdr):], nil
  }
  
  // UnixRights encodes a set of open file descriptors into a socket
  // control message for sending to another process.
  func UnixRights(fds ...int) []byte {
  	datalen := len(fds) * 4
 --	buf := make([]byte, CmsgSpace(datalen))
 --	cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
 --	cmsg.Level = SOL_SOCKET
 --	cmsg.Type = SCM_RIGHTS
 --	cmsg.SetLen(CmsgLen(datalen))
 --
 --	data := uintptr(cmsgData(cmsg))
 -+	b := make([]byte, CmsgSpace(datalen))
 -+	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
 -+	h.Level = SOL_SOCKET
 -+	h.Type = SCM_RIGHTS
 -+	h.SetLen(CmsgLen(datalen))
 -+	data := uintptr(cmsgData(h))
  	for _, fd := range fds {
  		*(*int32)(unsafe.Pointer(data)) = int32(fd)
  		data += 4
  	}
 --
 --	return buf
 -+	return b
  }
  
  // ParseUnixRights decodes a socket control message that contains an
  // integer array of open file descriptors from another process.
 -func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
 --	if msg.Header.Level != SOL_SOCKET {
 -+func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
 -+	if m.Header.Level != SOL_SOCKET {
  		return nil, EINVAL
  	}
 --	if msg.Header.Type != SCM_RIGHTS {
 -+	if m.Header.Type != SCM_RIGHTS {
  		return nil, EINVAL
  	}
 --	fds := make([]int, len(msg.Data)>>2)
 --	for i, j := 0, 0; i < len(msg.Data); i += 4 {
 --		fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
 -+	fds := make([]int, len(m.Data)>>2)
 -+	for i, j := 0, 0; i < len(m.Data); i += 4 {
 -+		fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
  		j++
  	}
  	return fds, nil

コアとなるコードの解説

src/pkg/syscall/sockcmsg_linux.go

  • UnixCredentials 関数:
    • 変更前: bufcmsgという変数名を使用していました。
    • 変更後: bhという短い変数名に変更されました。機能的な変更はありません。bufはバイトスライス、cmsgCmsghdrポインタを指すため、それぞれbhに短縮されています。
  • ParseUnixCredentials 関数:
    • 変更前: 引数msgを使用していました。
    • 変更後: 引数mという短い変数名に変更されました。関数内部でのmsg.Header.Levelmsg.Dataへのアクセスもm.Header.Levelm.Dataに変更されています。機能的な変更はありません。

src/pkg/syscall/sockcmsg_unix.go

  • import "unsafe" の削除:
    • ファイル冒頭のimport ("unsafe")が削除されました。これは、Goのコンパイラがコード内でunsafeパッケージの機能(例: unsafe.Pointer)が使用されていることを検出すると、自動的にインポートするため、明示的なインポート文が不要になったためです。
  • cmsgData 関数:
    • 変更前: 引数cmsgを使用していました。
    • 変更後: 引数hという短い変数名に変更されました。機能的な変更はありません。
  • ParseSocketControlMessage 関数:
    • 変更前: 引数buf、内部変数h, dbuf, e, cmsgsを使用していました。SocketControlMessageの初期化は複数行に分かれていました。
    • 変更後: 引数b、内部変数h, dbuf, err, msgsという短い変数名に変更されました。特にエラー変数eがGoの慣習であるerrに変更されています。
    • 最も顕著な変更は、SocketControlMessage構造体の初期化が、m := SocketControlMessage{Header: *h, Data: ...}という単一行の構造体リテラルに簡潔化された点です。これにより、コードの可読性が向上し、意図がより明確になります。
  • socketControlMessageHeaderAndData 関数:
    • 変更前: 引数bufを使用していました。
    • 変更後: 引数bという短い変数名に変更されました。機能的な変更はありません。
  • UnixRights 関数:
    • 変更前: bufcmsgという変数名を使用していました。
    • 変更後: bhという短い変数名に変更されました。機能的な変更はありません。
  • ParseUnixRights 関数:
    • 変更前: 引数msgを使用していました。
    • 変更後: 引数mという短い変数名に変更されました。機能的な変更はありません。

これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のコーディングスタイルとイディオムに沿ってコードをより簡潔で読みやすいものにするためのものです。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Linux man pages (sendmsg, cmsg)
  • Go言語のコーディングスタイルに関する一般的な情報源
  • Gerrit Change-ID: https://golang.org/cl/7016044 (これはGoプロジェクトのコードレビューシステムへのリンクであり、コミットの詳細な議論や変更の経緯を確認できます。)

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

このコミットは、Go言語の標準ライブラリであるsyscallパッケージ内のソケットコントロールメッセージ(Socket Control Messages、またはAncillary Data)を扱うコードの簡素化を目的としています。具体的には、src/pkg/syscall/sockcmsg_linux.gosrc/pkg/syscall/sockcmsg_unix.goの2つのファイルが変更されています。これらのファイルは、LinuxおよびUnix系システムにおけるソケットを介した補助データの送受信、特にプロセス間でファイルディスクリプタや認証情報をやり取りする機能を提供します。

コミット

このコミットは、ソケットコントロールメッセージを扱うコードの可読性とGo言語のイディオムへの準拠を向上させるためのリファクタリングです。機能的な変更は含まれておらず、主に変数名の短縮とコードの記述方法の簡素化が行われています。

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

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

元コミット内容

commit c241f696f87a1d0aaf1cc28eb6383e73184ef837
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date:   Tue Jan 15 08:52:22 2013 +0900

    syscall: simplify socket control messages
    
    R=golang-dev, iant
    CC=golang-dev
    https://golang.org/cl/7016044

変更の背景

この変更の背景には、Go言語のコードベース全体における一貫性と可読性の向上という一般的な目標があります。特に、syscallパッケージのような低レベルで複雑なコードにおいては、簡潔でイディオムに沿った記述が重要になります。

このコミットは、以下の点を改善するために行われました。

  1. 変数名の簡素化: bufbに、cmsghに、msgmに短縮することで、Go言語の慣習(短い変数名を好む傾向)に合わせ、コードの視覚的なノイズを減らしています。これにより、コードがより簡潔になり、一目で何が行われているかを把握しやすくなります。
  2. 冗長なインポートの削除: unsafeパッケージのインポートが重複していた箇所が削除されました。これは、Goのツールが自動的にインポートを管理するようになったり、コンパイラが不要なインポートを検出するようになったりした結果として行われる一般的なクリーンアップです。
  3. 構造体初期化の簡潔化: SocketControlMessage構造体の初期化が、より直接的なリテラル形式で行われるようになりました。これにより、コードの行数が減り、意図が明確になります。

これらの変更は、機能的な振る舞いを一切変更することなく、コードの保守性と理解しやすさを向上させるための純粋なリファクタリングです。

前提知識の解説

Go言語のsyscallパッケージ

syscallパッケージは、Goプログラムからオペレーティングシステム(OS)のシステムコールを直接呼び出すための低レベルなインターフェースを提供します。これにより、ファイル操作、プロセス管理、ネットワーク通信など、OSカーネルが提供する基本的な機能にアクセスできます。このパッケージは、Goの標準ライブラリの他の高レベルなパッケージ(例: netos)の基盤としても機能します。低レベルな操作のため、unsafeパッケージと組み合わせてC言語の構造体やメモリレイアウトを直接扱うことがよくあります。

ソケットコントロールメッセージ (Socket Control Messages / Ancillary Data)

ソケットコントロールメッセージは、Unixドメインソケット(または一部の他のソケットタイプ)を介して、通常のデータストリームとは別に補助的な情報を送受信するためのメカニズムです。これはsendmsg()およびrecvmsg()システムコールによって処理されます。主な用途は以下の通りです。

  • ファイルディスクリプタの受け渡し (SCM_RIGHTS): プロセス間でオープンされたファイルディスクリプタ(ソケット、ファイル、パイプなど)を安全に受け渡すことができます。これにより、子プロセスが親プロセスからリソースを継承したり、異なるプロセス間でリソースを共有したりすることが可能になります。
  • 認証情報の受け渡し (SCM_CREDENTIALS): 送信元のプロセスのユーザーID、グループID、プロセスIDなどの認証情報を相手プロセスに渡すことができます。これは、Unixドメインソケットを介したローカルな認証メカニズムとして利用されます。

これらのメッセージは、Cmsghdr構造体とそれに続くデータで構成されます。

Cmsghdr構造体

Cmsghdrは、ソケットコントロールメッセージのヘッダを定義する構造体です。主要なフィールドは以下の通りです。

  • cmsg_len: コントロールメッセージ全体の長さ(ヘッダとデータを含む)。
  • cmsg_level: メッセージのプロトコルレベル(例: SOL_SOCKET)。
  • cmsg_type: メッセージのタイプ(例: SCM_RIGHTSSCM_CREDENTIALS)。

この構造体は、C言語のAPIと直接やり取りするために、Goのunsafeパッケージを使ってメモリ上で直接操作されることが一般的です。

unsafeパッケージとポインタ操作

Go言語は通常、ポインタ演算を制限し、メモリ安全性を重視します。しかし、unsafeパッケージを使用すると、Goの型システムを迂回して、C言語のようにポインタを直接操作したり、異なる型のポインタ間で変換したりすることが可能になります。syscallパッケージのようにOSの低レベルなAPIと連携する場合、C言語の構造体とGoのバイトスライス間でデータを効率的にやり取りするために、unsafe.Pointeruintptrを用いたポインタ演算が不可欠となります。

  • unsafe.Pointer: 任意の型のポインタを保持できる汎用ポインタ。型チェックを無効にする。
  • uintptr: ポインタの値を整数として表現する型。ポインタ演算を行う際に使用される。

Goのイディオムとコードスタイル

Go言語には、公式のスタイルガイドやコミュニティで広く受け入れられているコーディング慣習(イディオム)があります。

  • 短い変数名: 特にスコープが狭い、または型が明確な変数には、ijb(バイトスライス)、r(リーダー)、w(ライター)、err(エラー)などの短い変数名が好まれます。これにより、コードが簡潔になり、読みやすくなります。
  • エラーハンドリング: Goはエラーを戻り値として明示的に返すことを推奨しており、if err != nilパターンが一般的です。
  • 構造体リテラル: 構造体の初期化には、フィールド名を明示的に指定する構造体リテラルがよく使われます。

このコミットは、これらのGoのイディオムに沿ってコードを改善しています。

技術的詳細

このコミットで行われた変更は、主に以下の3つのカテゴリに分類されます。

  1. 変数名の変更:

    • buf (buffer) -> b
    • cmsg (control message header) -> h
    • msg (socket control message) -> m
    • e (error) -> err (これはParseSocketControlMessage関数内のみ) これらの変更は、Go言語の慣習に従い、スコープが限定的で型が明確な変数に対して短い名前を使用するという原則を適用したものです。これにより、コードの行が短くなり、視覚的なノイズが減少し、コードの意図がより迅速に把握できるようになります。
  2. 冗長なimport "unsafe"の削除: src/pkg/syscall/sockcmsg_linux.gosrc/pkg/syscall/sockcmsg_unix.goの両方で、import ("unsafe")という行が削除されています。これは、Goのビルドシステムやリンターが、実際に使用されているパッケージのみをインポートするように最適化された結果、あるいは以前のコードで明示的にインポートされていたものが、Goのバージョンアップに伴い不要になったためと考えられます。unsafeパッケージは、unsafe.Pointeruintptrがコード内で使用されている限り、自動的にインポートされるため、明示的なインポート文は冗長になります。

  3. ParseSocketControlMessage関数内の構造体初期化の簡潔化: src/pkg/syscall/sockcmsg_unix.goParseSocketControlMessage関数内で、SocketControlMessage構造体の初期化方法が変更されました。

    変更前:

    m := SocketControlMessage{}
    m.Header = *h
    m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
    cmsgs = append(cmsgs, m)
    

    変更後:

    m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]}
    msgs = append(msgs, m)
    

    これは、Goの構造体リテラルを使用して、構造体のフィールドを一度に初期化する、より簡潔な方法です。これにより、コードの行数が減り、mがどのように構築されるかがより明確になります。また、エラー変数名もeからerrに変更され、Goの標準的なエラー変数名に統一されています。

これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のベストプラクティスとスタイルガイドに沿ってコードベースを改善するためのものです。

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

src/pkg/syscall/sockcmsg_linux.go

--- a/src/pkg/syscall/sockcmsg_linux.go
+++ b/src/pkg/syscall/sockcmsg_linux.go
@@ -6,33 +6,31 @@
 
  package syscall
  
 -import (
 -	"unsafe"
 -)
 +import "unsafe"
  
  // UnixCredentials encodes credentials into a socket control message
  // for sending to another process. This can be used for
  // authentication.
  func UnixCredentials(ucred *Ucred) []byte {
 --	buf := make([]byte, CmsgSpace(SizeofUcred))
 --	cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
 --	cmsg.Level = SOL_SOCKET
 --	cmsg.Type = SCM_CREDENTIALS
 --	cmsg.SetLen(CmsgLen(SizeofUcred))
 --	*((*Ucred)(cmsgData(cmsg))) = *ucred
 --	return buf
 -+	b := make([]byte, CmsgSpace(SizeofUcred))
 -+	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
 -+	h.Level = SOL_SOCKET
 -+	h.Type = SCM_CREDENTIALS
 -+	h.SetLen(CmsgLen(SizeofUcred))
 -+	*((*Ucred)(cmsgData(h))) = *ucred
 -+	return b
  }
  
  // ParseUnixCredentials decodes a socket control message that contains
  // credentials in a Ucred structure. To receive such a message, the
  // SO_PASSCRED option must be enabled on the socket.
 -func ParseUnixCredentials(msg *SocketControlMessage) (*Ucred, error) {
 --	if msg.Header.Level != SOL_SOCKET {
 -+func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
 -+	if m.Header.Level != SOL_SOCKET {
  		return nil, EINVAL
  	}
 --	if msg.Header.Type != SCM_CREDENTIALS {
 -+	if m.Header.Type != SCM_CREDENTIALS {
  		return nil, EINVAL
  	}
 --	ucred := *(*Ucred)(unsafe.Pointer(&msg.Data[0]))
 -+	ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
  	return &ucred, nil
  }

src/pkg/syscall/sockcmsg_unix.go

--- a/src/pkg/syscall/sockcmsg_unix.go
+++ b/src/pkg/syscall/sockcmsg_unix.go
@@ -8,9 +8,7 @@
 
  package syscall
  
 -import (
 -	"unsafe"
 -)
 +import "unsafe"
  
  // Round the length of a raw sockaddr up to align it propery.
  func cmsgAlignOf(salen int) int {
@@ -38,77 +36,69 @@ func CmsgSpace(datalen int) int {
  	return cmsgAlignOf(SizeofCmsghdr) + cmsgAlignOf(datalen)
  }
  
 -func cmsgData(cmsg *Cmsghdr) unsafe.Pointer {
 --	return unsafe.Pointer(uintptr(unsafe.Pointer(cmsg)) + SizeofCmsghdr)
 -+func cmsgData(h *Cmsghdr) unsafe.Pointer {
 -+	return unsafe.Pointer(uintptr(unsafe.Pointer(h)) + SizeofCmsghdr)
  }
  
 -// SocketControlMessage represents a socket control message.
  type SocketControlMessage struct {
  	Header Cmsghdr
  	Data   []byte
  }
  
 -func ParseSocketControlMessage(buf []byte) ([]SocketControlMessage, error) {
 --	var (
 --		h     *Cmsghdr
 --		dbuf  []byte
 --		e     error
 --		cmsgs []SocketControlMessage
 --	)
 --
 --	for len(buf) >= CmsgLen(0) {
 --		h, dbuf, e = socketControlMessageHeaderAndData(buf)
 --		if e != nil {
 --			break
 --		}
 --		m := SocketControlMessage{}
 --		m.Header = *h
 --		m.Data = dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]
 --		cmsgs = append(cmsgs, m)
 --		buf = buf[cmsgAlignOf(int(h.Len)):]
 -+func ParseSocketControlMessage(b []byte) ([]SocketControlMessage, error) {
 -+	var msgs []SocketControlMessage
 -+	for len(b) >= CmsgLen(0) {
 -+		h, dbuf, err := socketControlMessageHeaderAndData(b)
 -+		if err != nil {
 -+			return nil, err
 -+		}
 -+		m := SocketControlMessage{Header: *h, Data: dbuf[:int(h.Len)-cmsgAlignOf(SizeofCmsghdr)]}
 -+		msgs = append(msgs, m)
 -+		b = b[cmsgAlignOf(int(h.Len)):]
  	}
 --
 --	return cmsgs, e
 -+	return msgs, nil
  }
  
 -func socketControlMessageHeaderAndData(buf []byte) (*Cmsghdr, []byte, error) {
 --	h := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
 --	if h.Len < SizeofCmsghdr || int(h.Len) > len(buf) {
 -+func socketControlMessageHeaderAndData(b []byte) (*Cmsghdr, []byte, error) {
 -+	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
 -+	if h.Len < SizeofCmsghdr || int(h.Len) > len(b) {
  		return nil, nil, EINVAL
  	}
 --	return h, buf[cmsgAlignOf(SizeofCmsghdr):], nil
 -+	return h, b[cmsgAlignOf(SizeofCmsghdr):], nil
  }
  
  // UnixRights encodes a set of open file descriptors into a socket
  // control message for sending to another process.
  func UnixRights(fds ...int) []byte {
  	datalen := len(fds) * 4
 --	buf := make([]byte, CmsgSpace(datalen))
 --	cmsg := (*Cmsghdr)(unsafe.Pointer(&buf[0]))
 --	cmsg.Level = SOL_SOCKET
 --	cmsg.Type = SCM_RIGHTS
 --	cmsg.SetLen(CmsgLen(datalen))
 --
 --	data := uintptr(cmsgData(cmsg))
 -+	b := make([]byte, CmsgSpace(datalen))
 -+	h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
 -+	h.Level = SOL_SOCKET
 -+	h.Type = SCM_RIGHTS
 -+	h.SetLen(CmsgLen(datalen))
 -+	data := uintptr(cmsgData(h))
  	for _, fd := range fds {
  		*(*int32)(unsafe.Pointer(data)) = int32(fd)
  		data += 4
  	}
 --
 --	return buf
 -+	return b
  }
  
  // ParseUnixRights decodes a socket control message that contains an
  // integer array of open file descriptors from another process.
 -func ParseUnixRights(msg *SocketControlMessage) ([]int, error) {
 --	if msg.Header.Level != SOL_SOCKET {
 -+func ParseUnixRights(m *SocketControlMessage) ([]int, error) {
 -+	if m.Header.Level != SOL_SOCKET {
  		return nil, EINVAL
  	}
 --	if msg.Header.Type != SCM_RIGHTS {
 -+	if m.Header.Type != SCM_RIGHTS {
  		return nil, EINVAL
  	}
 --	fds := make([]int, len(msg.Data)>>2)
 --	for i, j := 0, 0; i < len(msg.Data); i += 4 {
 --		fds[j] = int(*(*int32)(unsafe.Pointer(&msg.Data[i])))
 -+	fds := make([]int, len(m.Data)>>2)
 -+	for i, j := 0, 0; i < len(m.Data); i += 4 {
 -+		fds[j] = int(*(*int32)(unsafe.Pointer(&m.Data[i])))
  		j++
  	}
  	return fds, nil

コアとなるコードの解説

src/pkg/syscall/sockcmsg_linux.go

  • UnixCredentials 関数:
    • 変更前: bufcmsgという変数名を使用していました。
    • 変更後: bhという短い変数名に変更されました。機能的な変更はありません。bufはバイトスライス、cmsgCmsghdrポインタを指すため、それぞれbhに短縮されています。
  • ParseUnixCredentials 関数:
    • 変更前: 引数msgを使用していました。
    • 変更後: 引数mという短い変数名に変更されました。関数内部でのmsg.Header.Levelmsg.Dataへのアクセスもm.Header.Levelm.Dataに変更されています。機能的な変更はありません。

src/pkg/syscall/sockcmsg_unix.go

  • import "unsafe" の削除:
    • ファイル冒頭のimport ("unsafe")が削除されました。これは、Goのコンパイラがコード内でunsafeパッケージの機能(例: unsafe.Pointer)が使用されていることを検出すると、自動的にインポートするため、明示的なインポート文が不要になったためです。
  • cmsgData 関数:
    • 変更前: 引数cmsgを使用していました。
    • 変更後: 引数hという短い変数名に変更されました。機能的な変更はありません。
  • ParseSocketControlMessage 関数:
    • 変更前: 引数buf、内部変数h, dbuf, e, cmsgsを使用していました。SocketControlMessageの初期化は複数行に分かれていました。
    • 変更後: 引数b、内部変数h, dbuf, err, msgsという短い変数名に変更されました。特にエラー変数eがGoの慣習であるerrに変更されています。
    • 最も顕著な変更は、SocketControlMessage構造体の初期化が、m := SocketControlMessage{Header: *h, Data: ...}という単一行の構造体リテラルに簡潔化された点です。これにより、コードの可読性が向上し、意図がより明確になります。
  • socketControlMessageHeaderAndData 関数:
    • 変更前: 引数bufを使用していました。
    • 変更後: 引数bという短い変数名に変更されました。機能的な変更はありません。
  • UnixRights 関数:
    • 変更前: bufcmsgという変数名を使用していました。
    • 変更後: bhという短い変数名に変更されました。機能的な変更はありません。
  • ParseUnixRights 関数:
    • 変更前: 引数msgを使用していました。
    • 変更後: 引数mという短い変数名に変更されました。機能的な変更はありません。

これらの変更はすべて、コードの機能に影響を与えることなく、Go言語のコーディングスタイルとイディオムに沿ってコードをより簡潔で読みやすいものにするためのものです。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Linux man pages (sendmsg, cmsg)
  • Go言語のコーディングスタイルに関する一般的な情報源
  • Gerrit Change-ID: https://golang.org/cl/7016044 (これはGoプロジェクトのコードレビューシステムへのリンクであり、コミットの詳細な議論や変更の経緯を確認できます。)