# 機能設計書 87-selectors

## 概要

本ドキュメントは、Nim標準ライブラリのselectorsモジュールに関する機能設計書である。高レベルなI/Oマルチプレクシングを実現し、プラットフォーム固有のシステムコール（epoll, kqueue, poll, select）を抽象化する。

### 本機能の処理概要

selectorsモジュールは、複数のファイルディスクリプタの読み書き可能状態を効率的に監視するためのI/Oマルチプレクサを提供する。Linux向けのepoll、BSD/macOS向けのkqueue、汎用のpoll/selectを統一されたインターフェースで利用可能にする。

**業務上の目的・背景**：高性能なネットワークサーバーやイベント駆動アプリケーションでは、数千〜数万の同時接続を効率的に処理する必要がある。selectorsは、O(1)またはO(log n)の計算量でイベント通知を実現し、C10K問題に対応するための基盤を提供する。

**機能の利用シーン**：asyncdispatchの内部実装、カスタムイベントループの実装、高性能ネットワークサーバー、プロセス間通信など。

**主要な処理内容**：
1. Selector[T]の生成と管理
2. ファイルディスクリプタの登録・更新・解除
3. タイマー、シグナル、プロセス監視の登録
4. イベント待機と結果取得（select/selectInto関数）

**関連システム・外部連携**：asyncdispatch、nativesocketsと連携。

**権限による制御**：ファイルディスクリプタの権限に従う。

## 関連画面

該当なし

## 機能種別

I/Oマルチプレクサ / イベント監視

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fd | int/SocketHandle | Yes | 監視対象のファイルディスクリプタ | 有効なFD |
| events | set[Event] | Yes | 監視するイベント種別 | Read/Write等 |
| data | T | Yes | FDに関連付けるアプリケーションデータ | - |
| timeout | int | Yes | タイムアウト（ミリ秒）、-1で無限待機 | -1以上 |

### 入力データソース

OSカーネルからのイベント通知

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Selector[T] | object | セレクタオブジェクト |
| ReadyKey | object | 準備完了イベント情報 |
| seq[ReadyKey] | sequence | 準備完了イベントのリスト |

### 出力先

アプリケーションへのイベント通知

## 処理フロー

### 処理シーケンス

```
1. Selector生成
   └─ newSelector[T]()
      ├─ [Linux] epoll_create
      ├─ [BSD] kqueue
      ├─ [Windows] select用構造初期化
      └─ [Other] poll用配列初期化

2. ハンドル登録
   └─ registerHandle(fd, events, data)
      ├─ [Linux] epoll_ctl(EPOLL_CTL_ADD)
      ├─ [BSD] kevent(EV_ADD)
      └─ [Other] 配列に追加

3. イベント待機
   └─ select(timeout) / selectInto(timeout, results)
      ├─ [Linux] epoll_wait
      ├─ [BSD] kevent
      ├─ [Windows] select
      └─ [Other] poll

4. 結果処理
   └─ ReadyKeyから情報取得
      ├─ fd: イベントが発生したFD
      ├─ events: 発生したイベントセット
      └─ getData(fd): 関連付けられたデータ
```

### フローチャート

