# 機能設計書 82-asyncdispatch

## 概要

本ドキュメントは、Nim標準ライブラリのasyncdispatchモジュールに関する機能設計書である。非同期I/O処理のためのイベントディスパッチャとFuture型を提供し、async/awaitパターンによる非同期プログラミングを実現する。

### 本機能の処理概要

asyncdispatchモジュールは、Nimにおける非同期I/Oの中核を担うモジュールである。イベントループ（ディスパッチャ）を実装し、ソケット通信、ファイルI/O、タイマー処理などを非ブロッキングで実行するための基盤を提供する。

**業務上の目的・背景**：現代のネットワークアプリケーションでは、多数の同時接続を効率的に処理する必要がある。従来の同期I/Oモデルでは、各接続に対してスレッドを割り当てる必要があり、スケーラビリティに問題がある。asyncdispatchは、単一スレッドで多数の非同期操作を効率的にマルチプレクスすることで、C10K問題に対応可能な高性能ネットワークアプリケーションの構築を可能にする。

**機能の利用シーン**：HTTPサーバー・クライアント、WebSocketサーバー、データベースコネクションプール、マイクロサービス間通信、リアルタイムチャットアプリケーションなど、非同期I/Oが必要なあらゆる場面で利用される。

**主要な処理内容**：
1. イベントループ（PDispatcher）の管理 - ソケット、タイマー、コールバックの登録と処理
2. Future型による非同期操作結果の管理
3. async/awaitマクロによる同期的スタイルでの非同期コード記述
4. プラットフォーム固有の最適化（Linux: epoll, Windows: IOCP, BSD: kqueue）

**関連システム・外部連携**：asyncnet（非同期ソケット）、asynchttpserver（非同期HTTPサーバー）、asyncfile（非同期ファイルI/O）、selectors（I/Oマルチプレクサ）と連携する。

**権限による制御**：本モジュールは低レベルのシステムリソースにアクセスするため、ファイルディスクリプタの制限やソケットの権限に従う。

## 関連画面

該当なし（ライブラリモジュールのため画面との直接的な関連はない）

## 機能種別

非同期I/O処理 / イベントディスパッチャ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| timeout | int | No | poll/drainのタイムアウト（ミリ秒）、デフォルト500ms | -1以上 |
| socket | AsyncFD | Yes | 非同期ソケットファイルディスクリプタ | 登録済みであること |
| size | int | Yes | recv/sendのデータサイズ | 正の整数 |
| flags | set[SocketFlag] | No | ソケットフラグ | SafeDisconn等 |
| address | string | Yes | 接続先アドレス | 有効なホスト名/IP |
| port | Port | Yes | 接続先ポート | 1-65535 |

### 入力データソース

OSのI/Oマルチプレクサ（epoll/IOCP/kqueue/poll）からのイベント通知

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Future[T] | object | 非同期操作の結果を保持するオブジェクト |
| AsyncFD | distinct int/cint | 非同期ファイルディスクリプタ |
| PDispatcher | ref object | イベントディスパッチャオブジェクト |

### 出力先

非同期コールバック / Future完了通知

## 処理フロー

### 処理シーケンス

