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

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

このコミットは、Go言語のランタイムにおけるネットワークポーリング記述子(PollDesc)のファイルディスクリプタ(fd)の型をint32からuintptrに変更するものです。これは、特にWindows版のネットワークポーリング(netpoll)の実装に向けた準備として行われました。

コミット

GoランタイムのPollDesc.fdの型をint32からuintptrに変更。この変更は、Windows版のnetpoll実装の準備として行われました。

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

https://github.com/golang/go/commit/38abb09a2e4c682d0dcbe2d592c32bf0f9c2d1c5

元コミット内容

commit 38abb09a2e4c682d0dcbe2d592c32bf0f9c2d1c5
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Mon May 20 12:55:50 2013 +1000

    runtime: change PollDesc.fd from int32 to uintptr
    
    This is in preparation for netpoll windows version.
    
    R=golang-dev, bradfitz
    CC=dvyukov, golang-dev, mikioh.mikioh
    https://golang.org/cl/9569043

変更の背景

この変更の主な背景は、GoランタイムのネットワークポーリングメカニズムをWindowsオペレーティングシステムに対応させるための準備です。Unix系システム(LinuxのepollやBSD/macOSのkqueueなど)では、ファイルディスクリプタ(FD)は通常、整数型(intint32)で表現されます。しかし、Windowsでは、ファイルやソケットなどのI/Oオブジェクトは「ハンドル(HANDLE)」と呼ばれるポインタのような型で扱われることが多く、これはUnix系のFDとは概念が異なります。

int32は32ビットの符号付き整数であり、その表現可能な値の範囲は限られています。一方、uintptrはポインタを保持できる十分な大きさの符号なし整数型であり、システムが32ビットか64ビットかによってそのサイズが異なります。Windowsのハンドルは、32ビットシステムでは32ビット、64ビットシステムでは64ビットの値を持ちうるため、int32では表現しきれない可能性があります。

このコミットは、将来的にWindowsのI/O完了ポート(IOCP: I/O Completion Port)などのメカニズムを利用したnetpollの実装を見据え、ファイルディスクリプタを表現する型を、より汎用性が高く、ポインタサイズに依存しないuintptrに変更することで、クロスプラットフォームな互換性を確保しようとしています。

前提知識の解説

ファイルディスクリプタ (File Descriptor, FD)

ファイルディスクリプタは、Unix系オペレーティングシステムにおいて、ファイルやソケット、パイプなどのI/Oリソースを識別するためにカーネルがプロセスに割り当てる非負の整数です。プログラムは、このFDを通じてI/O操作を行います。

int32

int32は、32ビットの符号付き整数型です。Go言語では、C言語との相互運用(cgo)や、特定のビット幅を持つ整数が必要な場合に使用されます。最大値は約20億です。

uintptr

uintptrは、Go言語における符号なし整数型で、ポインタを保持するのに十分な大きさを持つことが保証されています。そのサイズは、実行されているシステムのポインタサイズ(32ビットシステムでは32ビット、64ビットシステムでは64ビット)に依存します。これは、ポインタを整数として扱う必要がある場合や、C言語のポインタ型とGoの整数型の間で変換を行う際に特に有用です。uintptrは、メモリのアドレスや、OSが提供するハンドルなどの抽象的な識別子を表現するのに適しています。

PollDesc

PollDescは、Goランタイムのネットワークポーリングメカニズムで使用される内部構造体です。これは、特定のファイルディスクリプタ(またはWindowsのハンドル)に関連付けられたポーリング状態を管理するために使用されます。例えば、読み込み可能になったか、書き込み可能になったかなどのイベントを監視します。

netpoll

netpollは、Goランタイムが提供する非同期ネットワークI/Oの基盤となるメカニズムです。これは、複数のネットワーク接続からのI/Oイベントを効率的に処理するために、オペレーティングシステムが提供するポーリングAPI(Linuxのepoll、BSD/macOSのkqueue、WindowsのIOCPなど)を利用します。netpollは、Goのgoroutineスケジューラと連携し、I/Oが準備できるまでgoroutineをブロックし、準備ができたら再開することで、多数の同時接続を効率的に扱うことを可能にします。

