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

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

このコミットは、src/pkg/net/fd_linux.go ファイルに影響を与えています。具体的には、エラーメッセージの出力方法が変更されています。

コミット

  • コミットハッシュ: f7b7338ec247ddd8f47f4747e74b882ac562c2d2
  • Author: Russ Cox rsc@golang.org
  • Date: Tue Nov 1 22:18:16 2011 -0400
  • コミットメッセージ:
    net: update for error (linux)
    
    R=adg
    CC=golang-dev
    https://golang.org/cl/5303091
    

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

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

元コミット内容

net: update for error (linux)

このコミットは、Linux環境におけるネットワーク関連のエラー処理の更新を目的としています。

変更の背景

Go言語では、エラー処理は非常に重要な要素です。初期のGo言語では、エラー型がまだ完全に成熟しておらず、os.Errnoのようなシステムコールエラーを表す型が、String()メソッドとError()メソッドの両方を持っていました。

String()メソッドはfmt.Stringerインターフェースの一部であり、型のデフォルトの文字列表現を提供するために使用されます。一方、Error()メソッドは組み込みのerrorインターフェースの一部であり、エラーメッセージを取得するための標準的な方法です。

このコミットが行われた時期には、os.ErrnoString()メソッドが使用されていましたが、エラー処理の文脈ではerrorインターフェースのError()メソッドを使用することがGoのイディオムとして確立されつつありました。この変更は、エラーメッセージの取得において、より適切でイディオム的なError()メソッドを使用するようにコードを修正することで、Goのエラー処理のベストプラクティスに準拠することを目的としています。

前提知識の解説

epoll (LinuxカーネルのI/Oイベント通知メカニズム)

epollはLinuxカーネルが提供する高性能なI/Oイベント通知メカニズムです。多数のファイルディスクリプタ(ソケット、パイプなど)を効率的に監視し、I/Oイベント(読み込み可能、書き込み可能など)が発生した際にアプリケーションに通知します。従来のselectpollに比べて、監視対象のファイルディスクリプタ数が増えてもパフォーマンスが劣化しにくいという特徴があります。

epollの主要なシステムコールは以下の3つです。

  • epoll_create / epoll_create1: epollインスタンスを作成し、そのファイルディスクリプタを返します。
  • epoll_ctl: epollインスタンスにファイルディスクリプタを追加、変更、または削除します。
  • epoll_wait: epollインスタンスに登録されたファイルディスクリプタでイベントが発生するのを待ちます。

syscallパッケージ (Go言語)

Go言語のsyscallパッケージは、オペレーティングシステムが提供する低レベルなシステムコールへの直接的なインターフェースを提供します。これにより、GoプログラムからOSの機能(ファイル操作、ネットワーク通信、プロセス管理など)を直接呼び出すことができます。epollのようなOS固有の機能を利用する際には、このsyscallパッケージが用いられます。

このコミットで登場するsyscall.EpollCtlは、Linuxのepoll_ctlシステムコールに対応するGoの関数です。

os.Errno (Go言語)

os.Errnoは、Go言語のosパッケージで定義されている型で、システムコールが返すエラーコード(errno)を表します。例えば、ファイルが見つからない場合はsyscall.ENOENTのような値がos.Errnoとして返されます。

errorインターフェース (Go言語)

Go言語におけるエラー処理の基本は、組み込みのerrorインターフェースです。このインターフェースは非常にシンプルで、Error() stringという単一のメソッドのみを定義しています。

type error interface {
    Error() string
}

Goの関数がエラーを返す場合、通常はこのerrorインターフェース型を返します。これにより、エラーの具体的な型に依存せず、一貫した方法でエラーメッセージを取得できます。

fmt.Stringerインターフェース (Go言語)

fmt.Stringerインターフェースは、fmtパッケージで定義されており、String() stringという単一のメソッドを定義しています。

type Stringer interface {
    String() string
}

このインターフェースを実装する型は、fmt.Print系の関数(fmt.Println, fmt.Printfなど)で出力される際に、String()メソッドが返す文字列が使用されます。これは、デバッグ出力やログ出力など、型のデフォルトの文字列表現が必要な場合に便利です。

