# 機能設計書 135-条件変数

## 概要

uv_cond_init()/uv_cond_destroy()/uv_cond_signal()/uv_cond_broadcast()/uv_cond_wait()/uv_cond_timedwait()により条件変数（Condition Variable）を制御する機能の設計書である。

### 本機能の処理概要

本機能は、スレッド間で特定の条件が成立するまで待機し、条件成立時に通知を行うための同期プリミティブを提供する。

**業務上の目的・背景**：条件変数はミューテックスと組み合わせて使用される同期プリミティブであり、「ある条件が満たされるまで待機する」というパターンを効率的に実現する。ポーリングやビジーウェイトに比べてCPUリソースの浪費を防止する。libuvはPOSIXのpthread_cond_*とWindowsのCondition Variableの差異を吸収する。特にmacOSでの固有バグ回避やCLOCK_MONOTONICの使用など、プラットフォーム固有の対応を内包する。

**機能の利用シーン**：プロデューサー・コンシューマーパターンにおけるキュー待ちの実装、スレッドプール内のワーカースレッドへのタスク通知、状態変更の待機と通知に利用される。libuv内部でもバリアのカスタム実装やセマフォのカスタム実装で使用されている。

**主要な処理内容**：
1. uv_cond_init()による条件変数の初期化（非macOSではCLOCK_MONOTONIC属性設定）
2. uv_cond_destroy()による条件変数の破棄（macOSではシグナル済み未待機バグの回避処理）
3. uv_cond_signal()による1スレッドへの通知
4. uv_cond_broadcast()による全待機スレッドへの通知
5. uv_cond_wait()によるミューテックス解放を伴うブロッキング待機
6. uv_cond_timedwait()によるタイムアウト付きブロッキング待機

**関連システム・外部連携**：Unix系ではpthread_cond_*関数、WindowsではCondition Variable API（SleepConditionVariableCS等）を使用する。

**権限による制御**：特段の権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | スレッド | 主機能 | uv_cond_init()/destroy()/signal()/broadcast()/wait()のAPI定義 |

## 機能種別

同期プリミティブ操作（条件変数制御）

## 入力仕様

### 入力パラメータ

#### uv_cond_init()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cond | uv_cond_t* | Yes | 条件変数オブジェクト | NULLの場合は未定義動作 |

#### uv_cond_wait()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cond | uv_cond_t* | Yes | 条件変数オブジェクト | なし |
| mutex | uv_mutex_t* | Yes | 関連付けるミューテックス | 呼び出し側がロック保持していること |

#### uv_cond_timedwait()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| cond | uv_cond_t* | Yes | 条件変数オブジェクト | なし |
| mutex | uv_mutex_t* | Yes | 関連付けるミューテックス | 呼び出し側がロック保持していること |
| timeout | uint64_t | Yes | タイムアウト（ナノ秒単位） | なし |

### 入力データソース

呼び出し元アプリケーションからの直接指定。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 (init) | int | 成功時0、失敗時負のエラーコード |
| 戻り値 (timedwait) | int | 成功時0、タイムアウト時UV_ETIMEDOUT |
| 戻り値 (signal/broadcast/wait/destroy) | void | 失敗時abort() |

### 出力先

呼び出し元への戻り値。

## 処理フロー

### 処理シーケンス

```
uv_cond_init():
1. [macOS/MVS] pthread_cond_init(cond, NULL)
2. [その他Unix]
   a. pthread_condattr_init()
   b. pthread_condattr_setclock(CLOCK_MONOTONIC)
   c. pthread_cond_init(cond, &attr)
   d. pthread_condattr_destroy()
3. [Windows] InitializeConditionVariable()

uv_cond_destroy():
1. [macOS] シグナル済み未待機バグの回避処理
   └─ 一時mutexを作成、pthread_cond_timedwait_relative_np(1ns)実行後に破棄
2. pthread_cond_destroy(cond) / Windows: 空関数

uv_cond_timedwait():
1. [macOS] 相対時間でpthread_cond_timedwait_relative_np()
2. [MVS] gettimeofday()で現在時刻取得 + timeout加算 → 絶対時間でpthread_cond_timedwait()
3. [その他Unix] uv__hrtime(UV_CLOCK_PRECISE)で現在時刻取得 + timeout加算 → 絶対時間
4. [Windows] SleepConditionVariableCS(timeout / 1e6ミリ秒変換)
5. タイムアウト時UV_ETIMEDOUT返却
```