epollkqueue

  • epoll: Linuxカーネルが提供する高性能なI/Oイベント通知メカニズムです。多数のファイルディスクリプタを効率的に監視し、I/Oイベントが発生したFDのみを通知します。
  • kqueue: FreeBSD、macOS、NetBSD、OpenBSDなどのBSD系OSで利用可能なイベント通知インターフェースです。epollと同様に、多数のファイルディスクリプタやその他のイベントソースからのイベントを効率的に監視します。

WindowsのI/Oモデルとハンドル

Windowsでは、Unix系のファイルディスクリプタとは異なり、「ハンドル(HANDLE)」という概念がI/Oオブジェクトの識別子として使われます。ハンドルは、カーネルオブジェクト(ファイル、ソケット、イベントなど)への参照であり、その実体はポインタのような値です。Windowsの非同期I/Oは、主にI/O完了ポート(IOCP)を介して行われます。IOCPは、複数の非同期I/O操作の完了を効率的に処理するためのメカニズムです。

技術的詳細

このコミットの技術的な核心は、ファイルディスクリプタの型をint32からuintptrに変更することによって、Goランタイムのネットワークポーリング層がより広範なプラットフォーム、特にWindowsに対応できるようになる点にあります。

  1. 型サイズの互換性:

    • Unix系システムでは、ファイルディスクリプタは通常、比較的低い整数値で表現され、int32で十分な場合が多いです。
    • しかし、Windowsのハンドルは、32ビットシステムでは32ビット、64ビットシステムでは64ビットの値を持ちます。int32は32ビットの符号付き整数であるため、64ビットシステムで64ビットのハンドル値を扱う場合にはオーバーフローが発生し、正しくハンドルを表現できなくなります。
    • uintptrは、実行環境のポインタサイズ(32ビットまたは64ビット)に合わせてサイズが変化するため、32ビットシステムでも64ビットシステムでも、ポインタやハンドルを正確に表現できます。これにより、GoランタイムがWindowsのネイティブなハンドルを直接扱うことが可能になります。
  2. ポインタとしての扱い:

    • uintptrは、その名の通り「ポインタを保持できる整数型」であり、C言語のポインタ型とGoの整数型の間で安全に変換を行うための橋渡しとなります。
    • Goランタイムのnetpoll実装は、C言語で書かれた部分(netpoll_epoll.c, netpoll_kqueue.cなど)とGo言語で書かれた部分(fd_poll_runtime.go, netpoll.gocなど)が混在しています。C言語側ではファイルディスクリプタやハンドルをポインタまたはポインタサイズの整数として扱うことが一般的であり、uintptrへの変更は、これらのC言語側の実装との整合性を高めます。
  3. クロスプラットフォーム対応の柔軟性:

    • この変更により、PollDesc.fdは、Unix系のFDもWindowsのハンドルも、抽象化されたuintptrとして扱うことができるようになります。
    • これにより、netpollのインターフェース自体は変更せずに、プラットフォーム固有の実装(netpoll_windows.cのようなファイルが将来追加されることを想定)で、それぞれのOSのI/O識別子を適切に処理できるようになります。

このコミットは、Go言語がより多くのプラットフォームで高性能なネットワークI/Oを提供するための、重要な基盤整備の一環と言えます。

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

このコミットでは、以下の5つのファイルが変更されています。主な変更は、PollDesc構造体のfdフィールドの型、およびnetpollopennetpollcloseといった関連関数の引数や内部での型キャストをint32からuintptrに変更することです。

  • src/pkg/net/fd_poll_runtime.go
  • src/pkg/runtime/netpoll.goc
  • src/pkg/runtime/netpoll_epoll.c
  • src/pkg/runtime/netpoll_kqueue.c
  • src/pkg/runtime/runtime.h

