# 機能設計書 89-Async送信

## 概要

本ドキュメントは、libuvにおける非同期通知送信機能（uv_async_send）の設計仕様を記述する。uv_async_send()は任意のスレッドからイベントループスレッドに非同期通知を送信し、登録されたコールバックの実行をトリガーする。libuvにおいて数少ないスレッドセーフなAPIの一つである。

### 本機能の処理概要

**業務上の目的・背景**：マルチスレッドアプリケーションにおいて、ワーカースレッドからイベントループスレッドに安全に通知を送る仕組みが必要である。uv_async_send()はアトミック操作とI/O通知を組み合わせ、スレッドセーフな通知メカニズムを実現する。これにより、ロックフリーで効率的なスレッド間通信が可能になる。

**機能の利用シーン**：ワーカースレッドからのタスク完了通知、外部ライブラリのコールバックからイベントループへの通知、シグナルハンドラからイベントループへの通知、定期的なイベントループのウェイクアップなどで使用される。

**主要な処理内容**：
1. pendingフラグを確認し、既に通知が保留中なら何もしない（コアレシング）
2. busyフラグをインクリメントし、クリティカルセクションに入る
3. pendingフラグをアトミックに1にセットし、0から1への遷移の場合のみI/O通知を送信する
4. busyフラグをデクリメントし、クリティカルセクションを出る

**関連システム・外部連携**：OSのパイプ/eventfd/kqueueのEVFILT_USER機構と連携する。write()システムコールまたはkevent()システムコールを使用してイベントループを起こす。

**権限による制御**：特に権限制御はない。任意のスレッドから呼び出し可能（スレッドセーフ）。

## 関連画面

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

## 機能種別

スレッド間通信 / 通知

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| async | uv_async_t* | Yes | 通知対象のAsyncハンドル | NULLであってはならない |

### 入力データソース

呼び出し元の任意のスレッドから渡されるAsyncハンドルポインタ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 常に0を返す |

### 出力先

呼び出し元への戻り値。副作用としてイベントループのI/Oウォッチャーへの書き込みが行われ、イベントループが起床する。

## 処理フロー

### 処理シーケンス

```
1. 早期リターンチェック
   └─ pendingフラグのリラックスドリード。既に1なら即return 0
2. ビジーフラグインクリメント
   └─ atomic_fetch_add(busy, 1)でクリティカルセクション開始
3. 通知送信
   ├─ atomic_exchange(pending, 1)で前の値を取得
   └─ 前の値が0なら uv__async_send(loop)でI/O通知を送信
4. ビジーフラグデクリメント
   └─ atomic_fetch_add(busy, -1)でクリティカルセクション終了
5. return 0
```

### フローチャート

