# 機能設計書 30-ストリーム読み取り開始・停止

## 概要

本ドキュメントは、libuv の `uv_read_start()` および `uv_read_stop()` 関数によるストリームからの非同期読み取り制御機能の設計を記述する。

### 本機能の処理概要

本機能は、ストリーム（TCP、パイプ、TTY）からの非同期データ読み取りの開始と停止を制御する。`uv_read_start()`でストリームに読み取りコールバックを登録しI/Oポーリングを開始し、`uv_read_stop()`で読み取りを停止しコールバックを解除する。

**業務上の目的・背景**：非同期I/Oプログラミングにおいて、ストリームからのデータ受信は最も基本的な操作である。libuvはイベント駆動型の読み取りモデルを採用しており、データが到着するとコールバックが呼び出される。この仕組みにより、ブロッキングを行わずに効率的なデータ受信が可能となる。フロー制御のために、必要に応じて読み取りを停止・再開できることが重要である。

**機能の利用シーン**：
- TCP接続からのデータ受信（エコーサーバー、HTTPサーバー等）
- パイプからの子プロセス出力の読み取り
- TTYからのユーザー入力の読み取り
- バックプレッシャー制御のための読み取りの一時停止・再開

**主要な処理内容**：
1. `uv_read_start()`: 引数チェック後、プラットフォーム固有の読み取り開始処理を呼び出し
2. `uv__read_start()` (Unix): READING/READ_EOFフラグ設定、コールバック登録、I/Oウォッチャー開始
3. `uv_read_stop()`: READINGフラグ解除、I/Oウォッチャー停止、コールバック解除

**関連システム・外部連携**：I/Oポーリングサブシステム（epoll/kqueue/IOCP）。

**権限による制御**：なし。ストリームが読み取り可能（UV_HANDLE_READABLE）である必要がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | ストリーム | 主画面 | uv_read_start()/uv_read_stop()による非同期読み取り制御のAPI定義 |
| 35 | ネットワーク | 補助画面 | クライアントからのデータ読み取りの使用例 |

## 機能種別

I/O制御処理（ストリームからの非同期読み取りの開始・停止）

## 入力仕様

### 入力パラメータ

#### uv_read_start()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stream | uv_stream_t* | Yes | 読み取り対象のストリーム | NULLでないこと。クローズ中でないこと。読み取り可能であること |
| alloc_cb | uv_alloc_cb | Yes | データ受信用バッファ確保コールバック | NULLでないこと |
| read_cb | uv_read_cb | Yes | データ受信時に呼ばれるコールバック | NULLでないこと |

#### uv_read_stop()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| stream | uv_stream_t* | Yes | 読み取りを停止するストリーム | NULLでないこと |

### 入力データソース

呼び出し元から直接引数として渡される。ストリームはuv_tcp_t、uv_pipe_t、uv_tty_tのいずれかのサブタイプ。

## 出力仕様

### 出力データ

#### uv_read_start()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 0:成功、UV_EINVAL:引数不正、UV_EALREADY:既に読み取り中、UV_ENOTCONN:読み取り不可 |

#### uv_read_stop()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 0:成功（読み取り中でない場合も0を返す） |

### 出力先

戻り値として返却。読み取り開始後はデータ到着時にread_cbコールバックが非同期に呼ばれる。

## 処理フロー

### 処理シーケンス

```
uv_read_start(stream, alloc_cb, read_cb):
1. 引数チェック
   ├─ stream/alloc_cb/read_cb == NULL → UV_EINVAL
   ├─ UV_HANDLE_CLOSING フラグが設定済み → UV_EINVAL
   ├─ UV_HANDLE_READING フラグが設定済み → UV_EALREADY
   └─ UV_HANDLE_READABLE フラグが未設定 → UV_ENOTCONN
2. uv__read_start() 呼び出し（プラットフォーム固有）
   ├─ UV_HANDLE_READING フラグ設定
   ├─ UV_HANDLE_READ_EOF フラグクリア
   ├─ read_cb/alloc_cb をストリームに設定
   ├─ uv__io_start() で I/O ウォッチャー（POLLIN）を開始
   └─ uv__handle_start() でハンドルをアクティブにする

uv_read_stop(stream):
1. UV_HANDLE_READING フラグが未設定の場合は 0 を返して終了
2. UV_HANDLE_READING フラグをクリア
3. uv__io_stop() で I/O ウォッチャー（POLLIN）を停止
4. uv__handle_stop() でハンドルを非アクティブにする
5. read_cb/alloc_cb を NULL にクリア
6. 0 を返却
```