具体的な変更点:

  • src/pkg/net/fd_poll_runtime.go:
    • runtime_pollOpen関数の引数fdの型がintからuintptrに変更。
    • fd.sysfdruntime_pollOpenに渡す際にuintptr(fd.sysfd)と明示的に型キャスト。
  • src/pkg/runtime/netpoll.goc:
    • runtime·netpollopen関数のプロトタイプ宣言で、fdの型がint32からuintptrに変更。
    • PollDesc構造体内のfdフィールドの型がint32からuintptrに変更。
    • runtime_pollOpen関数の引数fdの型がintからuintptrに変更。
  • src/pkg/runtime/netpoll_epoll.c:
    • runtime·netpollopen関数の引数fdの型がint32からuintptrに変更。
    • runtime·epollctl関数にfdを渡す際に(int32)fdと型キャスト。
    • runtime·netpollclose関数の引数fdの型がint32からuintptrに変更。
    • runtime·epollctl関数にfdを渡す際に(int32)fdと型キャスト。
  • src/pkg/runtime/netpoll_kqueue.c:
    • runtime·netpollopen関数の引数fdの型がint32からuintptrに変更。
    • Kevent構造体のidentフィールドにfdを代入する際に(uint32)fdと型キャスト。
    • ev[0].identev[1].identの比較で(uint32)fdと型キャスト。
    • runtime·netpollclose関数の引数fdの型がint32からuintptrに変更。
  • src/pkg/runtime/runtime.h:
    • runtime·netpollopenruntime·netpollclose関数のプロトタイプ宣言で、fdの型がint32からuintptrに変更。

コアとなるコードの解説

これらの変更は、Goランタイムのネットワークポーリングサブシステム全体にわたる型の一貫性を確保し、特にWindowsプラットフォームへの対応を容易にするためのものです。

  • PollDesc構造体のfdフィールド: このフィールドは、ポーリング対象となるファイルディスクリプタ(またはハンドル)を保持します。int32からuintptrへの変更により、32ビットおよび64ビットシステムの両方で、Unix系のFDとWindowsのハンドルの両方を適切に格納できるようになります。
  • runtime_pollOpen関数: Go言語側からランタイムのポーリング機能を開くための関数です。引数の型をuintptrに変更することで、GoのnetFD.sysfd(システム固有のファイルディスクリプタ/ハンドル)を直接、型安全にランタイムに渡せるようになります。
  • runtime·netpollopenおよびruntime·netpollclose関数(C言語側): これらは、epollkqueueといったOSネイティブのポーリングAPIを呼び出すためのC言語関数です。引数の型をuintptrに変更することで、Go側から渡されたuintptr型の値を直接受け取ることができます。
    • C言語側では、epoll_ctlkeventといったシステムコールが期待する型(通常はintuint32)に合わせて、受け取ったuintptr値を明示的に型キャストしています。これは、uintptrがポインタサイズに依存する汎用的な整数型であるのに対し、システムコールは特定のビット幅の整数を要求するためです。このキャストは、uintptrが実際にFDやハンドルとして有効な値を保持していることを前提としています。
  • runtime.h: ランタイムのC言語部分で利用されるヘッダファイルであり、関数のプロトタイプ宣言が含まれています。ここでの型変更は、ランタイム全体のインターフェースの一貫性を保つために必要です。

全体として、この変更は、Goランタイムが異なるOSのI/O識別子を抽象化し、統一されたuintptr型で扱うことで、クロスプラットフォームなnetpoll実装の柔軟性と堅牢性を高めるための基盤を築いています。

関連リンク

  • GitHubコミットページ: https://github.com/golang/go/commit/38abb09a2e4c682d0dcbe2d592c32bf0f9c2d1c5

参考にした情報源リンク

  • Go言語のuintptrに関するドキュメントや解説記事
  • Go言語のnetpollに関する技術ブログやソースコード解説
  • Linuxのepoll、BSDのkqueue、WindowsのI/O完了ポート(IOCP)に関するOSドキュメントや解説
  • Unix系OSのファイルディスクリプタとWindowsのハンドルの違いに関する情報
  • Go言語のcgoに関するドキュメント# [インデックス 16342] ファイルの概要