### フローチャート

```mermaid
flowchart TD
    A[uv_cond_init] --> B{プラットフォーム}
    B -->|macOS/MVS| C[pthread_cond_init NULL属性]
    B -->|その他Unix| D[CLOCK_MONOTONIC属性設定]
    D --> E[pthread_cond_init with attr]
    B -->|Windows| F[InitializeConditionVariable]
    C --> G[結果返却]
    E --> G
    F --> G

    H[uv_cond_timedwait] --> I{プラットフォーム}
    I -->|macOS| J[相対時間で待機]
    I -->|その他Unix| K[絶対時間で待機]
    I -->|Windows| L[SleepConditionVariableCS]
    J --> M{結果}
    K --> M
    L --> M
    M -->|ETIMEDOUT| N[UV_ETIMEDOUT返却]
    M -->|成功| O[0返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-135-01 | CLOCK_MONOTONIC | macOS/MVS以外のUnixではCLOCK_MONOTONIC属性を設定し、システム時刻変更の影響を受けないようにする | Unix（macOS/MVS除く） |
| BR-135-02 | macOS destroy回避策 | macOSでのシグナル済み未待機条件変数のdestroy時クラッシュバグを1ns timedwaitで回避 | macOS |
| BR-135-03 | macOS wait回避策 | macOS 13.6以下でのEINVAL+EBUSYの組み合わせエラーを無視する | macOS |
| BR-135-04 | タイムアウト単位 | timedwaitのtimeoutはナノ秒単位、WindowsではミリiSeconds（/1e6）に変換 | 常時 |
| BR-135-05 | macOS相対時間 | macOSではpthread_cond_timedwait_relative_npにより相対時間指定 | macOS |

### 計算ロジック

タイムアウト計算（非macOS Unix）: `timeout += uv__hrtime(UV_CLOCK_PRECISE)` で現在の高精度時刻にタイムアウト値を加算し、tv_sec = timeout / 1e9、tv_nsec = timeout % 1e9 に変換。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_ETIMEDOUT | タイムアウト | timedwait()で指定時間内に通知がなかった | 再試行または代替処理 |
| abort() | 致命的エラー | signal/broadcast/wait/destroyでの内部エラー | プログラムを修正 |

### リトライ仕様

timedwait()がUV_ETIMEDOUTを返した場合にリトライ可能。スプリアスウェイクアップ対策として、wait()/timedwait()はwhile条件ループ内で使用すべき。

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

該当なし。

## パフォーマンス要件

条件変数の待機はカーネルのスリープキューに入るため、ビジーウェイトに比べてCPU消費が極めて低い。非macOS Unixでのタイムアウト計算にuv__hrtime()呼び出しが1回含まれる。

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

特になし。

## 備考

- 条件変数は必ずミューテックスと組み合わせて使用する。wait/timedwait呼び出し時にはミューテックスがロックされている必要がある。
- スプリアスウェイクアップ（偽の通知による復帰）が発生しうるため、条件チェックはwhileループで行うべきである。
- macOSでのdestroy時バグ回避の詳細はhttps://codereview.chromium.org/1323293005を参照。
- macOSでのwait時バグ回避の詳細はhttps://github.com/libuv/libuv/issues/4165を参照。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | unix.h | `include/uv/unix.h` | uv_cond_tの型定義（L134: pthread_cond_t） |
| 1-2 | win.h | `include/uv/win.h` | uv_cond_tの構造体定義（L257: CONDITION_VARIABLE cond_var含む） |
| 1-3 | uv.h | `include/uv.h` | API宣言（L1869-1881） |

**読解のコツ**: Windowsのuv_cond_tはCONDITION_VARIABLEのラッパー構造体であり、CRITICAL_SECTIONではなくuv_mutex_t（CRITICAL_SECTION）と組み合わせて使う点に注意。

#### Step 2: init()のプラットフォーム分岐を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | thread.c (Unix) | `src/unix/thread.c` | macOS/MVS版init（L732-734）: デフォルト属性 |
| 2-2 | thread.c (Unix) | `src/unix/thread.c` | 非macOS版init（L738-765）: CLOCK_MONOTONIC属性設定 |
| 2-3 | thread.c (Win) | `src/win/thread.c` | Windows版init（L501-504）: InitializeConditionVariable |

**主要処理フロー**:
- **L738-765 (非macOS init)**: condattr_init → condattr_setclock(CLOCK_MONOTONIC) → cond_init(cond, &attr) → condattr_destroy、エラー時はerror/error2ラベルでクリーンアップ

#### Step 3: destroy()のmacOS回避策を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | thread.c (Unix) | `src/unix/thread.c` | uv_cond_destroy()（L769-801） |

**主要処理フロー**:
- **L770-797 (macOS)**: 一時mutexを生成・ロックし、pthread_cond_timedwait_relative_np(cond, &mutex, {0,1ns})を実行、その後mutex解放・破棄
- **L799-800**: pthread_cond_destroy(cond)失敗でabort()

#### Step 4: wait()とtimedwait()を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | thread.c (Unix) | `src/unix/thread.c` | uv_cond_wait() macOS版（L815-830）: EINVAL+EBUSYバグ回避 |
| 4-2 | thread.c (Unix) | `src/unix/thread.c` | uv_cond_timedwait()（L841-874）: プラットフォーム別タイムアウト計算 |
| 4-3 | thread.c (Win) | `src/win/thread.c` | Windows版wait/timedwait（L523-535） |

**主要処理フロー**:
- **L841-874 (timedwait)**: macOS→相対時間、MVS→gettimeofday基準、その他→uv__hrtime基準で絶対時間を計算、ETIMEDOUT→UV_ETIMEDOUT
- **L529-535 (Win timedwait)**: SleepConditionVariableCS、タイムアウト値をns→msに変換(/1e6)

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

```
uv_cond_init(cond)
    +-- [macOS/MVS] pthread_cond_init(cond, NULL)
    +-- [その他Unix] pthread_condattr_init()
    |                pthread_condattr_setclock(CLOCK_MONOTONIC)
    |                pthread_cond_init(cond, &attr)
    +-- [Windows] InitializeConditionVariable()

