# 通知設計書 6-タイマー通知

## 概要

本ドキュメントは、libuvにおけるタイマー通知（uv_timer_cb）の設計を記述する。指定時間経過後にコールバックで通知する機構であり、ワンショットおよびリピートモードに対応する。バイナリヒープで効率的にタイマーを管理する。

### 本通知の処理概要

uv_timer_cbは、指定されたミリ秒の経過後にコールバックを実行するタイマー通知メカニズムである。バイナリ最小ヒープ（min-heap）でタイマーを管理し、期限切れのタイマーを効率的にO(log n)で処理する。repeatパラメータにより、ワンショット（1回限り）またはリピート（繰り返し）の動作モードを選択できる。

**業務上の目的・背景**：タイムアウト処理、定期的なポーリング、デバウンス処理、遅延実行等、時間に基づくイベントスケジューリングはほぼ全てのアプリケーションで必要となる。本通知はlibuvのイベントループに統合されたタイマーメカニズムを提供し、I/Oポーリングのタイムアウト計算にも使用される基盤的な機能である。

**通知の送信タイミング**：uv_timer_start()で指定されたtimeout（ミリ秒）が経過した時点で、イベントループのタイマーフェーズ（uv__run_timers）でコールバックが実行される。repeatモードの場合はrepeat間隔で自動的に再スケジュールされる。

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

**通知内容の概要**：コールバックにはuv_timer_tハンドルへのポインタのみが渡される。タイマーの用途に応じた追加データはhandle->dataフィールドを通じて受け渡す。

**期待されるアクション**：受信者はタイマー満了に応じた処理を行う。例えば接続タイムアウトの処理、定期的なハートビート送信、デバウンス後の処理実行等。

## 通知種別

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

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（イベントループのタイマーフェーズで処理） |
| 優先度 | 高（イベントループの各イテレーション冒頭で処理される） |
| リトライ | なし（repeatモードで自動再スケジュール） |

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

バイナリ最小ヒープ（timer_heap）のルートノード（最小timeout）から順に、loop->time以下のtimeoutを持つタイマーを取り出し、コールバックを実行する。同一timeoutの場合はstart_id（開始順序）で優先度が決まる。

## 通知テンプレート

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

| 項目 | 内容 |
|-----|------|
| 関数型 | `typedef void (*uv_timer_cb)(uv_timer_t* handle)` |
| 定義場所 | `include/uv.h` 335行目 |

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

```
handle: uv_timer_t* - タイマーハンドル
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| handle | タイマーハンドル | timer_heapのmin nodeから取得 | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| タイムアウト満了 | handle->timeout <= loop->time | uv_timer_start()で開始済み | uv__run_timers()でチェック |
| リピートタイマー | repeat間隔経過 | handle->repeat > 0 | uv_timer_again()で自動再スケジュール |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| cb == NULL | uv_timer_start()がUV_EINVALを返す（timer.c 73-74行目） |
| ハンドルクローズ中 | uv__is_closing(handle)がtrueの場合、UV_EINVAL返却（timer.c 73行目） |
| timeout未到達 | handle->timeout > loop->timeの場合、ヒープに残留 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[uv_timer_start] --> B[ヒープに挿入]
    B --> C[イベントループのイテレーション]
    C --> D[uv__run_timers]
    D --> E[heap_min取得]
    E --> F{timeout <= loop->time?}
    F -->|No| G[タイマーフェーズ終了]
    F -->|Yes| H[uv_timer_stop - ヒープから除去]
    H --> I[ready_queueに追加]
    I --> J[次のheap_minへ]
    J --> E
    G --> K[ready_queueからコールバック実行]
    K --> L[uv_timer_again - リピート再スケジュール]
    L --> M[timer_cb呼び出し]
    M --> N{ready_queue空?}
    N -->|No| K
    N -->|Yes| O[終了]
```

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

### 内部データ構造

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| loop->timer_heap | タイマー管理用バイナリ最小ヒープ | timeout昇順、同値はstart_id昇順 |
| handle->timeout | タイマー満了時刻（絶対値） | loop->time + timeout で計算 |
| handle->repeat | リピート間隔（ミリ秒） | 0の場合はワンショット |
| handle->start_id | タイマー開始順序ID | loop->timer_counterから採番 |
| handle->timer_cb | ユーザーコールバック | uv_timer_cb型 |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| UV_EINVAL | cb==NULL またはハンドルクローズ中 | エラーコードを返却（timer.c 73-74行目） |
| タイムアウトオーバーフロー | loop->time + timeout がオーバーフロー | UINT64_MAXにクランプ（timer.c 79-80行目） |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし（repeatモードは自動再スケジュール） |
| リトライ間隔 | handle->repeat（ミリ秒） |
| リトライ対象エラー | なし |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし（repeat間隔に依存） |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし。

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