このコミットは、Go言語のランタイムにおけるネットワークポーリング記述子(PollDesc)のファイルディスクリプタ(fd)の型をint32からuintptrに変更するものです。これは、特にWindows版のネットワークポーリング(netpoll)の実装に向けた準備として行われました。

コミット

GoランタイムのPollDesc.fdの型をint32からuintptrに変更。この変更は、Windows版のnetpoll実装の準備として行われました。

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

https://github.com/golang/go/commit/38abb09a2e4c682d0dcbe2d592c32bf0f9c2d1c5

元コミット内容

commit 38abb09a2e4c682d0dcbe2d592c32bf0f9c2d1c5
Author: Alex Brainman <alex.brainman@gmail.com>
Date:   Mon May 20 12:55:50 2013 +1000

    runtime: change PollDesc.fd from int32 to uintptr
    
    This is in preparation for netpoll windows version.
    
    R=golang-dev, bradfitz
    CC=dvyukov, golang-dev, mikioh.mikioh
    https://golang.org/cl/9569043

変更の背景

この変更の主な背景は、GoランタイムのネットワークポーリングメカニズムをWindowsオペレーティングシステムに対応させるための準備です。Unix系システム(LinuxのepollやBSD/macOSのkqueueなど)では、ファイルディスクリプタ(FD)は通常、整数型(intint32)で表現されます。しかし、Windowsでは、ファイルやソケットなどのI/Oオブジェクトは「ハンドル(HANDLE)」と呼ばれるポインタのような型で扱われることが多く、これはUnix系のFDとは概念が異なります。

int32は32ビットの符号付き整数であり、その表現可能な値の範囲は限られています。一方、uintptrはポインタを保持できる十分な大きさの符号なし整数型であり、システムが32ビットか64ビットかによってそのサイズが異なります。Windowsのハンドルは、32ビットシステムでは32ビット、64ビットシステムでは64ビットの値を持ちうるため、int32では表現しきれない可能性があります。

このコミットは、将来的にWindowsのI/O完了ポート(IOCP: I/O Completion Port)などのメカニズムを利用したnetpollの実装を見据え、ファイルディスクリプタを表現する型を、より汎用性が高く、ポインタサイズに依存しないuintptrに変更することで、クロスプラットフォームな互換性を確保しようとしています。

前提知識の解説

ファイルディスクリプタ (File Descriptor, FD)

ファイルディスクリプタは、Unix系オペレーティングシステムにおいて、ファイルやソケット、パイプなどのI/Oリソースを識別するためにカーネルがプロセスに割り当てる非負の整数です。プログラムは、このFDを通じてI/O操作を行います。

int32

int32は、32ビットの符号付き整数型です。Go言語では、C言語との相互運用(cgo)や、特定のビット幅を持つ整数が必要な場合に使用されます。最大値は約20億です。

uintptr

uintptrは、Go言語における符号なし整数型で、ポインタを保持するのに十分な大きさを持つことが保証されています。そのサイズは、実行されているシステムのポインタサイズ(32ビットシステムでは32ビット、64ビットシステムでは64ビット)に依存します。これは、ポインタを整数として扱う必要がある場合や、C言語のポインタ型とGoの整数型の間で変換を行う際に特に有用です。uintptrは、メモリのアドレスや、OSが提供するハンドルなどの抽象的な識別子を表現するのに適しています。

PollDesc

PollDescは、Goランタイムのネットワークポーリングメカニズムで使用される内部構造体です。これは、特定のファイルディスクリプタ(またはWindowsのハンドル)に関連付けられたポーリング状態を管理するために使用されます。例えば、読み込み可能になったか、書き込み可能になったかなどのイベントを監視します。

netpoll

netpollは、Goランタイムが提供する非同期ネットワークI/Oの基盤となるメカニズムです。これは、複数のネットワーク接続からのI/Oイベントを効率的に処理するために、オペレーティングシステムが提供するポーリングAPI(Linuxのepoll、BSD/macOSのkqueue、WindowsのIOCPなど)を利用します。netpollは、Goのgoroutineスケジューラと連携し、I/Oが準備できるまでgoroutineをブロックし、準備ができたら再開することで、多数の同時接続を効率的に扱うことを可能にします。

