# 画面設計書 13-Asyncハンドル

## 概要

本ドキュメントは、libuvドキュメントサイトにおける `uv_async_t`（Asyncハンドル）APIリファレンスページの画面設計書である。Sphinxにより生成されるHTMLページとして、Asyncハンドルの型定義・API関数仕様を表示する。

### 本画面の処理概要

Asyncハンドルは、別スレッドからイベントループを「ウェイクアップ」し、ループスレッド上でコールバックを呼び出すためのスレッド間通知メカニズムを提供する。本ページでは、Asyncハンドルの初期化と送信に関するAPIを詳細に解説する。

**業務上の目的・背景**：マルチスレッドアプリケーションにおいて、ワーカースレッドからイベントループスレッドに対して安全に通知を送る仕組みが必要である。Asyncハンドルは、スレッドセーフかつシグナルセーフな通知機構を提供し、libuvのイベント駆動モデルとスレッドベースの処理を橋渡しする。Node.jsのネイティブアドオンやスレッドプールの完了通知など、広範な用途で使用される。本ページは、開発者がAsyncハンドルのスレッドセーフ性やコールバックの合体（coalescing）動作を正確に理解するための公式リファレンスである。

**画面へのアクセス方法**：トップページ → APIドキュメント一覧（api.rst） → Asyncハンドル（async.rst）の順にナビゲーションリンクを辿ってアクセスする。

**主要な操作・処理内容**：
1. `uv_async_t` 型の説明とコールバック型 `uv_async_cb` の定義を閲覧する
2. `uv_async_init()` によるハンドル初期化（即座にハンドルが開始される点に注意）の仕様を確認する
3. `uv_async_send()` によるスレッド間通知送信の仕様を確認する
4. コールバックの合体動作（coalescing）に関するwarningを確認する
5. async-signal-safeである点に関するnoteを確認する
6. 基底ハンドル（`uv_handle_t`）の共通API関数へのリンクを辿る

**画面遷移**：
- 遷移元：APIドキュメント一覧（api.rst）
- 遷移先：ハンドル基底ページ（handle.rst）への参照リンク
- 関連ページ：スレッドページ（threading.rst）、スレッドプールページ（threadpool.rst）

**権限による表示制御**：なし（公開ドキュメントサイトのため、全ユーザーが同一内容を閲覧可能）

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 88 | Async初期化 | 主機能 | uv_async_init()による非同期通知ハンドル初期化のAPI定義 |
| 89 | Async送信 | 主機能 | uv_async_send()によるスレッド間非同期通知送信のAPI定義 |

## 画面種別

APIリファレンス詳細ページ

## URL/ルーティング

`docs/src/async.rst` → ビルド後: `/async.html`

## 入出力項目

本ページはドキュメント表示ページのため、ユーザー入力項目はない。

| 項目名 | 入出力 | 型 | 説明 |
|--------|--------|-----|------|
| ページコンテンツ | 出力 | HTML | rstファイルからSphinxによって生成されたHTML |

## 表示項目

| セクション | 表示内容 | 説明 |
|-----------|---------|------|
| タイトル | `uv_async_t` --- Async handle | ページタイトル |
| 概要説明 | Async handles allow the user to "wakeup" the event loop... | Asyncハンドルの動作概要 |
| Data types | `uv_async_t`, `uv_async_cb` | 型定義 |
| Public members | N/A | 固有のパブリックメンバーはなし |
| API - uv_async_init | 初期化関数の仕様 | NULLコールバック許可、即座にハンドル開始 |
| API - uv_async_send | 送信関数の仕様 | スレッドセーフ、async-signal-safe |
| Note (init) | 他のハンドル初期化と異なり即座に開始 | 重要な動作差異 |
| Note (send) | 任意のスレッドから呼び出し可能 | スレッドセーフ性 |
| Note (send) | async-signal-safe | シグナルハンドラからの安全性 |
| Warning (send) | コールバックの合体（coalescing） | 複数回sendしてもコールバックは1回の可能性 |
| See also | uv_handle_t API functions | 基底ハンドルAPIへの参照 |

## イベント仕様

### 1-ページ内リンク遷移

SphinxのreStructuredTextのcross-referenceにより、`:c:type:`uv_handle_t`` へのリンクをクリックすると、ハンドル基底ページに遷移する。signal-safetyの外部リンクで `man7.org` に遷移する。

### 2-Asyncコールバック実行（ランタイム動作）

ドキュメントに記載されるランタイム動作として、別スレッドから `uv_async_send()` を呼び出すと、ループスレッドのI/Oポーリングがウェイクアップされ、登録されたコールバックがループスレッド上で実行される。ただし、複数回のsendが合体されて1回のコールバック実行に統合される場合がある。

## データベース更新仕様

本ページは静的ドキュメント表示のため、データベース操作は存在しない。

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| N/A | N/A | N/A | 静的HTMLドキュメントのためDB操作なし |

### テーブル別更新項目詳細

該当なし

## メッセージ仕様

| メッセージ種別 | 条件 | メッセージ内容 |
|--------------|------|--------------|
| エラー | uv_async_init()初期化失敗 | error code < 0 返却 |
| エラー | uv_async_send()送信失敗 | error code < 0 返却 |

## 例外処理

- ページが見つからない場合：Webサーバーの404エラーが表示される
- Sphinxビルドエラー：rstファイルの構文エラー時にビルド時エラーとして検出される

