# 機能設計書 124-ワークキュー投入

## 概要

本ドキュメントは、libuvが提供するスレッドプールへのワーク投入機能 `uv_queue_work()` の設計仕様を記述する。ユーザー定義の処理をスレッドプール上で非同期に実行するための機能である。

### 本機能の処理概要

**業務上の目的・背景**：イベント駆動型プログラミングモデルにおいて、CPU集約的な処理やブロッキングI/O処理をメインのイベントループ上で実行するとレスポンス性が低下する。本機能は、そのような処理をスレッドプール上のワーカースレッドに委譲し、完了後にイベントループ上のコールバックで結果を受け取ることを可能にする。libuvのファイルシステム操作やDNS解決の内部でも、この仕組みが活用されている。

**機能の利用シーン**：暗号計算、画像処理、データ圧縮などのCPU集約処理、またはサードパーティのブロッキングAPIの非同期化に使用される。Node.jsのWorker Poolの基盤でもある。

**主要な処理内容**：
1. 入力パラメータ（work_cb）のバリデーション
2. uv_work_tリクエスト構造体の初期化とイベントループへの登録
3. 内部ワーク構造体にwork/doneコールバックを設定
4. uv__work_submit()でスレッドプールにUV__WORK_CPU種別としてワークを投入
5. ワーカースレッド上でユーザーのwork_cbを実行
6. 完了後、イベントループ上でafter_work_cbを呼び出し

**関連システム・外部連携**：libuvのスレッドプールシステム（init_threads/worker/post等）と連携。スレッドプールサイズはUV_THREADPOOL_SIZE環境変数で制御可能（デフォルト4、最大1024）。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | スレッドプール | 主機能 | uv_queue_work()によるスレッドプール非同期実行のAPI定義 |
| 36 | スレッド | 主機能 | uv_queue_work()によるスレッドプール活用のサンプル解説 |

## 機能種別

データ連携（非同期処理委譲）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | - |
| req | uv_work_t* | Yes | ワークリクエスト構造体 | - |
| work_cb | uv_work_cb | Yes | ワーカースレッドで実行されるコールバック | NULL不可（UV_EINVAL） |
| after_work_cb | uv_after_work_cb | No | 完了後にイベントループで実行されるコールバック。NULLの場合は完了通知なし | - |

### 入力データソース

ユーザーからの関数呼び出しパラメータ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 0:成功、UV_EINVAL:work_cbがNULL |

### 出力先

after_work_cbコールバック関数への引数として処理結果（statusコード）が返却される。

## 処理フロー

### 処理シーケンス