技術的詳細

このコミットの核心は、os.Errno型のString()メソッドの呼び出しをError()メソッドの呼び出しに置き換えることです。

  • os.Errno.String() vs os.Errno.Error(): os.Errno型は、errorインターフェースとfmt.Stringerインターフェースの両方を実装しています。つまり、Error()メソッドとString()メソッドの両方を持っています。

    • Error()メソッドは、errorインターフェースの一部として、エラーメッセージを返すことを目的としています。Goのエラー処理の文脈では、このメソッドを使用するのが標準的かつイディオム的です。
    • String()メソッドは、fmt.Stringerインターフェースの一部として、型の一般的な文字列表現を返すことを目的としています。fmt.Print系の関数で型を直接出力する際に暗黙的に呼び出されます。

    多くの場合、os.ErrnoString()Error()は同じ文字列を返しますが、セマンティックな意図が異なります。エラー処理のロジック内でエラーメッセージを取得する際には、その目的がエラーメッセージの取得であるため、Error()メソッドを使用する方が適切です。この変更は、Goのエラー処理の慣習に沿ったものと言えます。

  • syscall.EpollCtlのエラーハンドリング: 変更箇所は、syscall.EpollCtlの呼び出しでエラーが発生した場合のログ出力部分です。EpollCtlepollインスタンスのファイルディスクリプタの監視リストを操作するシステムコールであり、ネットワーク処理において非常に重要な役割を果たします。このシステムコールが失敗した場合、そのエラー情報を正確にログに出力することは、デバッグや問題診断において不可欠です。

    このコミットは、エラーメッセージの取得方法を改善することで、より堅牢でGoのイディオムに沿ったエラーハンドリングを実現しています。

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

--- a/src/pkg/net/fd_linux.go
+++ b/src/pkg/net/fd_linux.go
@@ -98,12 +98,12 @@ func (p *pollster) StopWaiting(fd int, bits uint) {
 		p.ctlEvent.Fd = int32(fd)
 		p.ctlEvent.Events = events
 		if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); e != 0 {
-			print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
+			print("Epoll modify fd=", fd, ": ", os.Errno(e).Error(), "\n")
 		}
 		p.events[fd] = events
 	} else {
 		if e := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); e != 0 {
-			print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
+			print("Epoll delete fd=", fd, ": ", os.Errno(e).Error(), "\n")
 		}
 		delete(p.events, fd)
 	}

コアとなるコードの解説

変更はsrc/pkg/net/fd_linux.goファイル内のStopWaitingメソッドにあります。このメソッドは、epollインスタンスからファイルディスクリプタの監視を停止または変更する際に呼び出されます。

具体的には、以下の2つの行が変更されています。

  1. syscall.EPOLL_CTL_MOD (変更) 処理のエラーログ:

    -			print("Epoll modify fd=", fd, ": ", os.Errno(e).String(), "\n")
    +			print("Epoll modify fd=", fd, ": ", os.Errno(e).Error(), "\n")
    

    syscall.EpollCtlEPOLL_CTL_MOD(既存のファイルディスクリプタのイベント監視設定を変更)操作でエラーを返した場合のログ出力です。以前はos.Errno(e).String()を使用していましたが、os.Errno(e).Error()に変更されました。

  2. syscall.EPOLL_CTL_DEL (削除) 処理のエラーログ:

    -			print("Epoll delete fd=", fd, ": ", os.Errno(e).String(), "\n")
    +			print("Epoll delete fd=", fd, ": ", os.Errno(e).Error(), "\n")
    

    syscall.EpollCtlEPOLL_CTL_DEL(ファイルディスクリプタをepollインスタンスから削除)操作でエラーを返した場合のログ出力です。こちらも同様にos.Errno(e).String()からos.Errno(e).Error()に変更されました。

この変更により、epoll関連のシステムコールでエラーが発生した場合に、Goのエラー処理の慣習に沿った方法でエラーメッセージが取得され、ログに出力されるようになります。これは、コードの可読性と保守性を向上させ、将来的なエラー処理の改善にも寄与します。

関連リンク

参考にした情報源リンク