### フローチャート

```mermaid
flowchart TD
    A[uv_read_start] --> B{stream/alloc_cb/read_cb != NULL?}
    B -->|No| C[return UV_EINVAL]
    B -->|Yes| D{CLOSING?}
    D -->|Yes| C
    D -->|No| E{READING?}
    E -->|Yes| F[return UV_EALREADY]
    E -->|No| G{READABLE?}
    G -->|No| H[return UV_ENOTCONN]
    G -->|Yes| I[uv__read_start]
    I --> J[READINGフラグ設定]
    J --> K[コールバック登録]
    K --> L[I/Oウォッチャー開始]
    L --> M[return 0]

    A2[uv_read_stop] --> N{READING?}
    N -->|No| O[return 0]
    N -->|Yes| P[READINGフラグクリア]
    P --> Q[I/Oウォッチャー停止]
    Q --> R[コールバック解除]
    R --> S[return 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-30-01 | NULL引数拒否 | stream, alloc_cb, read_cbのいずれかがNULLの場合UV_EINVALを返す | uv_read_start()呼び出し時 |
| BR-30-02 | クローズ中拒否 | UV_HANDLE_CLOSINGフラグが設定されている場合UV_EINVALを返す | uv_read_start()呼び出し時 |
| BR-30-03 | 二重開始防止 | 既にUV_HANDLE_READINGフラグが設定されている場合UV_EALREADYを返す | uv_read_start()呼び出し時 |
| BR-30-04 | 読み取り可能性チェック | UV_HANDLE_READABLEフラグが未設定の場合UV_ENOTCONNを返す | uv_read_start()呼び出し時 |
| BR-30-05 | 冪等な停止 | 読み取り中でない場合でもuv_read_stop()は0を返す | uv_read_stop()呼び出し時 |
| BR-30-06 | コールバック解除 | uv_read_stop()はread_cbとalloc_cbをNULLに設定する | uv_read_stop()成功時 |

### 計算ロジック

特別な計算ロジックはない。フラグ操作とI/Oウォッチャー制御が主な処理。

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

データベース操作は存在しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | 不正引数 | NULL引数またはクローズ中のストリーム | 引数を確認し有効なストリームを渡す |
| UV_EALREADY | 既に実行中 | ストリームが既に読み取り中 | 一度uv_read_stop()を呼んでから再開する |
| UV_ENOTCONN | 未接続 | ストリームが読み取り可能でない | ストリームの接続状態を確認する |

### リトライ仕様

UV_EALREADYの場合は、`uv_read_stop()`後に再度`uv_read_start()`を呼ぶことで読み取りを再開できる。

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

トランザクションは存在しない。

## パフォーマンス要件

`uv_read_start()`と`uv_read_stop()`自体はO(1)の定数時間。I/Oウォッチャーの登録・解除がepoll_ctl等のシステムコールを伴う場合がある。

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

- alloc_cbで確保するバッファサイズは適切に制御すること（メモリ枯渇攻撃防止）。
- read_cbで受信したデータの検証はアプリケーション側で行うこと。

## 備考

- `uv_read_start()`の共通部分（引数チェック）は`src/uv-common.c`に、プラットフォーム固有の処理は`src/unix/stream.c`（Unix）や`src/win/stream.c`（Windows）に実装されている。
- macOS（Apple）ではselect互換のためのワークアラウンド（`uv__stream_osx_interrupt_select()`）が含まれる。
- `uv_read_stop()`はストリームクローズ時にも内部的に呼ばれる（`src/unix/stream.c` L1541）。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | UV_STREAM_FIELDSマクロ（L520-526）。write_queue_size, alloc_cb, read_cbフィールド |
| 1-2 | uv.h | `include/uv.h` | uv_stream_s構造体（L535-538）。UV_HANDLE_FIELDSとUV_STREAM_FIELDSを含む |
| 1-3 | uv.h | `include/uv.h` | uv_alloc_cbとuv_read_cbのコールバック型定義 |

**読解のコツ**: `uv_stream_t`は`uv_handle_t`のサブクラスであり、TCP, パイプ, TTYの共通基底型。`alloc_cb`と`read_cb`がストリーム自体にフィールドとして保持される。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv.h | `include/uv.h` | uv_read_start()の関数宣言（L545-547）とuv_read_stop()の宣言（L548） |
| 2-2 | uv-common.c | `src/uv-common.c` | uv_read_start()の共通引数チェック部分（L922-938） |

**主要処理フロー**:
1. **925-926行目**: stream/alloc_cb/read_cbのNULLチェック → UV_EINVAL
2. **928-929行目**: UV_HANDLE_CLOSINGフラグチェック → UV_EINVAL
3. **931-932行目**: UV_HANDLE_READINGフラグチェック → UV_EALREADY
4. **934-935行目**: UV_HANDLE_READABLEフラグチェック → UV_ENOTCONN
5. **937行目**: uv__read_start()を呼び出し（プラットフォーム固有実装へ）

#### Step 3: Unix固有実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stream.c | `src/unix/stream.c` | uv__read_start()のUnix実装（L1447-1470）。フラグ設定→コールバック登録→I/Oウォッチャー開始 |
| 3-2 | stream.c | `src/unix/stream.c` | uv_read_stop()の実装（L1473-1485）。フラグクリア→I/Oウォッチャー停止→コールバック解除 |

**主要処理フロー（uv__read_start）**:
- **1455行目**: UV_HANDLE_READINGフラグ設定
- **1456行目**: UV_HANDLE_READ_EOFフラグクリア
- **1462-1463行目**: read_cb/alloc_cbをストリームに設定
- **1465行目**: uv__io_start()でPOLLINイベントの監視を開始
- **1466行目**: uv__handle_start()でハンドルをアクティブに

**主要処理フロー（uv_read_stop）**:
- **1474-1475行目**: READINGフラグ未設定なら0を返す
- **1477行目**: UV_HANDLE_READINGフラグクリア
- **1478行目**: uv__io_stop()でPOLLIN監視を停止
- **1479行目**: uv__handle_stop()でハンドルを非アクティブに
- **1482-1483行目**: read_cb/alloc_cbをNULLにクリア

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

```
uv_read_start(stream, alloc_cb, read_cb)   [src/uv-common.c]
    ├─ 引数チェック（NULL, CLOSING, READING, READABLE）
    └─ uv__read_start(stream, alloc_cb, read_cb)   [src/unix/stream.c]
           ├─ フラグ設定（READING, !READ_EOF）
           ├─ コールバック登録
           ├─ uv__io_start(loop, &stream->io_watcher, POLLIN)
           ├─ uv__handle_start(stream)
           └─ uv__stream_osx_interrupt_select(stream)  [macOSのみ]

