# 機能設計書 128-スレッドアフィニティ制御

## 概要

本ドキュメントは、libuvが提供するスレッドCPUアフィニティ制御機能 `uv_thread_setaffinity()` / `uv_thread_getaffinity()` の設計仕様を記述する。スレッドが実行されるCPUコアを制御するためのクロスプラットフォームAPIである。

### 本機能の処理概要

**業務上の目的・背景**：高性能なアプリケーションでは、スレッドを特定のCPUコアにバインドすることで、キャッシュの局所性を向上させ、コンテキストスイッチのコストを削減できる。本機能はスレッドのCPUアフィニティ（どのCPUで実行されるか）を設定・取得するためのAPIを提供する。ただし、全プラットフォームでサポートされているわけではなく、Linux、FreeBSD、Windowsでのみ利用可能である。

**機能の利用シーン**：リアルタイム処理、低レイテンシアプリケーション、NUMAアーキテクチャ上での最適化、ベンチマーク時のCPU固定に使用される。

**主要な処理内容**：
1. `uv_thread_setaffinity()`: CPUマスクに基づきスレッドのアフィニティを設定し、旧マスクを取得可能
2. `uv_thread_getaffinity()`: 現在のスレッドのCPUアフィニティマスクを取得

**関連システム・外部連携**：Linux sched_setaffinity()/sched_getaffinity()、FreeBSD pthread_setaffinity_np()/pthread_getaffinity_np()、Windows SetThreadAffinityMask()/GetProcessAffinityMask()。

**権限による制御**：アフィニティ設定にはOSレベルの権限が必要な場合がある（Linuxではcapability依存）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | スレッド | 主機能 | uv_thread_setaffinity()/getaffinity()によるCPUアフィニティ制御のAPI定義 |

## 機能種別

リソース管理（CPUアフィニティ制御）

## 入力仕様

### 入力パラメータ

#### uv_thread_setaffinity()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tid | uv_thread_t* | Yes | 対象スレッドID | - |
| cpumask | char* | Yes | 設定するCPUマスク（各バイトが各CPUに対応、0/1） | mask_size >= uv_cpumask_size() |
| oldmask | char* | No | 変更前のCPUマスクの格納先。NULLの場合は取得しない | - |
| mask_size | size_t | Yes | マスク配列のサイズ | uv_cpumask_size()以上 |

#### uv_thread_getaffinity()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tid | uv_thread_t* | Yes | 対象スレッドID | - |
| cpumask | char* | Yes | CPUマスクの格納先 | mask_size >= uv_cpumask_size() |
| mask_size | size_t | Yes | マスク配列のサイズ | uv_cpumask_size()以上 |

### 入力データソース

ユーザーからの関数呼び出しパラメータ。CPUマスクはchar配列で、各要素がCPUコアに対応（0:未使用、非0:使用）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 0:成功、UV_ENOTSUP:非対応プラットフォーム、UV_EINVAL:パラメータエラー |
| cpumask | char[] | 取得されたCPUアフィニティマスク |
| oldmask | char[] | 変更前のCPUアフィニティマスク（setaffinity時、oldmask!=NULLの場合） |

### 出力先

cpumask/oldmask配列にCPUアフィニティ情報が格納される。

## 処理フロー

### 処理シーケンス

```
■ uv_thread_setaffinity()（Unix/Linux版）:
1. uv_cpumask_size()でCPUマスクサイズを取得・検証
2. oldmask != NULLの場合、先にuv_thread_getaffinity()で現在のマスクを取得
3. cpu_set_t構造体を初期化（CPU_ZERO）
4. cpumask配列からcpu_set_t構造体にCPUフラグを設定（CPU_SET）
5. pthread_setaffinity_np()（またはsched_setaffinity()）で適用

■ uv_thread_setaffinity()（Windows版）:
1. uv_cpumask_size()でCPUマスクサイズを取得・検証
2. GetProcessAffinityMask()でプロセスのアフィニティを取得
3. cpumaskからthreadmaskを構築（プロセスマスクとの整合性チェック）
4. SetThreadAffinityMask()で適用、旧マスクを取得
5. oldmask != NULLの場合、旧マスクから配列に変換

■ 非対応プラットフォーム:
1. UV_ENOTSUPを返却
```

### フローチャート

