# 機能設計書 134-セマフォ

## 概要

uv_sem_init()/uv_sem_destroy()/uv_sem_post()/uv_sem_wait()/uv_sem_trywait()によりセマフォ同期プリミティブを制御する機能の設計書である。

### 本機能の処理概要

本機能は、カウンティングセマフォによるスレッド間同期のためのクロスプラットフォームAPIを提供する。

**業務上の目的・背景**：セマフォは有限リソースへのアクセスを制限するための同期プリミティブであり、プロデューサー・コンシューマーパターンやリソースプールの管理に不可欠である。ミューテックスが1つのスレッドのみがリソースを使用可能であるのに対し、セマフォはカウンタ値までの同時アクセスを許可する。libuvは各プラットフォーム（macOSのMachセマフォ、LinuxのPOSIXセマフォ、glibcのバグ回避用カスタム実装、WindowsのWin32セマフォ）の差異を吸収して統一APIを提供する。

**機能の利用シーン**：コネクションプールの同時接続数制限、ワーカースレッドの同時実行数制御、プロデューサー・コンシューマーキューのフロー制御に利用される。

**主要な処理内容**：
1. uv_sem_init()によるセマフォの初期化（初期カウント値を指定）
2. uv_sem_destroy()によるセマフォの破棄
3. uv_sem_post()によるセマフォカウントの増加（シグナル送信）
4. uv_sem_wait()によるセマフォカウントのブロッキングデクリメント
5. uv_sem_trywait()によるセマフォカウントの非ブロッキングデクリメント試行

**関連システム・外部連携**：macOSではMachセマフォ（semaphore_create/signal/wait）、Linux/glibc < 2.21ではカスタム実装（mutex+condvar）、その他UnixではPOSIXセマフォ（sem_init/post/wait）、WindowsではWin32セマフォ（CreateSemaphore/ReleaseSemaphore/WaitForSingleObject）を使用する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | スレッド | 主機能 | uv_sem_init()/destroy()/post()/wait()/trywait()のAPI定義 |

## 機能種別

同期プリミティブ操作（セマフォ制御）

## 入力仕様

### 入力パラメータ

#### uv_sem_init()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sem | uv_sem_t* | Yes | セマフォオブジェクト | NULLの場合は未定義動作 |
| value | unsigned int | Yes | 初期カウント値 | macOSではKERN_INVALID_ARGUMENTでUV_EINVAL |

#### uv_sem_post() / uv_sem_wait() / uv_sem_trywait() / uv_sem_destroy()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| sem | uv_sem_t* | Yes | セマフォオブジェクト | NULLの場合は未定義動作 |

### 入力データソース

呼び出し元アプリケーションからの直接指定。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 (init) | int | 成功時0、失敗時UV_EINVAL/UV_ENOMEM |
| 戻り値 (trywait) | int | 成功時0、セマフォ値が0の場合UV_EAGAIN |
| 戻り値 (post/wait/destroy) | void | 失敗時abort() |

### 出力先

呼び出し元への戻り値。

## 処理フロー

### 処理シーケンス

```
uv_sem_init():
1. [macOS] semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value)
2. [glibc < 2.21 / MVS] カスタム実装: uv__custom_sem_init()
   └─ mutex + condvar + カウンタで構成されるuv_semaphore_t構造体を動的確保
3. [その他Unix] sem_init(sem, 0, value)
4. [Windows] CreateSemaphore(NULL, value, INT_MAX, NULL)

uv_sem_post():
1. [macOS] semaphore_signal(*sem)
2. [カスタム] mutex lock → value++ → cond_signal → mutex unlock
3. [POSIX] sem_post(sem)
4. [Windows] ReleaseSemaphore(*sem, 1, NULL)

uv_sem_wait():
1. [macOS] semaphore_wait(*sem)（KERN_ABORTEDをリトライ）
2. [カスタム] mutex lock → while(value==0) cond_wait → value-- → mutex unlock
3. [POSIX] sem_wait(sem)（EINTRをリトライ）
4. [Windows] WaitForSingleObject(*sem, INFINITE)

uv_sem_trywait():
1. [macOS] semaphore_timedwait(*sem, {0,0})
   └─ TIMED_OUT → UV_EAGAIN
2. [カスタム] mutex trylock → value==0ならUV_EAGAIN → value-- → unlock
3. [POSIX] sem_trywait(sem) → EAGAIN → UV_EAGAIN
4. [Windows] WaitForSingleObject(*sem, 0) → WAIT_TIMEOUT → UV_EAGAIN
```

