[インデックス 16862] ファイルの概要
このコミットは、Goランタイムのネットワークポーラーにおけるkqueue
のEV_RECEIPT
フラグのサポートを削除し、BSD系OS(FreeBSD, OpenBSD)でのランタイム統合型ネットワークポーラーのビルドを可能にする変更です。これにより、将来的にこれらのプラットフォームでのネットワークポーラーの統合に向けた準備が進められます。
コミット
commit 8f746af65d563ce442720aeb35a0f80efc62b7d6
Author: Mikio Hara <mikioh.mikioh@gmail.com>
Date: Thu Jul 25 00:24:17 2013 +0900
runtime: drop EV_RECEIPT support from network pollster on kqueue
Currently Darwin and FreeBSD support and NetBSD and OpenBSD do not
support EV_RECEIPT flag. We will drop use of EV_RECEIPT for now.
Also enables to build runtime-integrated network pollster on
freebsd/amd64,386 and openbsd/amd64,386. It just does build but never
runs pollster stuff.
This is in preparation for runtime-integrated network pollster for BSD
variants.
Update #5199
R=dvyukov, minux.ma
CC=golang-dev
https://golang.org/cl/11759044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/8f746af65d563ce442720aeb35a0f80efc62b7d6
元コミット内容
runtime: drop EV_RECEIPT support from network pollster on kqueue
Currently Darwin and FreeBSD support and NetBSD and OpenBSD do not
support EV_RECEIPT flag. We will drop use of EV_RECEIPT for now.
Also enables to build runtime-integrated network pollster on
freebsd/amd64,386 and openbsd/amd64,386. It just does build but never
runs pollster stuff.
This is in preparation for runtime-integrated network pollster for BSD
variants.
Update #5199
R=dvyukov, minux.ma
CC=golang-dev
https://golang.org/cl/11759044
変更の背景
この変更の主な背景は、Goランタイムのネットワークポーラーが、異なるBSD系OS間でのEV_RECEIPT
フラグのサポート状況の不一致に対応するためです。具体的には、Darwin(macOS)とFreeBSDはEV_RECEIPT
をサポートしている一方で、NetBSDとOpenBSDはサポートしていませんでした。この不一致が原因で、クロスプラットフォームでの一貫した動作を保証することが困難でした。
また、このコミットは、将来的にGoランタイムに統合されたネットワークポーラーをBSD系OS(特にFreeBSDとOpenBSDのamd64および386アーキテクチャ)で完全に機能させるための準備段階でもあります。これまでは、これらのプラットフォームではネットワークポーラーがビルドされても実行されない状態でしたが、この変更によりビルドが可能になり、将来的な統合への道が開かれました。
Goのネットワークポーラーは、非同期I/O操作を効率的に処理するために不可欠なコンポーネントであり、異なるOSのI/O多重化メカニズム(Linuxのepoll、macOS/BSDのkqueueなど)を抽象化しています。この変更は、Goのネットワークスタックの移植性と堅牢性を向上させることを目的としています。
前提知識の解説
1. Goランタイムとネットワークポーラー
Go言語は、独自のランタイム(実行環境)を持っています。このランタイムは、ガベージコレクション、スケジューラ(ゴルーチンの管理)、そしてネットワークI/Oなど、プログラムの実行に必要な多くの低レベルな機能を提供します。
ネットワークポーラー(Network Pollster)は、Goランタイムの重要なコンポーネントの一つで、ネットワーク接続からのイベント(データの読み込み準備完了、書き込み準備完了など)を効率的に監視し、対応するゴルーチンをスケジューラに通知する役割を担っています。これにより、Goの非同期ネットワークI/Oが実現され、多数の同時接続を効率的に処理できるようになります。
OSごとに異なるI/O多重化メカニズムが存在するため、Goランタイムはこれらの違いを吸収し、統一されたインターフェースを提供しています。
2. kqueue
kqueue
は、FreeBSD、NetBSD、OpenBSD、macOS(Darwin)などのBSD系OSで利用される、高性能なイベント通知インターフェースです。これは、Linuxのepoll
やWindowsのI/O Completion Ports (IOCP) に相当するもので、ファイルディスクリプタ(ソケット、ファイル、パイプなど)の状態変化を効率的に監視するために使用されます。
kqueue
は、kevent
システムコールを通じてイベントを登録し、発生したイベントを取得します。イベントの種類には、読み込み可能(EVFILT_READ
)、書き込み可能(EVFILT_WRITE
)、ファイル変更(EVFILT_VNODE
)などがあります。
3. EV_RECEIPTフラグ
EV_RECEIPT
は、kqueue
のkevent
システムコールでイベントを登録する際に使用できるフラグの一つです。このフラグは、イベントの登録(EV_ADD
)が成功したかどうか、またはエラーが発生したかどうかを即座に確認するために使用されます。
通常、kevent
でイベントを登録する際、登録操作自体は成功しても、そのイベントが実際に有効になるまでに時間がかかる場合があります。EV_RECEIPT
を使用すると、kevent
呼び出しが完了した時点で、登録されたイベントの状態(成功、エラーコードなど)を即座に結果として受け取ることができます。これにより、イベント登録の成功を同期的に確認し、エラーハンドリングを簡素化できる可能性があります。
しかし、このフラグは全てのBSD系OSでサポートされているわけではありません。コミットメッセージにあるように、DarwinとFreeBSDはサポートしていますが、NetBSDとOpenBSDはサポートしていませんでした。この互換性の問題が、今回の変更の直接的な原因となっています。
4. ビルドタグ(+build
)
Goのソースコードでは、ファイルの先頭に+build
ディレクティブを記述することで、特定のOSやアーキテクチャ、またはその他の条件に基づいてファイルを条件付きでコンパイルするかどうかを制御できます。これは、クロスプラットフォーム開発において、OS固有のコードを分離するために非常に便利です。
例:
// +build linux
:Linuxでのみコンパイルされる// +build darwin freebsd
:macOSまたはFreeBSDでコンパイルされる// +build freebsd,amd64
:FreeBSDのamd64アーキテクチャでのみコンパイルされる
このコミットでは、+build
タグが変更され、特定のBSD系OSおよびアーキテクチャでネットワークポーラー関連のファイルがビルドされるように調整されています。
技術的詳細
このコミットの技術的な核心は、kqueue
インターフェースを使用するGoランタイムのネットワークポーラー実装において、EV_RECEIPT
フラグの使用を停止することです。
src/pkg/runtime/netpoll_kqueue.c
ファイルは、kqueue
ベースのネットワークポーラーの主要な実装を含んでいます。このファイル内のruntime·netpollopen
関数は、新しいファイルディスクリプタ(ソケットなど)をポーラーに登録する際に呼び出されます。
変更前は、この関数内でkevent
システムコールを呼び出す際に、EV_ADD|EV_RECEIPT|EV_CLEAR
というフラグの組み合わせを使用していました。
EV_ADD
: イベントをkqueue
に登録します。EV_RECEIPT
: イベント登録の成功/失敗を即座に結果として返します。EV_CLEAR
: イベントが処理された後に、kqueue
から自動的にクリアされます。
EV_RECEIPT
フラグを使用すると、kevent
呼び出しの戻り値として、登録操作自体の結果(エラーコードなど)を受け取ることが期待されます。変更前のコードでは、この戻り値をチェックし、EV_ERROR
フラグやev[0].data
、ev[1].data
(エラーコードが含まれる可能性がある)を検証するロジックが含まれていました。
しかし、NetBSDやOpenBSDがEV_RECEIPT
をサポートしていないため、このフラグを使用するとこれらのプラットフォームで問題が発生する可能性がありました。そこで、このコミットではEV_RECEIPT
フラグを削除し、EV_ADD|EV_CLEAR
のみを使用するように変更しました。
EV_RECEIPT
の削除に伴い、kevent
呼び出しの後のエラーチェックロジックも削除されました。これは、EV_RECEIPT
がない場合、kevent
がイベント登録の結果を即座に返すことを期待しないためです。代わりに、kevent
はイベントを登録するだけで、その後のイベント発生は通常のポーリングループで検出されることになります。
また、kevent
の呼び出し方も変更されています。
変更前: n = runtime·kevent(kq, ev, 2, ev, 2, nil);
変更後: n = runtime·kevent(kq, ev, 2, nil, 0, nil);
これは、イベントを登録する際に、kevent
の出力バッファ(ev
)と出力イベント数(2
)を渡す必要がなくなったことを意味します。登録操作自体は、入力バッファ(ev
)と入力イベント数(2
)のみで行われます。これは、EV_RECEIPT
が削除されたため、登録操作の結果を即座に受け取る必要がなくなったことと整合しています。
さらに、+build
タグの変更により、src/pkg/runtime/netpoll.goc
とsrc/pkg/runtime/netpoll_kqueue.c
がFreeBSDのamd64/386およびOpenBSDでもビルドされるようになりました。これにより、これらのプラットフォームでもGoランタイムのネットワークポーラーが利用できるようになり、将来的な完全な統合への第一歩となります。同時に、src/pkg/runtime/netpoll_stub.c
のビルドタグからFreeBSDのamd64/386およびOpenBSDが削除され、これらのプラットフォームがスタブではなく実際のkqueue実装を使用するようになったことを示しています。
コアとなるコードの変更箇所
src/pkg/runtime/netpoll.goc
--- a/src/pkg/runtime/netpoll.goc
+++ b/src/pkg/runtime/netpoll.goc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin linux windows
+// +build darwin freebsd,amd64 freebsd,386 linux openbsd windows
package net
+build
タグにfreebsd,amd64
,freebsd,386
,openbsd
が追加され、これらのプラットフォームでもnetpoll
パッケージがビルドされるようになりました。
src/pkg/runtime/netpoll_kqueue.c
--- a/src/pkg/runtime/netpoll_kqueue.c
+++ b/src/pkg/runtime/netpoll_kqueue.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin
+// +build darwin freebsd,amd64 freebsd,386 openbsd
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
@@ -37,23 +37,15 @@ runtime·netpollopen(uintptr fd, PollDesc *pd)
// when fd is closed.
ev[0].ident = (uint32)fd;
ev[0].filter = EVFILT_READ;
- ev[0].flags = EV_ADD|EV_RECEIPT|EV_CLEAR;
+ ev[0].flags = EV_ADD|EV_CLEAR;
ev[0].fflags = 0;
ev[0].data = 0;
ev[0].udata = (byte*)pd;
ev[1] = ev[0];
ev[1].filter = EVFILT_WRITE;
- n = runtime·kevent(kq, ev, 2, ev, 2, nil);
+ n = runtime·kevent(kq, ev, 2, nil, 0, nil);
if(n < 0)
return -n;
- if(n != 2 ||
- (ev[0].flags&EV_ERROR) == 0 || ev[0].ident != (uint32)fd || ev[0].filter != EVFILT_READ ||
- (ev[1].flags&EV_ERROR) == 0 || ev[1].ident != (uint32)fd || ev[1].filter != EVFILT_WRITE)
- return EFAULT; // just to mark out from other errors
- if(ev[0].data != 0)
- return ev[0].data;
- if(ev[1].data != 0)
- return ev[1].data;
return 0;
}
+build
タグにfreebsd,amd64
,freebsd,386
,openbsd
が追加され、これらのプラットフォームでもkqueue
ベースのネットワークポーラー実装がビルドされるようになりました。runtime·netpollopen
関数内で、ev[0].flags
からEV_RECEIPT
フラグが削除されました。runtime·kevent
の呼び出しで、出力イベントバッファと出力イベント数を指定する引数(ev, 2
)がnil, 0
に変更されました。EV_RECEIPT
に関連する、kevent
呼び出し後のエラーチェックロジックが削除されました。
src/pkg/runtime/netpoll_stub.c
--- a/src/pkg/runtime/netpoll_stub.c
+++ b/src/pkg/runtime/netpoll_stub.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build freebsd netbsd openbsd plan9
+// +build freebsd,arm netbsd plan9
#include "runtime.h"
+build
タグからfreebsd
(amd64/386を含む)とopenbsd
が削除され、freebsd,arm
のみが残りました。これは、これらのプラットフォームがスタブではなく、実際のkqueue
実装を使用するようになったことを意味します。
コアとなるコードの解説
このコミットの主要な変更は、src/pkg/runtime/netpoll_kqueue.c
内のruntime·netpollopen
関数に集中しています。
-
EV_RECEIPT
フラグの削除: 変更前:ev[0].flags = EV_ADD|EV_RECEIPT|EV_CLEAR;
変更後:ev[0].flags = EV_ADD|EV_CLEAR;
この変更により、kqueue
にイベントを登録する際に、EV_RECEIPT
フラグが使用されなくなりました。前述の通り、NetBSDやOpenBSDがこのフラグをサポートしていないため、クロスプラットフォーム互換性を確保するために削除されました。これにより、kevent
呼び出しが即座に登録結果を返すことを期待しなくなります。 -
kevent
呼び出しの変更: 変更前:n = runtime·kevent(kq, ev, 2, ev, 2, nil);
変更後:n = runtime·kevent(kq, ev, 2, nil, 0, nil);
kevent
システムコールは、イベントの登録(入力)と発生したイベントの取得(出力)の両方に使用できます。変更前は、入力イベント(ev
,2
)と出力イベント(ev
,2
)の両方を指定していました。これはEV_RECEIPT
フラグを使用している場合に、登録操作の結果を即座に出力バッファで受け取るためのパターンです。EV_RECEIPT
が削除されたため、登録操作の結果を即座に受け取る必要がなくなりました。したがって、出力バッファと出力イベント数をnil, 0
に設定し、登録操作のみを行うように変更されました。これにより、kevent
はイベントを登録するだけで、その後のイベント発生はポーリングループで処理されることになります。 -
エラーチェックロジックの削除:
EV_RECEIPT
フラグの削除に伴い、kevent
呼び出しの直後にあった、EV_ERROR
フラグやev[0].data
,ev[1].data
をチェックするロジックが削除されました。これらのチェックはEV_RECEIPT
が返す情報に依存していたため、フラグがなくなったことで不要になりました。
これらの変更により、Goランタイムのネットワークポーラーは、EV_RECEIPT
フラグのサポート状況に依存することなく、より広範なBSD系OSで動作するようになります。また、+build
タグの調整により、FreeBSD/amd64,386およびOpenBSDでもkqueue
ベースのポーラーがビルドされるようになり、将来的な完全な統合に向けた重要なステップとなります。
関連リンク
- Go Issue #5199: https://github.com/golang/go/issues/5199 (このコミットが更新したIssue)
- Go Code Review: https://golang.org/cl/11759044 (このコミットのコードレビューページ)
参考にした情報源リンク
kqueue
man page (FreeBSD): https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2kevent
man page (FreeBSD): https://www.freebsd.org/cgi/man.cgi?query=kevent&sektion=2- Go build constraints: https://pkg.go.dev/cmd/go#hdr-Build_constraints
- Go runtime network poller (general concept): https://go.dev/blog/go-concurrency-patterns-pipelines (直接的ではないが、Goの並行処理とI/Oの背景理解に役立つ)
- Go source code (for context): https://github.com/golang/go