```
1. work_cbバリデーション
   └─ work_cb == NULLの場合はUV_EINVAL返却
2. リクエスト初期化
   └─ uv__req_init(loop, req, UV_WORK)でリクエスト型を設定
   └─ req->loop, work_cb, after_work_cbを設定
3. ワーク投入
   └─ uv__work_submit()にUV__WORK_CPU種別で投入
   └─ 内部work関数: uv__queue_work（work_cbを呼び出すラッパー）
   └─ 内部done関数: uv__queue_done（after_work_cbを呼び出すラッパー）
4. スレッドプール初期化（初回のみ）
   └─ uv_once()によりinit_threads()を一度だけ実行
   └─ UV_THREADPOOL_SIZE環境変数でスレッド数を決定
5. ワーカースレッドでの実行
   └─ worker()がキューからワークを取得しwork関数を実行
   └─ 完了後、ループのwqキューに結果を追加しuv_async_send()で通知
6. イベントループ上での完了処理
   └─ uv__work_done()がwqキューからワークを取得
   └─ キャンセル判定（UV_ECANCELED）
   └─ after_work_cbを呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[uv_queue_work呼び出し] --> B{work_cb != NULL?}
    B -->|No| Z[UV_EINVAL返却]
    B -->|Yes| C[リクエスト初期化]
    C --> D[uv__work_submit UV__WORK_CPU]
    D --> E[スレッドプール初期化 - 初回のみ]
    E --> F[ワーカースレッドがキューからワーク取得]
    F --> G[work_cb実行]
    G --> H[完了をループのwqに通知]
    H --> I[イベントループがuv__work_done実行]
    I --> J{キャンセル?}
    J -->|Yes| K[after_work_cb status=UV_ECANCELED]
    J -->|No| L[after_work_cb status=0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-124-1 | CPU種別 | ワークはUV__WORK_CPUとして投入される（SLOW_IOではない） | 常時 |
| BR-124-2 | スレッドプールサイズ | デフォルト4スレッド、UV_THREADPOOL_SIZE環境変数で1-1024の範囲で設定可能 | 常時 |
| BR-124-3 | スタックサイズ | ワーカースレッドのスタックサイズは8MB | 常時 |
| BR-124-4 | キャンセル可能 | uv_cancel()により未実行のワークをキャンセル可能。実行中のワークはキャンセル不可 | 常時 |
| BR-124-5 | after_work_cb省略可 | after_work_cbがNULLの場合、完了通知は行われないがリクエスト登録解除は実行される | after_work_cb == NULL |

### 計算ロジック

SLOW_IOスロットリング閾値:
```
slow_work_thread_threshold = (nthreads + 1) / 2
```
UV__WORK_CPUのワークにはこの制限は適用されない。

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

### 操作別データベース影響一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | work_cb == NULL | work_cbを指定する |
| UV_ECANCELED | キャンセル | uv_cancel()によりキャンセルされた | after_work_cbのstatusで判定 |
| UV_EBUSY | キャンセル失敗 | uv_cancel()時に既に実行中 | 完了を待つ |

### リトライ仕様

キャンセルされたワークはユーザーが再投入する必要がある。

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

該当なし。

## パフォーマンス要件

- スレッドプールのデフォルトサイズは4スレッド。CPU集約的な処理が多い場合はUV_THREADPOOL_SIZEで調整可能
- SLOW_IOワーク（DNS解決、ファイルシステム操作等）はスレッドの半分以上を占有しないようスロットリングされるが、UV__WORK_CPUにはこの制限はない

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

- work_cb内でのメモリ操作はスレッドセーフである必要がある
- 共有データへのアクセスにはミューテックス等の同期機構を使用すること

## 備考

- fork後のスレッドプールは再初期化される（pthread_atforkにより）
- ワーカースレッド名は"libuv-worker"に設定される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **1195-1198行目**: `uv_queue_work()`の関数シグネチャ |
| 1-2 | uv-common.h | `src/uv-common.h` | `struct uv__work`の定義。loop, wq（キューノード）, work関数ポインタ, done関数ポインタを持つ |

**読解のコツ**: `uv_work_t`は`work_req`メンバとして`struct uv__work`を内部に持つ。`container_of`マクロでuv__workからuv_work_tを逆引きする設計パターンが多用されている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | threadpool.c | `src/threadpool.c` | **379-396行目**: `uv_queue_work()`関数本体。バリデーション、リクエスト初期化、uv__work_submit()呼び出し |

**主要処理フロー**:
1. **383-384行目**: work_cbのNULLチェック
2. **386-389行目**: リクエスト初期化とフィールド設定
3. **390-394行目**: uv__work_submit()呼び出し（UV__WORK_CPU種別）

#### Step 3: スレッドプール投入処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | threadpool.c | `src/threadpool.c` | **276-286行目**: `uv__work_submit()`。uv_once()で初回初期化を保証し、ワークをキューに投入 |
| 3-2 | threadpool.c | `src/threadpool.c` | **143-161行目**: `post()`。UV__WORK_CPUはメインのwqキューに直接追加。SLOW_IOは別キューに追加 |
| 3-3 | threadpool.c | `src/threadpool.c` | **194-252行目**: `init_threads()`。スレッドプールの初期化。UV_THREADPOOL_SIZE環境変数の読み取り、スレッド作成 |

#### Step 4: ワーカースレッドの動作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | threadpool.c | `src/threadpool.c` | **57-140行目**: `worker()`。ワーカースレッドのメインループ。キューからワークを取得し、work関数を実行し、完了をループに通知する |

**主要処理フロー**:
- **62行目**: スレッド名を"libuv-worker"に設定
- **72-79行目**: ワークキューが空の間、条件変数で待機
- **82-86行目**: exit_messageならループを抜けてスレッド終了
- **88-89行目**: キューからワークを取り出し、初期化（uv_cancel()への通知）
- **120-130行目**: ワーク実行後、ループのwqに完了を追加しuv_async_send()

#### Step 5: 完了処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | threadpool.c | `src/threadpool.c` | **319-356行目**: `uv__work_done()`。イベントループ上で実行される。wqキューから完了ワークを取得しdone関数を呼び出す |
| 5-2 | threadpool.c | `src/threadpool.c` | **359-376行目**: `uv__queue_work()`/`uv__queue_done()`。work_cb/after_work_cbを呼び出す内部ラッパー |

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

```
uv_queue_work() [src/threadpool.c:379]
    │
    +-- uv__req_init() リクエスト初期化
    │
    └── uv__work_submit() [src/threadpool.c:276]
            +-- uv_once(&once, init_once)
            │       └── init_threads() [src/threadpool.c:194]
            │               +── UV_THREADPOOL_SIZE環境変数読み取り
            │               +── uv_cond_init() / uv_mutex_init()
            │               └── uv_thread_create_ex() × nthreads
            │
            └── post() [src/threadpool.c:143]
                    └── uv__queue_insert_tail(&wq, q)
                            └── uv_cond_signal() → worker()起動

worker() [src/threadpool.c:57]  ※ワーカースレッド
    │
    +── uv__queue_work() [src/threadpool.c:359]
    │       └── req->work_cb(req) ユーザーコールバック
    │
    └── uv_async_send(&loop->wq_async) → uv__work_done()起動

uv__work_done() [src/threadpool.c:319]  ※イベントループ
    │
    └── uv__queue_done() [src/threadpool.c:366]
            +── uv__req_unregister()
            └── req->after_work_cb(req, err) ユーザーコールバック
```

### データフロー図

```
[入力]                  [スレッドプール]              [イベントループ]

work_cb ─────┐
             ├──▶ uv_queue_work() ──▶ post() ──▶ wqキュー
after_work_cb┘                                      │
                                              worker()がキューから取得
                                                    │
                                              work_cb(req) 実行
                                                    │
                                              loop->wqキューに完了追加
                                                    │
                                              uv_async_send() 通知
                                                    │
                                              uv__work_done()
                                                    │
                                              after_work_cb(req, status)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API定義（uv_queue_work関数宣言、uv_work_t型） |
| threadpool.c | `src/threadpool.c` | ソース | スレッドプール全体の実装（初期化、ワーカー、投入、完了、キャンセル） |
| uv-common.h | `src/uv-common.h` | ヘッダ | 内部構造体（struct uv__work）の定義 |
| uv-common.c | `src/uv-common.c` | ソース | uv_cancel()の実装 |