### フローチャート

```mermaid
flowchart TD
    A[uv_sem_init] --> B{プラットフォーム}
    B -->|macOS| C[semaphore_create Mach]
    B -->|glibc<2.21/MVS| D[カスタム実装 mutex+cond+counter]
    B -->|その他Unix| E[sem_init POSIX]
    B -->|Windows| F[CreateSemaphore]
    C --> G[結果返却]
    D --> G
    E --> G
    F --> G
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-134-01 | glibc互換 | glibc < 2.21ではsem_destroy()のバグ（#12674）を回避するためカスタム実装を使用 | glibc < 2.21環境 |
| BR-134-02 | macOS Mach | macOSではPOSIXセマフォの代わりにMachセマフォを使用 | macOS環境 |
| BR-134-03 | MVS固定カスタム | z/OS (MVS)では常にカスタム実装を使用 | MVS環境 |
| BR-134-04 | EINTR再試行 | POSIX sem_wait()のEINTRは自動的にリトライされる | Unix（POSIX実装時） |
| BR-134-05 | Windows上限 | WindowsセマフォのカウントはINT_MAXが上限 | Windows環境 |

### 計算ロジック

glibcバージョン判定: `version[0] == '2' && version[1] == '.' && atoi(version + 2) < 21` でglibc 2.21未満かを判定（src/unix/thread.c L532-537）。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | macOSでの無効な初期値 | 正しい初期値で再呼び出し |
| UV_ENOMEM | メモリ不足 | macOSでリソース不足、カスタム実装でmalloc失敗 | メモリ確保後に再試行 |
| UV_EAGAIN | セマフォゼロ | trywait()でセマフォ値が0 | リトライまたは別処理 |
| abort() | 致命的エラー | post/wait/destroy内部での予期しないエラー | プログラムを修正 |

### リトライ仕様

trywait()がUV_EAGAINを返した場合にリトライ可能。wait()はブロッキングで自動待機。

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

該当なし。

## パフォーマンス要件

カスタム実装はmutex+condvar+counterで構成されるため、ネイティブセマフォに比べてオーバーヘッドがある。macOS Machセマフォとglibc >= 2.21のPOSIXセマフォはカーネルネイティブで高速。

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

特になし。

## 備考

- カスタムセマフォ実装（uv_semaphore_t）はuv_sem_tのサイズ内にポインタを格納する形で実装されており、ABI互換性が維持されている。STATIC_ASSERTでsizeof(uv_sem_t) >= sizeof(uv_semaphore_t*)が保証される。
- glibcバージョンチェックはuv_once()で1回だけ実行される。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | unix.h | `include/uv/unix.h` | uv_sem_tの型定義（L133: UV_PLATFORM_SEM_T） |
| 1-2 | win.h | `include/uv/win.h` | uv_sem_tの型定義（L238: HANDLE） |
| 1-3 | uv.h | `include/uv.h` | API宣言（L1863-1867） |
| 1-4 | thread.c (Unix) | `src/unix/thread.c` | uv_semaphore_t構造体定義（L549-553: mutex+cond+value） |

**読解のコツ**: macOSではuv_sem_tがsemaphore_t（Machセマフォ）、Linuxではsem_t（POSIXセマフォ）として定義されるが、glibcバグ回避のカスタム実装ではuv_sem_tの内部にuv_semaphore_t*ポインタを格納するトリックが使われている。

#### Step 2: macOS版実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | thread.c (Unix) | `src/unix/thread.c` | macOS Machセマフォ実装（L458-515） |

**主要処理フロー**:
- **L460-473 (init)**: semaphore_create、KERN_INVALID_ARGUMENT→UV_EINVAL、KERN_RESOURCE_SHORTAGE→UV_ENOMEM
- **L476-479 (destroy)**: semaphore_destroy失敗でabort()
- **L482-485 (post)**: semaphore_signal失敗でabort()
- **L488-497 (wait)**: semaphore_wait、KERN_ABORTEDをdo-whileでリトライ
- **L500-515 (trywait)**: semaphore_timedwait(interval={0,0})、TIMED_OUT→UV_EAGAIN

#### Step 3: カスタム実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | thread.c (Unix) | `src/unix/thread.c` | glibcバージョンチェック（L529-537） |
| 3-2 | thread.c (Unix) | `src/unix/thread.c` | カスタムセマフォ実装（L560-635） |
| 3-3 | thread.c (Unix) | `src/unix/thread.c` | ディスパッチ関数（L684-725） |

**主要処理フロー**:
- **L529-537**: glibc_version_checkでバージョン2.21未満を判定
- **L560-582 (custom_init)**: malloc → mutex_init → cond_init → value設定
- **L595-604 (custom_post)**: mutex_lock → value++ → value==1ならcond_signal → mutex_unlock
- **L607-616 (custom_wait)**: mutex_lock → while(value==0) cond_wait → value-- → mutex_unlock
- **L619-635 (custom_trywait)**: mutex_trylock → value==0ならUV_EAGAIN → value-- → unlock
- **L684-725**: platform_needs_custom_semaphoreフラグでカスタム/POSIX実装を分岐

#### Step 4: Windows版実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | thread.c (Win) | `src/win/thread.c` | Windows版セマフォ実装（L460-498） |

**主要処理フロー**:
- **L460-466 (init)**: CreateSemaphore(NULL, value, INT_MAX, NULL)
- **L469-472 (destroy)**: CloseHandle失敗でabort()
- **L475-478 (post)**: ReleaseSemaphore(*sem, 1, NULL)失敗でabort()
- **L481-484 (wait)**: WaitForSingleObject(*sem, INFINITE)、WAIT_OBJECT_0以外でabort()
- **L487-498 (trywait)**: WaitForSingleObject(*sem, 0)、WAIT_TIMEOUT→UV_EAGAIN

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

```
uv_sem_init(sem, value)
    |
    +-- [macOS] semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value)
    +-- [glibc<2.21/MVS] uv__custom_sem_init()
    |       +-- uv__malloc(sizeof(uv_semaphore_t))
    |       +-- uv_mutex_init(&sem->mutex)
    |       +-- uv_cond_init(&sem->cond)
    +-- [POSIX] sem_init(sem, 0, value)
    +-- [Windows] CreateSemaphore(NULL, value, INT_MAX, NULL)

uv_sem_wait(sem)
    |
    +-- [macOS] semaphore_wait(*sem) [KERN_ABORTEDリトライ]
    +-- [カスタム] uv__custom_sem_wait()
    |       +-- uv_mutex_lock → while(value==0) uv_cond_wait → value-- → uv_mutex_unlock
    +-- [POSIX] sem_wait(sem) [EINTRリトライ]
    +-- [Windows] WaitForSingleObject(*sem, INFINITE)
```

### データフロー図

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

sem, value          --> semaphore_create()         --> 初期化済みセマフォ
                        / sem_init() / CreateSemaphore()

sem                 --> sem_post/signal            --> カウント+1
sem                 --> sem_wait                   --> カウント-1（ブロッキング）
sem                 --> sem_trywait                --> 0 / UV_EAGAIN
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言（L1863-1867） |
| unix.h | `include/uv/unix.h` | ヘッダ | uv_sem_t型定義（L133） |
| win.h | `include/uv/win.h` | ヘッダ | uv_sem_t型定義（L238） |
| thread.c (Unix) | `src/unix/thread.c` | ソース | Unix版セマフォ実装（L458-727） |
| thread.c (Win) | `src/win/thread.c` | ソース | Windows版セマフォ実装（L460-498） |