- タイマーの精度はOSのクロック解像度に依存する
- タイムアウト値のオーバーフローはUINT64_MAXへのクランプで対処済み

## 備考

- uv__next_timeout()によりI/Oポーリングのタイムアウトが最も近いタイマーの残り時間に設定される
- uv__run_timers()ではまず全ての期限切れタイマーをready_queueに移動してからコールバックを実行する（timer.c 170-193行目）
- uv_timer_again()はrepeatが設定されている場合のみ再スケジュールを行う（timer.c 112-122行目）
- uv_timer_get_due_in()で残り時間を取得可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | 335行目: uv_timer_cb型定義、227行目: uv_timer_t前方宣言、967-985行目: 公開API宣言 |
| 1-2 | heap-inl.h | `src/heap-inl.h` | バイナリヒープの実装（heap_insert, heap_remove, heap_min, heap_node） |

**読解のコツ**: timer_less_than()がヒープの比較関数であり、timeout→start_idの順で比較する。container_ofマクロでheap_nodeからuv_timer_tを取得する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | timer.c | `src/timer.c` | 57-64行目: uv_timer_init() - タイマー初期化 |
| 2-2 | timer.c | `src/timer.c` | 67-94行目: uv_timer_start() - タイマー開始 |

**主要処理フロー**:
1. **73-74行目**: 引数バリデーション（closing/NULL cb）
2. **76行目**: 既存タイマーの停止
3. **78-80行目**: timeout計算とオーバーフロークランプ
4. **86行目**: start_id採番（timer_counter++）
5. **88-90行目**: ヒープ挿入

#### Step 3: タイマー実行サイクルを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | timer.c | `src/timer.c` | 164-194行目: uv__run_timers() - イベントループのタイマー実行フェーズ |
| 3-2 | timer.c | `src/timer.c` | 112-122行目: uv_timer_again() - リピートタイマーの再スケジュール |
| 3-3 | timer.c | `src/timer.c` | 143-161行目: uv__next_timeout() - I/Oポーリングタイムアウト計算 |

**主要処理フロー**:
- **172-183行目**: 期限切れタイマーをヒープからready_queueに移動
- **185-193行目**: ready_queueからコールバック実行（uv_timer_again→timer_cb）
- **191行目**: uv_timer_again()でrepeat時の再スケジュール
- **192行目**: handle->timer_cb(handle) コールバック実行

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

```
uv_timer_init()
    +-- uv__handle_init()

uv_timer_start(handle, cb, timeout, repeat)
    +-- uv_timer_stop()          ← 既存タイマー停止
    +-- heap_insert()            ← ヒープに挿入
    +-- uv__handle_start()

[イベントループ各イテレーション]
uv__run_timers()
    +-- heap_min()               ← 最小timeout取得
    +-- uv_timer_stop()          ← ヒープから除去
    +-- ready_queueに移動
    +-- uv_timer_again()         ← repeat再スケジュール
    +-- handle->timer_cb(handle) ← コールバック実行

uv__next_timeout()               ← I/Oポーリングタイムアウト計算
    +-- heap_min()
    +-- handle->timeout - loop->time
```

### データフロー図

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

uv_timer_start()     heap_insert(timer_heap)
(timeout, repeat)  ──▶  タイマー登録
                         │
                  [イベントループ イテレーション]
                         │
                         ▼
                  uv__run_timers()
                  heap_min() → timeout <= loop->time ?
                         │
                         ▼
                  ready_queueに移動
                  uv_timer_again() (repeatの場合)
                         │
                         ▼
                  handle->timer_cb(handle) ──▶ ユーザーコールバック
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_timer_cb型定義、uv_timer_t構造体、公開API宣言 |
| timer.c | `src/timer.c` | ソース | タイマー通知の全実装（init, start, stop, again, run_timers, next_timeout） |
| heap-inl.h | `src/heap-inl.h` | ヘッダ | バイナリ最小ヒープの実装 |
| uv-common.h | `src/uv-common.h` | ヘッダ | container_ofマクロ等の共通定義 |