epollkqueue

  • epoll: Linuxカーネルが提供する高性能なI/Oイベント通知メカニズムです。多数のファイルディスクリプタを効率的に監視し、I/Oイベントが発生したFDのみを通知します。
  • kqueue: FreeBSD、macOS、NetBSD、OpenBSDなどのBSD系OSで利用可能なイベント通知インターフェースです。epollと同様に、多数のファイルディスクリプタやその他のイベントソースからのイベントを効率的に監視します。

WindowsのI/Oモデルとハンドル

Windowsでは、Unix系のファイルディスクリプタとは異なり、「ハンドル(HANDLE)」という概念がI/Oオブジェクトの識別子として使われます。ハンドルは、カーネルオブジェクト(ファイル、ソケット、イベントなど)への参照であり、その実体はポインタのような値です。Windowsの非同期I/Oは、主にI/O完了ポート(IOCP)を介して行われます。IOCPは、複数の非同期I/O操作の完了を効率的に処理するためのメカニズムです。

技術的詳細

このコミットの技術的な核心は、ファイルディスクリプタの型をint32からuintptrに変更することによって、Goランタイムのネットワークポーリング層がより広範なプラットフォーム、特にWindowsに対応できるようになる点にあります。

  1. 型サイズの互換性:

    • Unix系システムでは、ファイルディスクリプタは通常、比較的低い整数値で表現され、int32で十分な場合が多いです。
    • しかし、Windowsのハンドルは、32ビットシステムでは32ビット、64ビットシステムでは64ビットの値を持ちます。int32は32ビットの符号付き整数であるため、64ビットシステムで64ビットのハンドル値を扱う場合にはオーバーフローが発生し、正しくハンドルを表現できなくなります。
    • uintptrは、実行環境のポインタサイズ(32ビットまたは64ビット)に合わせてサイズが変化するため、32ビットシステムでも64ビットシステムでも、ポインタやハンドルを正確に表現できます。これにより、GoランタイムがWindowsのネイティブなハンドルを直接扱うことが可能になります。
  2. ポインタとしての扱い:

    • uintptrは、その名の通り「ポインタを保持できる整数型」であり、C言語のポインタ型とGoの整数型の間で安全に変換を行うための橋渡しとなります。
    • Goランタイムのnetpoll実装は、C言語で書かれた部分(netpoll_epoll.c, netpoll_kqueue.cなど)とGo言語で書かれた部分(fd_poll_runtime.go, netpoll.gocなど)が混在しています。C言語側ではファイルディスクリプタやハンドルをポインタまたはポインタサイズの整数として扱うことが一般的であり、uintptrへの変更は、これらのC言語側の実装との整合性を高めます。
  3. クロスプラットフォーム対応の柔軟性:

    • この変更により、PollDesc.fdは、Unix系のFDもWindowsのハンドルも、抽象化されたuintptrとして扱うことができるようになります。
    • これにより、netpollのインターフェース自体は変更せずに、プラットフォーム固有の実装(netpoll_windows.cのようなファイルが将来追加されることを想定)で、それぞれのOSのI/O識別子を適切に処理できるようになります。

このコミットは、Go言語がより多くのプラットフォームで高性能なネットワークI/Oを提供するための、重要な基盤整備の一環と言えます。

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

このコミットでは、以下の5つのファイルが変更されています。主な変更は、PollDesc構造体のfdフィールドの型、およびnetpollopennetpollcloseといった関連関数の引数や内部での型キャストをint32からuintptrに変更することです。

  • src/pkg/net/fd_poll_runtime.go
  • src/pkg/runtime/netpoll.goc
  • src/pkg/runtime/netpoll_epoll.c
  • src/pkg/runtime/netpoll_kqueue.c
  • src/pkg/runtime/runtime.h

