# 機能設計書 88-Async初期化

## 概要

本ドキュメントは、libuvにおける非同期通知ハンドル初期化機能（uv_async_init）の設計仕様を記述する。uv_async_init()はスレッド間通信用の非同期通知ハンドルを初期化し、別スレッドからイベントループを安全に起こすための仕組みを確立する。

### 本機能の処理概要

**業務上の目的・背景**：マルチスレッドプログラミングにおいて、ワーカースレッドからイベントループスレッドに処理完了を通知したり、イベントループに新しいタスクを依頼したりする必要がある。uv_async_init()はこのスレッド間通信の基盤を提供する。libuvのハンドル操作はスレッドセーフではないため、Asyncハンドルはスレッド安全な通知メカニズムとして重要な役割を担う。

**機能の利用シーン**：ワーカースレッドからのタスク完了通知、スレッドプールの結果のイベントループへの委譲、外部イベントの非同期通知、イベントループのウェイクアップなどで使用される。

**主要な処理内容**：
1. ループの非同期I/O基盤を初期化する（uv__async_start）
2. ハンドルをUV_ASYNCタイプとして初期化する
3. コールバック関数を設定する（NULLも許容）
4. pendingフラグとbusyフラグを0に初期化する
5. ハンドルをループのasync_handlesキューに追加する
6. ハンドルをアクティブ化する

**関連システム・外部連携**：OSのパイプ/eventfd/kqueueのEVFILT_USER機構と連携する。Linuxではeventfd、macOSではkqueueのEVFILT_USERまたはパイプ、その他のUnixではパイプが使用される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | Asyncハンドル | 主機能 | uv_async_init()による非同期通知ハンドル初期化のAPI定義 |

## 機能種別

初期化 / スレッド間通信

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | イベントループ | NULLであってはならない |
| async | uv_async_t* | Yes | 初期化対象のAsyncハンドル | NULLであってはならない |
| async_cb | uv_async_cb | No | 通知受信時のコールバック関数。NULLの場合は通知のみでコールバックなし | 特になし |

### 入力データソース

呼び出し元のアプリケーションコードから直接渡される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、失敗時はエラーコード |

### 出力先

呼び出し元への戻り値。副作用としてループのasync_handlesキューへの追加と非同期I/O基盤の初期化が行われる。

## 処理フロー

### 処理シーケンス

```
1. 非同期I/O基盤の初期化
   └─ uv__async_start(loop)でパイプ/eventfd/kqueueを初期化
      └─ 既に初期化済みなら何もしない
2. ハンドル初期化
   └─ uv__handle_init()でUV_ASYNCとして初期化
3. コールバック設定
   └─ handle->async_cb = async_cb
4. フラグ初期化
   ├─ handle->pending = 0（送信保留フラグ）
   └─ handle->u.fd = 0（ビジーフラグ）
5. キュー登録
   └─ loop->async_handlesキュー末尾に追加
6. アクティブ化
   └─ uv__handle_start(handle)
```

### フローチャート

