# 機能設計書 25-デバッグ用ハンドル表示

## 概要

本ドキュメントは、libuv の `uv_print_all_handles()` および `uv_print_active_handles()` 関数によるデバッグ用ハンドル情報出力機能の設計を記述する。

### 本機能の処理概要

本機能は、イベントループに登録されているハンドルの情報をデバッグ用に出力する2つの関数を提供する。`uv_print_all_handles()`は全ハンドルを、`uv_print_active_handles()`はアクティブなハンドルのみを出力する。各ハンドルについて、参照状態（R/-）、アクティブ状態（A/-）、内部フラグ（I/-）、型名、アドレスを表示する。

**業務上の目的・背景**：libuvアプリケーションのデバッグにおいて、イベントループが終了しない原因の特定や、ハンドルのリーク検出が頻繁に必要になる。これらの関数は、ループに残っているハンドルの一覧を簡便に出力することで、問題の原因究明を支援する。

**機能の利用シーン**：
- イベントループが期待通りに終了しない場合の原因調査
- ハンドルリークの検出
- アプリケーション状態のダンプ出力
- テストやCI環境でのリソース管理の検証

**主要な処理内容**：
1. ループのハンドルキューを走査
2. 各ハンドルのフラグ（REF/ACTIVE/INTERNAL）を取得
3. ハンドルの型名を取得
4. フォーマットされた文字列を指定ストリーム（デフォルトstderr）に出力

**関連システム・外部連携**：FILE*ストリームへの出力（fprintf）。

**権限による制御**：なし。ただし出力先のストリームに書き込み権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 29 | その他ユーティリティ | 主画面 | uv_print_all_handles()/uv_print_active_handles()によるデバッグ出力のAPI定義 |

## 機能種別

デバッグ情報出力処理（ハンドル状態の表示）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | No | 対象のイベントループ。NULLの場合はデフォルトループを使用 | NULL許容 |
| stream | FILE* | No | 出力先ストリーム。NULLの場合はstderrを使用 | NULL許容 |

### 入力データソース

呼び出し元から引数として渡される。ループが持つハンドルキュー（loop->handle_queue）からハンドル情報を取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 出力行 | 文字列 | `[RAI] type     address` 形式。R=参照あり/-, A=アクティブ/-, I=内部/- |

出力例：
```
[RA-] timer    0x7f8e4c004a00
[R--] async    0x7f8e4c004b80
[-A-] tcp      0x7f8e4c004c00
```

### 出力先

指定されたFILE*ストリーム（デフォルトstderr）。

## 処理フロー

### 処理シーケンス

```
1. 引数チェック
   ├─ stream == NULL の場合、stderr を使用
   └─ loop == NULL の場合、uv_default_loop() を使用
2. ハンドルキューの走査
   └─ uv__queue_foreach で loop->handle_queue を走査
3. 各ハンドルの処理
   ├─ uv_print_active_handles() の場合：アクティブでなければスキップ
   ├─ ハンドル型の文字列変換（UV_HANDLE_TYPE_MAPマクロ）
   └─ fprintf で "[RAI] type address" 形式で出力
```

### フローチャート