```mermaid
flowchart TD
    A[newSelector] --> B{プラットフォーム}
    B -->|Linux| C[epoll_create]
    B -->|BSD| D[kqueue]
    B -->|Windows| E[select初期化]
    B -->|Other| F[poll初期化]

    G[registerHandle] --> H{プラットフォーム}
    H -->|Linux| I[epoll_ctl ADD]
    H -->|BSD| J[kevent EV_ADD]
    H -->|Other| K[配列追加]

    L[select/selectInto] --> M{プラットフォーム}
    M -->|Linux| N[epoll_wait]
    M -->|BSD| O[kevent]
    M -->|Windows| P[select]
    M -->|Other| Q[poll]
    N --> R[ReadyKey生成]
    O --> R
    P --> R
    Q --> R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-87-01 | プラットフォーム選択 | 最適なバックエンドを自動選択 | コンパイル時 |
| BR-87-02 | スレッドセーフ | -d:threadsafeでスレッドセーフ版を使用 | マルチスレッド時 |
| BR-87-03 | タイムアウト | -1は無限待機、0は即時リターン | select呼び出し時 |
| BR-87-04 | イベント種別 | Read/Write/Timer/Signal/Process/Vnode/User/Error | 登録時 |

### 計算ロジック

**バックエンド選択**（nimIoselectorによる上書き可能）:
- Linux（非Android、非Emscripten）: epoll
- BSD/macOS: kqueue
- Windows: select
- Solaris/その他: poll

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IOSelectorsException | セレクタエラー | システムコール失敗 | OSエラーコード確認 |
| ValueError | 未登録FD | 未登録FDの操作 | registerHandle必須 |

### リトライ仕様

- EINTR時は自動リトライ（selectorsレベル）

## トランザクション仕様

該当なし

## パフォーマンス要件

- epoll/kqueue: O(1)のイベント取得（イベント数に対して）
- poll: O(n)のFDスキャン
- select: FD_SETSIZEの制限あり

## セキュリティ考慮事項

- シグナル監視はプロセス権限に従う
- ファイルディスクリプタのアクセス権はOSに従う

## 備考

- -d:nimIoselector=epoll/kqueue/poll/selectでバックエンド強制
- ioselSupportedPlatform定数で完全サポートプラットフォームを判定可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | selectors.nim | `lib/pure/selectors.nim` | Event列挙型（61-77行目、ドキュメント） |
| 1-2 | selectors.nim | `lib/pure/selectors.nim` | ReadyKey型（79-84行目、ドキュメント） |
| 1-3 | selectors.nim | `lib/pure/selectors.nim` | Selector[T]型（55-56行目、ドキュメント） |
| 1-4 | selectors.nim | `lib/pure/selectors.nim` | SelectorKey[T]型（271-275行目） |

**読解のコツ**:
- Event列挙型はプラットフォーム固有のイベントも含む（Vnode等はBSD専用）
- ReadyKeyはイベント結果を表現
- Selector[T]のTはアプリケーションデータの型

#### Step 2: バックエンド選択ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | selectors.nim | `lib/pure/selectors.nim` | ioselSupportedPlatform（42-47行目） |
| 2-2 | selectors.nim | `lib/pure/selectors.nim` | バックエンド選択（349-381行目） |

**主要処理フロー**:
- **349-381行目**: when文によるプラットフォーム判定とinclude

#### Step 3: 主要API（ドキュメント部分）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | selectors.nim | `lib/pure/selectors.nim` | newSelector（89-90行目） |
| 3-2 | selectors.nim | `lib/pure/selectors.nim` | registerHandle（95-99行目） |
| 3-3 | selectors.nim | `lib/pure/selectors.nim` | select/selectInto（172-190行目） |
| 3-4 | selectors.nim | `lib/pure/selectors.nim` | getData/setData（192-200行目） |
| 3-5 | selectors.nim | `lib/pure/selectors.nim` | withDataテンプレート（206-230行目） |

### プログラム呼び出し階層図

```
アプリケーションコード / asyncdispatch
    │
    ├─ newSelector[T]()
    │      └─ [epoll] epoll_create()
    │      └─ [kqueue] kqueue()
    │      └─ [poll/select] 配列/FD_SET初期化
    │
    ├─ registerHandle(fd, events, data)
    │      └─ [epoll] epoll_ctl(EPOLL_CTL_ADD)
    │      └─ [kqueue] kevent(EV_ADD)
    │      └─ [poll] pollfds配列追加
    │      └─ [select] FD_SET追加
    │
    ├─ selectInto(timeout, results)
    │      └─ [epoll] epoll_wait()
    │      └─ [kqueue] kevent()
    │      └─ [poll] poll()
    │      └─ [select] select()
    │      └─ ReadyKey配列生成
    │
    ├─ getData(fd) / withData
    │      └─ SelectorKey[T].data取得
    │
    └─ close()
           └─ [epoll/kqueue] close(fd)
           └─ [poll/select] 配列クリア
```

### データフロー図

```
[アプリケーション]         [Selector]              [OS Kernel]

registerHandle(fd, events, data)
        │
        ▼
┌─────────────────┐
│ SelectorKey[T]  │
│   fd: 5         │
│   events: {R}   │──────────────▶ epoll_ctl/kevent
│   data: myData  │               ADD fd=5, EPOLLIN
└─────────────────┘

selectInto(timeout)
        │
        ▼
  epoll_wait ◀────────────────── イベント発生
        │                        fd=5 readable
        ▼
┌─────────────────┐
│  ReadyKey       │
│    fd: 5        │
│    events: {R}  │
└─────────────────┘
        │
        ▼
  アプリケーション処理
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| selectors.nim | `lib/pure/selectors.nim` | メインソース | セレクタ抽象化 |
| ioselectors_epoll.nim | `lib/pure/ioselects/ioselectors_epoll.nim` | バックエンド | Linux epoll実装 |
| ioselectors_kqueue.nim | `lib/pure/ioselects/ioselectors_kqueue.nim` | バックエンド | BSD kqueue実装 |
| ioselectors_poll.nim | `lib/pure/ioselects/ioselectors_poll.nim` | バックエンド | poll実装 |
| ioselectors_select.nim | `lib/pure/ioselects/ioselectors_select.nim` | バックエンド | select実装 |
| nativesockets.nim | `lib/pure/nativesockets.nim` | 依存 | ソケット関連定義 |
| oserrors.nim | `lib/std/oserrors.nim` | 依存 | OSエラー処理 |