```
1. アプリケーション起動
   └─ getGlobalDispatcher()で暗黙的にディスパッチャ初期化

2. 非同期操作の登録
   └─ register(fd)でファイルディスクリプタを登録
   └─ addRead/addWriteでコールバックを登録

3. イベントループの実行
   └─ poll()またはrunForever()を呼び出し
   └─ runOnce()内部で以下を実行:
      ├─ processTimers() - タイマー処理
      ├─ selector.selectInto() - I/Oイベント待機
      ├─ processBasicCallbacks() - 読み書きコールバック処理
      └─ processPendingCallbacks() - 遅延コールバック処理

4. 非同期操作の完了
   └─ Future.complete()またはFuture.fail()でFutureを完了
   └─ 登録されたコールバックが呼び出される

5. waitFor()による同期的待機
   └─ Futureが完了するまでpoll()を繰り返し呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ディスパッチャ初期化]
    B --> C[AsyncFD登録]
    C --> D[非同期操作開始]
    D --> E[Future返却]
    E --> F{poll/waitFor}

    F --> G[runOnce]
    G --> H[タイマー処理]
    H --> I[I/Oイベント取得]
    I --> J{イベントあり?}

    J -->|Yes| K[コールバック実行]
    K --> L{Future完了?}
    L -->|No| F
    L -->|Yes| M[結果取得]

    J -->|No| N[タイムアウト処理]
    N --> F

    M --> O[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-82-01 | スレッドローカルディスパッチャ | 各スレッドは独自のディスパッチャを持つ | マルチスレッド環境 |
| BR-82-02 | ファイルディスクリプタ登録必須 | 非同期操作前にregister()が必要 | 全AsyncFD操作 |
| BR-82-03 | asyncプロシージャ制約 | varパラメータ使用不可、Future[T]返却必須 | asyncプラグマ使用時 |
| BR-82-04 | Futureのdiscard禁止 | asyncCheckまたはawaitで処理必須 | Future取得時 |

### 計算ロジック

**タイムアウト調整ロジック**（adjustTimeout関数）:
- コールバックキューが空でない場合: タイムアウト = 0（即時リターン）
- 次のタイマーがある場合: min(pollTimeout, nextTimer)
- それ以外: 指定されたpollTimeout

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ValueError | ディスパッチャ空エラー | poll()時に登録済みハンドルがない | 最低1つの非同期操作を登録 |
| ValueError | 未登録FDエラー | 未登録のAsyncFDに対する操作 | register()で事前登録 |
| OSError | システムコールエラー | I/O操作失敗 | エラーコードに応じた対処 |
| FutureError | 二重完了エラー | 同一Futureを複数回complete | デバッグモードで検出 |

### リトライ仕様

- EINTR/EAGAIN/EWOULDBLOCKエラー時は自動的にリトライ
- SafeDisconnフラグ有効時、切断エラーは空文字列として返却

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

該当なし

## パフォーマンス要件

- Linux/BSD: O(1)のイベント通知（epoll/kqueue使用）
- Windows: IOCPによる高効率な非同期I/O
- メモリ: Future1つあたり約80-120バイト
- タイマー: HeapQueueによるO(log n)の挿入・取り出し

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

- inheritable=false（デフォルト）で子プロセスへのFD継承を防止
- バッファオーバーフロー対策としてサイズ検証を実施
- GC_ref/GC_unrefによるメモリ管理でUAFを防止

## 備考

- -d:futureLoggingでペンディングFutureのデバッグが可能
- -d:asyncBackend=chronosでChronosライブラリへの切り替えが可能
- Genodeプラットフォーム向けの特殊対応あり

---

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

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

### 推奨読解順序

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

まず、非同期処理の基盤となるデータ構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | asyncfutures.nim | `lib/pure/asyncfutures.nim` | FutureBase/Future[T]型の定義（26-44行目） |
| 1-2 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | PDispatcherBase型（244-248行目） |
| 1-3 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | Windows: PDispatcher, AsyncFD, CompletionData（306-341行目） |
| 1-4 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | Unix: PDispatcher, AsyncFD, AsyncData（1183-1196行目） |

**読解のコツ**: Nimの`when defined(windows)`による条件コンパイルを理解すること。Windows版はIOCP、Unix版はselectorsモジュールを使用する。

#### Step 2: ディスパッチャの初期化フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | newDispatcher()関数 Windows版（346-352行目） |
| 2-2 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | newDispatcher()関数 Unix版（1207-1215行目） |
| 2-3 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | getGlobalDispatcher()（362-365行目、1234-1239行目） |

**主要処理フロー**:
- **346-352行目**: Windows版ではIOCPハンドルを作成
- **1207-1215行目**: Unix版ではSelectorオブジェクトを作成
- **362-365行目**: スレッドローカルのgDispを初期化

#### Step 3: イベントループ（runOnce）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | Windows版runOnce（395-456行目） |
| 3-2 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | Unix版runOnce（1397-1453行目） |
| 3-3 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | processTimers（249-264行目） |
| 3-4 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | processPendingCallbacks（266-270行目） |

**主要処理フロー**:
- **395-456行目**: Windows版はgetQueuedCompletionStatusでIOCP待機
- **1397-1453行目**: Unix版はselectIntoでイベント待機
- **249-264行目**: HeapQueueからタイマーをポップして処理

#### Step 4: 非同期ソケット操作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | register関数（372-379行目、1244-1247行目） |
| 4-2 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | recv関数 Windows版（494-565行目） |
| 4-3 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | recv関数 Unix版（1455-1484行目） |
| 4-4 | asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | send関数（633-676行目、1511-1543行目） |

**主要処理フロー**:
- **372-379行目**: createIoCompletionPortでIOCPに登録
- **494-565行目**: WSARecvで非同期受信、CompletionDataにコールバック設定
- **1455-1484行目**: addReadでコールバックを登録し、recv時にFuture完了

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

```
アプリケーションコード
    │
    ├─ waitFor(fut) / runForever()
    │      └─ poll()
    │            └─ runOnce(timeout)
    │                  ├─ processTimers()
    │                  ├─ [Windows] getQueuedCompletionStatus()
    │                  │      └─ CompletionData.cb()
    │                  │            └─ Future.complete()
    │                  ├─ [Unix] selector.selectInto()
    │                  │      ├─ processBasicCallbacks()
    │                  │      │      └─ Callback(fd)
    │                  │      │            └─ Future.complete()
    │                  │      └─ processCustomCallbacks()
    │                  └─ processPendingCallbacks()
    │
    ├─ recv(socket, size)
    │      ├─ verifyPresence(socket)
    │      ├─ newFuture[string]()
    │      ├─ [Windows] WSARecv()
    │      └─ [Unix] addRead() + nativesockets.recv()
    │
    ├─ send(socket, data)
    │      └─ 同様の構造
    │
    └─ sleepAsync(ms)
           ├─ newFuture[void]()
           └─ timers.push()