```mermaid
flowchart TD
    A[uv_async_init 呼び出し] --> B[uv__async_start loop]
    B --> C{初期化失敗?}
    C -->|Yes| D[return エラーコード]
    C -->|No| E[uv__handle_init UV_ASYNC]
    E --> F[async_cb 設定]
    F --> G[pending = 0, busy = 0]
    G --> H[async_handles キュー末尾に追加]
    H --> I[uv__handle_start]
    I --> J[return 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-88-01 | NULLコールバック許容 | async_cbにNULLを渡すことが許容される（ウェイクアップのみ用途） | async_cb == NULLの場合 |
| BR-88-02 | I/O基盤の遅延初期化 | 非同期I/O基盤は最初のuv_async_init()呼び出し時に初期化される | 常時 |
| BR-88-03 | 即時アクティブ | 初期化完了時点でハンドルはアクティブになる | 常時 |
| BR-88-04 | プラットフォーム依存の通知機構 | Linux: eventfd、macOS: EVFILT_USER/パイプ、その他: パイプ | 常時 |

### 計算ロジック

特になし。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_ENOMEM | メモリ不足 | パイプ/eventfdの作成に失敗 | リソースを解放してリトライ |
| UV_EMFILE | FD枯渇 | ファイルディスクリプタの上限到達 | 不要なFDを閉じてリトライ |

### リトライ仕様

I/O基盤の初期化失敗時はリソース解放後にリトライ可能。

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

トランザクション制御なし。

## パフォーマンス要件

- 初期化処理: O(1)（ただし最初の呼び出しでI/O基盤初期化のためのシステムコールあり）

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

- パイプ/eventfdのFDはCLOEXECフラグ付きで作成され、子プロセスへのリークを防止する。

## 備考

- uv_async_init()はuv_async_send()とともにlibuvで唯一スレッドセーフなAPI群の一部であるが、uv_async_init()自体はイベントループスレッドから呼ぶ必要がある。
- async_cbにNULLを渡した場合、uv_async_send()はイベントループを起こすが、コールバックは実行されない。
- macOSでは、kqueueのEVFILT_USERがサポートされている場合はそれを使い、サポートされていない場合はパイプにフォールバックする。ランタイム検出が行われる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **955-958行目**: uv_async_s構造体。UV_HANDLE_FIELDSとUV_ASYNC_PRIVATE_FIELDSで構成 |

**読解のコツ**: pendingフィールドはアトミック操作で使用される送信保留フラグ。u.fdはビジーフラグとして流用される（通常のハンドルではOSファイルディスクリプタ用）。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | async.c | `src/unix/async.c` | **74-90行目**: uv_async_init()関数の実装 |

**主要処理フロー**:
1. **77-79行目**: uv__async_start(loop)でI/O基盤を初期化。エラーなら即return
2. **81行目**: uv__handle_init()でUV_ASYNCとして初期化
3. **82行目**: async_cbを設定
4. **83行目**: pending = 0
5. **84行目**: u.fd = 0（ビジーフラグ）
6. **86行目**: async_handlesキュー末尾に追加
7. **87行目**: uv__handle_start()でアクティブ化

#### Step 3: I/O基盤の初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | async.c | `src/unix/async.c` | **258-329行目**: uv__async_start()の実装 |

**主要処理フロー**:
- **265-266行目**: 既に初期化済み（async_io_watcher.fd != -1）ならreturn 0
- **268-274行目**: Linux: eventfd(EFD_CLOEXEC | EFD_NONBLOCK)
- **275-304行目**: macOS/BSD: kqueue EVFILT_USERまたはパイプ
- **305-308行目**: その他: パイプ
- **311-312行目**: uv__io_init_start()でI/Oウォッチャーを登録

#### Step 4: kqueueランタイム検出を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | async.c | `src/unix/async.c` | **41-67行目**: EVFILT_USERのランタイム検出。**46-66行目**でkqueueにテストイベントを登録して動作確認 |

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

```
uv_async_init(loop, async, async_cb)
    |
    +-- uv__async_start(loop)
    |       |
    |       +-- [Linux] eventfd(EFD_CLOEXEC | EFD_NONBLOCK)
    |       +-- [macOS EVFILT_USER] uv__open_cloexec("/") + kevent()
    |       +-- [その他] uv__make_pipe(UV_NONBLOCK_PIPE)
    |       +-- uv__io_init_start(loop, &loop->async_io_watcher, ...)
    |
    +-- uv__handle_init(loop, handle, UV_ASYNC)
    +-- async_cb = async_cb
    +-- pending = 0, u.fd = 0
    +-- uv__queue_insert_tail(&loop->async_handles, ...)
    +-- uv__handle_start(handle)
```

### データフロー図

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

uv_loop_t*,
uv_async_t*,
uv_async_cb ────> uv_async_init()            ───> int (0 or error)
                       |
                       +-- I/O基盤初期化
                       |     (eventfd/pipe/kqueue)
                       +-- ハンドル初期化
                       +-- async_handles キュー登録
                       +-- ハンドルアクティブ化
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言（960-962行目）、構造体定義（955-958行目） |
| async.c | `src/unix/async.c` | ソース | uv_async_init()実装（74-90行目）、uv__async_start()実装（258-329行目） |
| uv-common.h | `src/uv-common.h` | ヘッダ | uv__handle_init/startマクロ |