## 備考

- `uv_async_init()` は他のハンドル初期化関数と異なり、初期化と同時にハンドルが開始される
- NULLコールバックが許可されている（通知のみでコールバック不要な場合）
- `uv_async_send()` はasync-signal-safeであり、シグナルハンドラ内から安全に呼び出せる
- コールバックの合体動作により、正確な呼び出し回数の保証はない
- `uv_handle_t` の共通メンバーおよびAPI関数がそのまま適用される

---

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

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

### 推奨読解順序

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

まず、`uv_async_t` の型定義とコールバック型を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | 955-963行目: `uv_async_s` 構造体定義と `uv_async_init`/`uv_async_send` の関数宣言 |
| 1-2 | async.rst | `docs/src/async.rst` | 1-66行目: ドキュメント全体構成・note/warningの記載内容 |

**読解のコツ**: `uv_async_s` 構造体は `UV_HANDLE_FIELDS` と `UV_ASYNC_PRIVATE_FIELDS` マクロで展開される。プライベートフィールドには `pending` フラグと `async_cb` が含まれ、アトミック操作でスレッドセーフ性を実現している。

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

Unix用のAsync実装を中心に、初期化と送信の仕組みを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | async.c | `src/unix/async.c` | 74-90行目: `uv_async_init` - ループのasyncインフラを開始し、ハンドルを初期化してキューに追加 |
| 2-2 | async.c | `src/unix/async.c` | 93-115行目: `uv_async_send` - アトミック操作でpendingフラグを設定し、ループをウェイクアップ |

**主要処理フロー**:
1. **74行目**: `uv_async_init` - `uv__async_start()` でパイプ/eventfd/kqueueインフラを初期化
2. **81行目**: `uv__handle_init` でハンドルを初期化
3. **86行目**: `async_handles` キューに挿入し即座に開始
4. **93行目**: `uv_async_send` - `atomic_load` でpendingフラグを確認（cheap read）
5. **105行目**: busyフラグをアトミックにインクリメント
6. **108行目**: `atomic_exchange` でpendingを1に設定、以前0なら `uv__async_send` でウェイクアップ

#### Step 3: I/Oコールバック処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | async.c | `src/unix/async.c` | 160-210行目: `uv__async_io` - ループスレッド上でpendingフラグを確認し、コールバックを実行 |

**主要処理フロー**:
- **192行目**: `async_handles` キューを走査
- **202行目**: `atomic_exchange` でpendingフラグを0にリセット
- **208行目**: コールバック `h->async_cb(h)` を実行

#### Step 4: プラットフォーム別のウェイクアップ実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | async.c | `src/unix/async.c` | 213-255行目: `uv__async_send` 内部関数 - Linux(eventfd), BSD(EVFILT_USER), その他(pipe)の3方式 |
| 4-2 | async.c | `src/win/async.c` | 58-92行目: Windows用の `uv_async_init`/`uv_async_send` 実装 |

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

```
uv_async_init(loop, handle, cb) [src/unix/async.c:74]
    |
    +-- uv__async_start(loop) [src/unix/async.c:258]
    |      |
    |      +-- eventfd() / uv__make_pipe() / kqueue EVFILT_USER
    |      +-- uv__io_init_start() [I/Oウォッチャー登録]
    |
    +-- uv__handle_init() [ハンドル初期化]
    +-- uv__queue_insert_tail() [キュー追加]
    +-- uv__handle_start() [即座に開始]

uv_async_send(handle) [src/unix/async.c:93]
    |
    +-- atomic_load(pending) [cheap read]
    +-- atomic_fetch_add(busy, 1) [busyフラグ設定]
    +-- atomic_exchange(pending, 1) [pending設定]
    +-- uv__async_send(loop) [src/unix/async.c:213]
           |
           +-- write(fd) / kevent(EVFILT_USER) [ウェイクアップ]

uv__async_io(loop, w, events) [src/unix/async.c:160]
    |
    +-- read(w->fd) [通知データ読み出し]
    +-- async_handles キュー走査
    +-- atomic_exchange(pending, 0) [pending確認・リセット]
    +-- h->async_cb(h) [ユーザーコールバック実行]
```

### データフロー図

```
[ワーカースレッド]           [イベントループスレッド]

uv_async_send(handle)
    |
    +-- pending = 1 (atomic)
    +-- write(fd) / kevent -------> I/Oポーリングウェイクアップ
                                        |
                                    uv__async_io()
                                        |
                                    pending確認 (atomic)
                                        |
                                    async_cb(handle) 実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| async.rst | `docs/src/async.rst` | テンプレート | Asyncハンドルドキュメントのソース |
| uv.h | `include/uv.h` | ソース | uv_async_t構造体・API関数宣言（955-963行目） |
| async.c | `src/unix/async.c` | ソース | Unix用async init/send/io/close/start/stop/fork実装 |
| async.c | `src/win/async.c` | ソース | Windows用async init/send実装 |
| core.c | `src/unix/core.c` | ソース | イベントループメインロジック |
| loop.c | `src/unix/loop.c` | ソース | ループ初期化時のwq_async設定（97行目） |
| threadpool.c | `src/threadpool.c` | ソース | スレッドプール完了通知でuv_async_sendを使用（129, 312行目） |