```

### データフロー図

```
[アプリケーション]                    [ディスパッチャ]                    [OS]

非同期操作開始
    │
    ├─ newFuture[T]() ──────────────▶ Future生成
    │
    ├─ I/O要求登録 ──────────────────▶ selector.register()
    │                                       │
    │                                       ▼
    │                                 OSに非同期I/O要求 ──────────▶ I/O実行
    │
    └─ Future[T]返却 ◀────────────────────────────────────────────────────
          │
          │
          ▼
    waitFor(future)
          │
          ├─ poll() ────────────────▶ runOnce()
          │                                │
          │                                ├─ selectInto()/IOCP ◀──── イベント通知
          │                                │
          │                                ├─ コールバック実行
          │                                │       │
          │                                │       └─ Future.complete(result)
          │                                │
          │                          ◀─────┘
          │
          └─ Future.read() ──────────▶ 結果取得
                    │
                    ▼
              処理結果
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| asyncdispatch.nim | `lib/pure/asyncdispatch.nim` | メインソース | イベントディスパッチャ実装 |
| asyncfutures.nim | `lib/pure/asyncfutures.nim` | コア | Future型の実装 |
| asyncmacro.nim | `lib/pure/asyncmacro.nim` | マクロ | async/awaitマクロ |
| asyncstreams.nim | `lib/pure/asyncstreams.nim` | 補助 | FutureStream実装 |
| selectors.nim | `lib/pure/selectors.nim` | 依存 | I/Oマルチプレクサ抽象化 |
| nativesockets.nim | `lib/pure/nativesockets.nim` | 依存 | 低レベルソケットAPI |
| winlean.nim | `lib/windows/winlean.nim` | 依存 | Windows API定義 |
| posix.nim | `lib/posix/posix.nim` | 依存 | POSIX API定義 |