uv_read_stop(stream)   [src/unix/stream.c]
    ├─ READINGフラグチェック
    ├─ フラグクリア
    ├─ uv__io_stop(loop, &stream->io_watcher, POLLIN)
    ├─ uv__handle_stop(stream)
    └─ uv__stream_osx_interrupt_select(stream)  [macOSのみ]
```

### データフロー図

```
[入力]                    [処理]                                [出力]

uv_stream_t* ───▶ 引数チェック
alloc_cb      ───▶ フラグ設定                     ───▶ int (戻り値)
read_cb       ───▶ I/Oウォッチャー登録
                   └─ POLLINイベント発生時
                      ├─ alloc_cb呼び出し → バッファ取得
                      ├─ read() システムコール
                      └─ read_cb呼び出し → データ受信通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | uv_read_start()/uv_read_stop()関数宣言（L545-548）、UV_STREAM_FIELDSマクロ |
| uv-common.c | `src/uv-common.c` | ソース | uv_read_start()の共通引数チェック（L922-938） |
| stream.c | `src/unix/stream.c` | ソース | uv__read_start()/uv_read_stop()のUnix実装（L1447-1485） |
| stream.c | `src/win/stream.c` | ソース | Windows版のストリーム読み取り実装 |
| tcp.c | `src/win/tcp.c` | ソース | Windows版TCP固有の読み取り実装 |
| pipe.c | `src/win/pipe.c` | ソース | Windows版パイプ固有の読み取り実装 |