uv_cond_wait(cond, mutex)
    +-- [macOS] pthread_cond_wait() [EINVAL+EBUSYバグ回避]
    +-- [Unix] pthread_cond_wait() → 失敗: abort()
    +-- [Windows] SleepConditionVariableCS(INFINITE)

uv_cond_timedwait(cond, mutex, timeout)
    +-- [macOS] pthread_cond_timedwait_relative_np(相対時間)
    +-- [MVS] gettimeofday() + timeout → pthread_cond_timedwait(絶対時間)
    +-- [Unix] uv__hrtime() + timeout → pthread_cond_timedwait(絶対時間)
    +-- [Windows] SleepConditionVariableCS(timeout/1e6)
```

### データフロー図

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

cond, mutex             --> cond_wait()           --> mutex再取得後に復帰
cond, mutex, timeout    --> cond_timedwait()      --> 0 / UV_ETIMEDOUT
cond                    --> cond_signal()          --> 1スレッドに通知
cond                    --> cond_broadcast()       --> 全待機スレッドに通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言（L1869-1881） |
| unix.h | `include/uv/unix.h` | ヘッダ | uv_cond_t型定義（L134） |
| win.h | `include/uv/win.h` | ヘッダ | uv_cond_t型定義（L257） |
| thread.c (Unix) | `src/unix/thread.c` | ソース | Unix版条件変数実装（L730-874） |
| thread.c (Win) | `src/win/thread.c` | ソース | Windows版条件変数実装（L501-535） |