具体的な変更点:

  • src/pkg/net/fd_poll_runtime.go:
    • runtime_pollOpen関数の引数fdの型がintからuintptrに変更。
    • fd.sysfdruntime_pollOpenに渡す際にuintptr(fd.sysfd)と明示的に型キャスト。
  • src/pkg/runtime/netpoll.goc:
    • runtime·netpollopen関数のプロトタイプ宣言で、fdの型がint32からuintptrに変更。
    • PollDesc構造体内のfdフィールドの型がint32からuintptrに変更。
    • runtime_pollOpen関数の引数fdの型がintからuintptrに変更。
  • src/pkg/runtime/netpoll_epoll.c:
    • runtime·netpollopen関数の引数fdの型がint32からuintptrに変更。
    • runtime·epollctl関数にfdを渡す際に(int32)fdと型キャスト。
    • runtime·netpollclose関数の引数fdの型がint32からuintptrに変更。
    • runtime·epollctl関数にfdを渡す際に(int32)fdと型キャスト。
  • src/pkg/runtime/netpoll_kqueue.c:
    • runtime·netpollopen関数の引数fdの型がint32からuintptrに変更。
    • Kevent構造体のidentフィールドにfdを代入する際に(uint32)fdと型キャスト。
    • ev[0].identev[1].identの比較で(uint32)fdと型キャスト。
    • runtime·netpollclose関数の引数fdの型がint32からuintptrに変更。
  • src/pkg/runtime/runtime.h:
    • runtime·netpollopenruntime·netpollclose関数のプロトタイプ宣言で、fdの型がint32からuintptrに変更。

コアとなるコードの解説

これらの変更は、Goランタイムのネットワークポーリングサブシステム全体にわたる型の一貫性を確保し、特にWindowsプラットフォームへの対応を容易にするためのものです。

  • PollDesc構造体のfdフィールド: このフィールドは、ポーリング対象となるファイルディスクリプタ(またはハンドル)を保持します。int32からuintptrへの変更により、32ビットおよび64ビットシステムの両方で、Unix系のFDとWindowsのハンドルの両方を適切に格納できるようになります。
  • runtime_pollOpen関数: Go言語側からランタイムのポーリング機能を開くための関数です。引数の型をuintptrに変更することで、GoのnetFD.sysfd(システム固有のファイルディスクリプタ/ハンドル)を直接、型安全にランタイムに渡せるようになります。
  • runtime·netpollopenおよびruntime·netpollclose関数(C言語側): これらは、epollkqueueといったOSネイティブのポーリングAPIを呼び出すためのC言語関数です。引数の型をuintptrに変更することで、Go側から渡されたuintptr型の値を直接受け取ることができます。
    • C言語側では、epoll_ctlkeventといったシステムコールが期待する型(通常はintuint32)に合わせて、受け取ったuintptr値を明示的に型キャストしています。これは、uintptrがポインタサイズに依存する汎用的な整数型であるのに対し、システムコールは特定のビット幅の整数を要求するためです。このキャストは、uintptrが実際にFDやハンドルとして有効な値を保持していることを前提としています。
  • runtime.h: ランタイムのC言語部分で利用されるヘッダファイルであり、関数のプロトタイプ宣言が含まれています。ここでの型変更は、ランタイム全体のインターフェースの一貫性を保つために必要です。

全体として、この変更は、Goランタイムが異なるOSのI/O識別子を抽象化し、統一されたuintptr型で扱うことで、クロスプラットフォームなnetpoll実装の柔軟性と堅牢性を高めるための基盤を築いています。

関連リンク

  • GitHubコミットページ: https://github.com/golang/go/commit/38abb09a2e4c682d0dcbe2d592c32bf0f9c2d1c5

参考にした情報源リンク

  • Go言語のuintptrに関するドキュメントや解説記事
  • Go言語のnetpollに関する技術ブログやソースコード解説
  • Linuxのepoll、BSDのkqueue、WindowsのI/O完了ポート(IOCP)に関するOSドキュメントや解説
  • Unix系OSのファイルディスクリプタとWindowsのハンドルの違いに関する情報
  • Go言語のcgoに関するドキュメント