```mermaid
flowchart TD
    A[uv_thread_setaffinity呼び出し] --> B{プラットフォーム対応?}
    B -->|No| Z[UV_ENOTSUP返却]
    B -->|Yes| C[CPUマスクサイズ検証]
    C -->|不足| Y[UV_EINVAL返却]
    C -->|OK| D{oldmask != NULL?}
    D -->|Yes| E[現在のアフィニティ取得]
    D -->|No| F[cpumask→cpu_set_t変換]
    E --> F
    F --> G[pthread_setaffinity_np / SetThreadAffinityMask]
    G -->|成功| H[0返却]
    G -->|失敗| I[エラーコード返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-128-1 | プラットフォーム制限 | Linux、FreeBSD、Windowsのみ対応。その他はUV_ENOTSUP | 常時 |
| BR-128-2 | マスクサイズ検証 | mask_sizeがuv_cpumask_size()未満の場合UV_EINVAL | 常時 |
| BR-128-3 | Windowsプロセスマスク整合性 | Windowsではプロセスアフィニティに含まれないCPUへの設定はUV_EINVAL | Windows |
| BR-128-4 | Android/OHOS特殊処理 | Android/OHOSではpthread_gettid_np()とsched_setaffinity()を使用 | Android/OHOS |

### 計算ロジック

CPUマスク変換（char[] → cpu_set_t）:
```c
CPU_ZERO(&cpuset);
for (i = 0; i < cpumasksize; i++)
    if (cpumask[i])
        CPU_SET(i, &cpuset);
```

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

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_ENOTSUP | 非対応 | 対応していないプラットフォーム | プラットフォーム対応状況を確認 |
| UV_EINVAL | パラメータエラー | mask_sizeが不足、またはプロセスマスク外のCPU指定 | パラメータを修正 |
| UV_EPERM | 権限不足 | アフィニティ設定権限なし | 権限を確認 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

アフィニティ設定はシステムコールを伴うが、通常は即座に完了する。頻繁な変更は推奨されない。

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

- CPUアフィニティの変更にはOS権限が必要な場合がある
- 不適切なアフィニティ設定はシステム全体の性能に影響を与える可能性がある

## 備考

- `uv_cpumask_size()` でCPUマスクの必要サイズを事前に確認すること
- UV__CPU_AFFINITY_SUPPORTEDマクロで機能の有無がコンパイル時に決定される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv.h | `include/uv.h` | **1914-1920行目**: `uv_thread_setaffinity()`/`uv_thread_getaffinity()`の関数シグネチャ |

#### Step 2: Unix/Linux実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | thread.c | `src/unix/thread.c` | **189-227行目**: 対応プラットフォーム版`uv_thread_setaffinity()`。CPUマスクサイズ検証、oldmask取得、cpu_set_t構築、pthread_setaffinity_np()適用 |
| 2-2 | thread.c | `src/unix/thread.c` | **230-259行目**: 対応プラットフォーム版`uv_thread_getaffinity()`。cpu_set_t取得→char配列変換 |
| 2-3 | thread.c | `src/unix/thread.c` | **261-273行目**: 非対応プラットフォーム版（UV_ENOTSUP返却） |

**主要処理フロー（setaffinity Linux版）**:
- **200-203行目**: uv_cpumask_size()でサイズ検証
- **206-209行目**: oldmask指定時、先にgetaffinityで旧マスク取得
- **212-215行目**: cpumask→cpu_set_t変換
- **223行目**: pthread_setaffinity_np()呼び出し

#### Step 3: Windows実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | thread.c | `src/win/thread.c` | **173-214行目**: Windows版`uv_thread_setaffinity()`。プロセスマスク取得、threadmask構築、SetThreadAffinityMask()適用 |
| 3-2 | thread.c | `src/win/thread.c` | **216-243行目**: Windows版`uv_thread_getaffinity()`。SetThreadAffinityMask()のトリック（設定→復元）で現在値を取得 |

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

```
uv_thread_setaffinity() [src/unix/thread.c:191]
    │
    +── uv_cpumask_size() マスクサイズ検証
    +── uv_thread_getaffinity() ※oldmask取得時
    +── CPU_ZERO() / CPU_SET()
    └── pthread_setaffinity_np() / sched_setaffinity()

uv_thread_getaffinity() [src/unix/thread.c:230]
    │
    +── uv_cpumask_size() マスクサイズ検証
    +── CPU_ZERO()
    +── pthread_getaffinity_np() / sched_getaffinity()
    └── CPU_ISSET() → cpumask配列変換

uv_thread_setaffinity() [src/win/thread.c:173]
    │
    +── uv_cpumask_size()
    +── GetProcessAffinityMask()
    +── SetThreadAffinityMask()
    └── oldmask配列変換
```

### データフロー図

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

cpumask (char[]) ──────┐
tid (uv_thread_t*) ────┤──▶ uv_thread_setaffinity()
mask_size ─────────────┤       │
oldmask (char[]*) ─────┘  [cpu_set_t構築]
                               │
                          [OS API呼び出し] ──▶ int (0 or error)
                               │
                          [旧マスク取得] ──▶ oldmask (char[])
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言 |
| thread.c | `src/unix/thread.c` | ソース | Unix実装（Linux/FreeBSD対応版・非対応版） |
| thread.c | `src/win/thread.c` | ソース | Windows実装 |
