# 通知設計書 7-ストリームデータ到着通知

## 概要

本ドキュメントは、libuvにおけるストリームデータ到着通知（uv_read_cb）の設計を記述する。TCP接続やパイプ等のストリームからデータが到着した際にコールバックで通知するメカニズムについて定義する。

### 本通知の処理概要

uv_read_cbは、TCP接続、パイプ、TTY等のストリーム型ハンドルに対して、読み取り可能なデータが到着した際にコールバックで通知する仕組みである。uv_alloc_cbでバッファを確保した後、read()/recvmsg()でデータを読み取り、uv_read_cbで受信データを通知する。I/Oポーリング（epoll/kqueue）によるレベルトリガーで読み取り可能を検出する。

**業務上の目的・背景**：ネットワーク通信やプロセス間通信において、ストリーム上のデータ受信は最も基本的な操作である。本通知は、非ブロッキングI/Oとイベントループの統合により、データ到着を効率的に検出し、ユーザーに通知する。バッファの確保をユーザー制御とすることで、メモリ管理の柔軟性を提供する。

**通知の送信タイミング**：uv_read_start()で読み取り監視を開始し、ストリームに読み取り可能なデータが到着した時点でI/Oポーリングがイベントを検出し、uv__read()内でコールバックが実行される。ループスタベーション防止のため、1回のイテレーションで最大32回の読み取りに制限される。

**通知の受信者**：uv_read_start()で設定されたコールバック関数（uv_read_cb）が受信者となる。

**通知内容の概要**：コールバックにはストリームハンドル（uv_stream_t*）、読み取りバイト数またはエラーコード（ssize_t nread）、バッファ（const uv_buf_t* buf）が渡される。nreadが正の場合は読み取りデータのバイト数、0の場合はデータなし（EAGAIN）、UV_EOFの場合はストリーム終端、負の値の場合はエラーコード。

**期待されるアクション**：受信者はnreadの値に応じた処理を行う。正の場合はデータの解析・処理、UV_EOFの場合は接続終了処理、エラーの場合はuv_close()等のエラー処理を行う。また、alloc_cbで確保したバッファの解放はユーザーの責任である。

## 通知種別

コールバック通知（Cコールバック関数呼び出し）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（I/Oポーリング + read()/recvmsg()による読み取り） |
| 優先度 | 中（I/Oポーリングイベントとして処理） |
| リトライ | なし |

### 送信先決定ロジック

ストリームのio_watcherにPOLLINイベントが発生すると、uv__stream_io()→uv__read()が呼び出され、stream->read_cbが実行される。

## 通知テンプレート

### コールバック関数シグネチャ

| 項目 | 内容 |
|-----|------|
| 関数型 | `typedef void (*uv_read_cb)(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf)` |
| 定義場所 | `include/uv.h` 326-328行目 |
| alloc_cb型 | `typedef void (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)` |
| alloc_cb定義 | `include/uv.h` 323-325行目 |

### コールバックパラメータ

```
stream: uv_stream_t* - ストリームハンドル
nread: ssize_t - 読み取りバイト数（正=データ、0=EAGAIN、UV_EOF=終端、負=エラー）
buf: const uv_buf_t* - バッファ（alloc_cbで確保されたもの）
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| stream | ストリームハンドル | io_watcher経由 | Yes |
| nread | 読み取りバイト数/エラーコード | read()/recvmsg()の戻り値 | Yes |
| buf | 受信バッファ | alloc_cb()で確保 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| データ到着 | ストリームにデータ到着（POLLIN） | uv_read_start()で監視中 | nread > 0 でコールバック |
| ストリーム終端 | read()が0を返す | 読み取り監視中 | nread = UV_EOF でコールバック |
| 読み取りエラー | read()が-1を返す（EAGAIN以外） | 読み取り監視中 | nread = UV__ERR(errno) でコールバック |
| バッファ確保失敗 | alloc_cbがNULL/0バッファを返す | 読み取り監視中 | nread = UV_ENOBUFS でコールバック |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| 読み取りループ上限 | 1イテレーションで最大32回（stream.c 1036行目） |
| UV_HANDLE_READING非設定 | stream->flagsにUV_HANDLE_READINGがない場合（stream.c 1044行目） |
| read_cb == NULL | コールバック未設定の場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[データ到着 - POLLIN] --> B[uv__stream_io]
    B --> C[uv__read]
    C --> D[alloc_cb - バッファ確保]
    D --> E{buf.base==NULL?}
    E -->|Yes| F[read_cb UV_ENOBUFS]
    E -->|No| G[read/recvmsg実行]
    G --> H{nread結果}
    H -->|nread > 0| I[read_cb 成功通知]
    H -->|nread == 0| J[uv__stream_eof - UV_EOF]
    H -->|EAGAIN| K[read_cb nread=0]
    H -->|エラー| L[read_cb エラー通知]
    I --> M{count-- > 0?}
    M -->|Yes| C
    M -->|No| N[終了]
    F --> N
    J --> N
    K --> N
    L --> N
```