```mermaid
flowchart TD
    A[uv_print_all_handles / uv_print_active_handles] --> B[uv__print_handles 呼び出し]
    B --> C{stream == NULL?}
    C -->|Yes| D[stream = stderr]
    C -->|No| E[引数のstreamを使用]
    D --> F{loop == NULL?}
    E --> F
    F -->|Yes| G[loop = uv_default_loop]
    F -->|No| H[引数のloopを使用]
    G --> I[handle_queueを走査]
    H --> I
    I --> J{only_activeかつ非アクティブ?}
    J -->|Yes| K[スキップ]
    J -->|No| L[型名を取得]
    L --> M["fprintf [RAI] type addr"]
    K --> I
    M --> I
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-25-01 | NULLストリームのデフォルト | stream==NULLの場合stderrを使用 | 常時 |
| BR-25-02 | NULLループのデフォルト | loop==NULLの場合uv_default_loop()を使用 | 常時 |
| BR-25-03 | API安定性非保証 | ヘッダーに「no API/ABI stability guaranteed」と明記 | 常時 |
| BR-25-04 | アクティブフィルタ | uv_print_active_handles()はonly_active=1で内部関数を呼ぶ | uv_print_active_handles使用時 |

### 計算ロジック

フラグ文字の決定：
- R: `h->flags & UV_HANDLE_REF` が真なら'R'、偽なら'-'
- A: `h->flags & UV_HANDLE_ACTIVE` が真なら'A'、偽なら'-'
- I: `h->flags & UV_HANDLE_INTERNAL` が真なら'I'、偽なら'-'

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | ループ取得失敗 | uv_default_loop()がNULLを返した場合 | "uv_default_loop() failed"をstreamに出力して戻る |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

ハンドル数に比例するO(n)の線形時間。デバッグ用途であるため、パフォーマンス要件は緩い。

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

- ハンドルのメモリアドレスが出力されるため、本番環境のログには注意が必要。
- API/ABI安定性が保証されていない旨がヘッダーに明記されている。

## 備考

- ヘッダーコメントに「Helpers for ad hoc debugging, no API/ABI stability guaranteed.」と記載されており、本番コードでの使用は推奨されない。
- 内部関数`uv__print_handles()`が共通実装であり、`only_active`パラメータで全ハンドル表示とアクティブハンドル表示を切り替える。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | UV_HANDLE_FIELDSマクロ（L463-476）。handle_queueフィールドで全ハンドルがリンクリストで管理される |

**読解のコツ**: ハンドルはイベントループの`handle_queue`に`uv__queue`（侵入型双方向リスト）で連結されている。`uv__queue_data()`マクロでキューノードからハンドルポインタを取得する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv.h | `include/uv.h` | 関数宣言（L501-502）。「no API/ABI stability guaranteed」コメント（L500） |
| 2-2 | uv-common.c | `src/uv-common.c` | uv_print_all_handles()（L613-615）とuv_print_active_handles()（L618-620） |

**主要処理フロー**:
1. **613-615行目**: `uv_print_all_handles()` - only_active=0でuv__print_handles()を呼ぶ
2. **618-620行目**: `uv_print_active_handles()` - only_active=1でuv__print_handles()を呼ぶ

#### Step 3: 内部実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | uv-common.c | `src/uv-common.c` | uv__print_handles()（L573-610）。NULLチェック→キュー走査→fprintf出力のフロー |

**主要処理フロー**:
- **578-579行目**: stream==NULL時にstderrを設定
- **581-587行目**: loop==NULL時にuv_default_loop()を使用
- **589-609行目**: handle_queueを走査し、各ハンドルの型名とフラグを出力
- **596-598行目**: UV_HANDLE_TYPE_MAPマクロで型名文字列を取得
- **602-608行目**: fprintf()で`[RAI] type addr`形式を出力

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

```
uv_print_all_handles(loop, stream)
    └─ uv__print_handles(loop, 0, stream)
           ├─ stream NULLチェック → stderr
           ├─ loop NULLチェック → uv_default_loop()
           └─ uv__queue_foreach → fprintf()

uv_print_active_handles(loop, stream)
    └─ uv__print_handles(loop, 1, stream)
           └─ (同上 + uv__is_active(h) チェック)
```

### データフロー図

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

uv_loop_t* ───▶ handle_queue走査 ───▶ FILE* stream
                 各ハンドルの               (stderr or 指定)
                 flags/type取得
                 └─ fprintf出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | 関数宣言（L501-502） |
| uv-common.c | `src/uv-common.c` | ソース | uv_print_all_handles()/uv_print_active_handles()/uv__print_handles()の実装（L573-620） |