```mermaid
flowchart TD
    A[uv_async_send 呼び出し] --> B{pending != 0? relaxed read}
    B -->|Yes| C[return 0 早期リターン]
    B -->|No| D[atomic busy++]
    D --> E{atomic_exchange pending,1 前の値}
    E -->|前の値 == 0| F[uv__async_send loop]
    E -->|前の値 != 0| G[通知不要]
    F --> H[atomic busy--]
    G --> H
    H --> I[return 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-89-01 | スレッドセーフ | uv_async_send()は任意のスレッドから安全に呼び出せる | 常時 |
| BR-89-02 | コアレシング | 複数回のuv_async_send()が1回のコールバック呼び出しに統合される可能性がある | 複数回連続呼び出し時 |
| BR-89-03 | 戻り値保証 | 常に0を返す | 常時 |
| BR-89-04 | ビジーフラグによるクローズ安全性 | ビジーフラグによりuv__async_close()はsend中のハンドルを安全に待機できる | ハンドルクローズ時 |

### 計算ロジック

特になし。アトミック操作によるフラグ管理のみ。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| なし | - | uv_async_send()は常に0を返す | - |

### リトライ仕様

リトライ不要。I/O書き込みが失敗した場合（EAGAIN/EWOULDBLOCK以外）はabort()される。

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

トランザクション制御なし。アトミック操作によるロックフリー同期。

## パフォーマンス要件

- 既にpendingの場合: O(1)（リラックスドリードのみ）
- 実際の通知送信: O(1)（write()またはkevent()システムコール1回）

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

特になし。

## 備考

- uv_async_send()はコアレシング特性を持つ。つまり、コールバックが実行される前に複数回uv_async_send()が呼ばれても、コールバックは1回しか呼ばれない場合がある。
- pendingフラグのリラックスドリードは最適化のためで、既にpendingな場合の不要なアトミック操作とI/O書き込みを避ける。
- ビジーフラグ（busy）はuv__async_close()時にスピンウェイトで使用され、send中のハンドルが安全にクローズされることを保証する。
- uv__async_send()内部でのI/O書き込みが失敗した場合（EAGAINを除く）、abort()が呼ばれる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **955-958行目**: uv_async_s構造体。pendingとu.fdに注目 |

**読解のコツ**: pendingフィールドは_Atomic intとしてキャストされて使用される。u.fdフィールドは通常のFD用途ではなく、ビジーフラグとして流用される。

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

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

**主要処理フロー**:
1. **94-95行目**: _Atomic intへのキャスト（pending, busy）
2. **101-102行目**: リラックスドリードによる早期リターン
3. **105行目**: atomic_fetch_add(busy, 1)でビジーフラグ設定
4. **108行目**: atomic_exchange(pending, 1)で前の値を取得
5. **109行目**: 前の値が0ならuv__async_send(loop)で通知
6. **112行目**: atomic_fetch_add(busy, -1)でビジーフラグ解除

#### Step 3: I/O通知の仕組みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | async.c | `src/unix/async.c` | **213-255行目**: uv__async_send()（static関数）の実装 |

**主要処理フロー**:
- **219-229行目**: Linux eventfdの場合、uint64_t値を書き込む
- **231-241行目**: macOS kqueue EVFILT_USERの場合、kevent()でトリガー
- **243-255行目**: パイプの場合、1バイトを書き込む

#### Step 4: コールバック実行側を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | async.c | `src/unix/async.c` | **160-210行目**: uv__async_io()。I/Oポーリングから呼ばれ、保留中のAsyncハンドルのコールバックを実行 |
| 4-2 | async.c | `src/unix/async.c` | **120-150行目**: uv__async_spin()。クローズ時のビジーウェイト |

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

```
uv_async_send(async)  [任意のスレッドから]
    |
    +-- [pending != 0 relaxed] --> return 0
    |
    +-- atomic busy++
    +-- atomic_exchange(pending, 1)
    |       |
    |       +-- [前の値 == 0] --> uv__async_send(loop)
    |                               |
    |                               +-- [Linux] write(eventfd, val)
    |                               +-- [macOS kqueue] kevent(EVFILT_USER, NOTE_TRIGGER)
    |                               +-- [pipe] write(pipe_wfd, buf, 1)
    +-- atomic busy--
    +-- return 0

[イベントループスレッド側]
uv__io_poll() --> uv__async_io()
    +-- read(fd) でI/O通知を消費
    +-- async_handles走査
    +-- atomic_exchange(pending, 0)
    +-- [前の値 != 0] --> async_cb(h)
```

### データフロー図

```
[ワーカースレッド]         [I/O機構]              [イベントループスレッド]

uv_async_send()    ───> eventfd/pipe/kqueue ───> uv__async_io()
  pending=1              write()/kevent()          read()
  busy++/--                                        pending=0
                                                   async_cb(h)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | uv_async_send()のAPI宣言（963行目） |
| async.c | `src/unix/async.c` | ソース | uv_async_send()実装（93-115行目）、uv__async_send()実装（213-255行目）、uv__async_io()実装（160-210行目） |