## データベース参照・更新仕様

### 内部データ構造

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| stream->read_cb | 読み取りコールバック | uv_read_cb型 |
| stream->alloc_cb | バッファ確保コールバック | uv_alloc_cb型 |
| stream->io_watcher | I/Oウォッチャー | POLLINで読み取り可能を監視 |
| stream->flags | ストリーム状態フラグ | UV_HANDLE_READING, UV_HANDLE_READ_EOF等 |
| stream->accepted_fd | 受け入れ済みfd（IPC時） | recvmsgのSCM_RIGHTSで受信 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| UV_ENOBUFS | alloc_cbがNULLバッファを返す | read_cbにUV_ENOBUFSを渡す（stream.c 1052行目） |
| UV_EOF | read()が0を返す | uv__stream_eof()でEOF通知（stream.c 1107-1108行目） |
| EAGAIN/EWOULDBLOCK | データなし | read_cbにnread=0を渡す（stream.c 1089行目） |
| その他のエラー | read()がエラーを返す | read_cbにUV__ERR(errno)を渡す（stream.c 1098行目） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（レベルトリガーにより次のイテレーションで再通知） |
| リトライ間隔 | なし |
| リトライ対象エラー | EINTR時のみread()を再試行 |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1回のイテレーションあたり | 最大32回のread()呼び出し（stream.c 1036行目） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。

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

- IPCモード（named pipe + ipc）ではrecvmsgでファイルディスクリプタの受け渡しが可能（SCM_RIGHTS）
- バッファの確保と解放はユーザー責任であり、メモリリークに注意

## 備考

- IPC通信時はrecvmsg()でSCM_RIGHTSによるファイルディスクリプタ受信をサポート
- macOSではselect()スレッドによるワークアラウンドが存在（uv__stream_select_t）
- suggested_size（alloc_cbの引数）は64 * 1024（64KB）固定（stream.c 1049行目）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | 323-328行目: uv_alloc_cb/uv_read_cb型定義、523-524行目: UV_STREAM_FIELDSマクロ内のalloc_cb/read_cb |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stream.c | `src/unix/stream.c` | 81-116行目: uv__stream_init() - ストリーム初期化 |
| 2-2 | stream.c | `src/unix/stream.c` | uv_read_start() - 読み取り監視開始（546-547行目のAPI宣言参照） |

#### Step 3: データ読み取り処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stream.c | `src/unix/stream.c` | 1190-1199行目: uv__stream_io() - I/Oウォッチャーコールバック |
| 3-2 | stream.c | `src/unix/stream.c` | 1024-1158行目: uv__read() - データ読み取りとコールバック実行 |
| 3-3 | stream.c | `src/unix/stream.c` | 931-938行目: uv__stream_eof() - EOF処理 |

**主要処理フロー**:
- **1036行目**: ループカウンタ初期化（count = 32）
- **1048-1049行目**: alloc_cb呼び出し（suggested_size = 64KB）
- **1060-1063行目**: 通常read()（非IPC）
- **1064-1078行目**: recvmsg()（IPC）
- **1089行目**: EAGAIN時のread_cb(stream, 0, &buf)
- **1098行目**: エラー時のread_cb(stream, UV__ERR(errno), &buf)
- **1107-1108行目**: EOF時のuv__stream_eof()→read_cb(stream, UV_EOF, &buf)
- **1145行目**: 成功時のread_cb(stream, nread, &buf)

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

```
uv_read_start(stream, alloc_cb, read_cb)
    +-- stream->read_cb = read_cb
    +-- stream->alloc_cb = alloc_cb
    +-- uv__io_start(POLLIN)

[I/Oポーリングでデータ到着検出]
uv__stream_io()
    +-- uv__read()
            +-- alloc_cb(handle, 64*1024, &buf)
            +-- read() / recvmsg()
            +-- stream->read_cb(stream, nread, &buf)
            +-- [EOF時] uv__stream_eof()
                    +-- stream->read_cb(stream, UV_EOF, &buf)
```

### データフロー図

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

ネットワークデータ    I/Oポーリング (epoll/kqueue)
(TCP/Pipe等)  ──▶   POLLIN検出
                         │
                         ▼
                  uv__stream_io()
                  uv__read()
                         │
                         ▼
                  alloc_cb() → buf確保
                  read(fd, buf.base, buf.len)
                         │
                         ▼
                  read_cb(stream, nread, &buf) ──▶ ユーザーコールバック
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_read_cb/uv_alloc_cb型定義、UV_STREAM_FIELDS、公開API宣言 |
| stream.c | `src/unix/stream.c` | ソース | ストリームI/Oの全実装（init, read, write, connect, listen, accept） |
| internal.h | `src/unix/internal.h` | ヘッダ | uv__stream_io(), uv__stream_init()等の内部関数宣言 |
