# 機能設計書 131-スレッド名制御

## 概要

uv_thread_setname()/uv_thread_getname()によりスレッド名の設定・取得を行う機能の設計書である。

### 本機能の処理概要

本機能は、libuvで管理するスレッドに対して人間可読な名前を設定・取得するためのクロスプラットフォームAPIを提供する。

**業務上の目的・背景**：マルチスレッドアプリケーションのデバッグやプロファイリングにおいて、各スレッドに意味のある名前を付与することで問題特定の効率を大幅に向上させる。デバッガ（gdb、lldb、Visual Studio）やシステムモニタリングツール（top、htop、Activity Monitor）でスレッド名が表示されるため、本番障害時のスレッド特定が容易になる。各プラットフォームではスレッド名のAPI（pthread_setname_np、SetThreadDescriptionなど）が異なり、名前の最大長やAPIシグネチャも統一されていないため、libuvが統一的なインターフェースを提供することでクロスプラットフォーム開発の負担を軽減する。

**機能の利用シーン**：マルチスレッドサーバーアプリケーションにおけるワーカースレッド・I/Oスレッド・タイマースレッドへの名前付与、パフォーマンスプロファイリング時のスレッド識別、クラッシュダンプ解析時のスレッド役割特定に利用される。

**主要な処理内容**：
1. uv_thread_setname()による現在のスレッドへの名前設定（プラットフォーム固有APIへの委譲）
2. uv_thread_getname()による指定スレッドからの名前取得（プラットフォーム固有APIへの委譲）
3. 名前長のプラットフォーム固有上限（UV_PTHREAD_MAX_NAMELEN_NP）への自動切り詰め処理
4. 入力パラメータの検証（NULLチェック、サイズチェック）

**関連システム・外部連携**：POSIX pthread_setname_np/pthread_getname_np、macOS pthread_setname_np/pthread_getname_np、Windows SetThreadDescription/GetThreadDescription APIを内部で使用する。

**権限による制御**：特段の権限制御はない。ただし、uv_thread_getname()は他スレッドの名前も取得可能である。uv_thread_setname()は現在のスレッドのみ設定可能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 28 | スレッド | 主機能 | uv_thread_setname()/getname()によるスレッド名制御のAPI定義 |

## 機能種別

ユーティリティ操作（スレッドメタデータの設定・取得）

## 入力仕様

### 入力パラメータ

#### uv_thread_setname()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | const char* | Yes | 設定するスレッド名（NUL終端文字列） | NULLの場合UV_EINVALを返す。UV_PTHREAD_MAX_NAMELEN_NP-1文字を超える場合は自動切り詰め |

#### uv_thread_getname()

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| tid | uv_thread_t* | Yes | 対象スレッドID | NULLまたは無効なスレッドの場合UV_EINVALを返す（Windows） |
| name | char* | Yes | 名前を格納するバッファ | NULLの場合UV_EINVALを返す |
| size | size_t | Yes | バッファサイズ | 0の場合UV_EINVALを返す |

### 入力データソース

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

## 出力仕様

### 出力データ

#### uv_thread_setname()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、失敗時負のエラーコード（UV_EINVAL, UV_ENOSYS等） |

#### uv_thread_getname()

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | int | 成功時0、失敗時負のエラーコード |
| name | char* | 取得されたスレッド名（NUL終端） |

### 出力先

呼び出し元への戻り値、および引数として渡されたバッファへの書き込み。

## 処理フロー

### 処理シーケンス

```
uv_thread_setname():
1. 入力パラメータ検証
   └─ nameがNULLの場合UV_EINVALを返す
2. プラットフォーム固有実装（uv__thread_setname）の呼び出し
   └─ namebufにUV_PTHREAD_MAX_NAMELEN_NP-1文字までstrncpyでコピー
   └─ NUL終端を保証
3. プラットフォーム固有API呼び出し
   └─ Unix: pthread_setname_np() / pthread_set_name_np()
   └─ Windows: SetThreadDescription()（UTF-16変換後）
   └─ AIX/MVS/PASE: UV_ENOSYSを返す

uv_thread_getname():
1. 入力パラメータ検証
   └─ nameがNULLまたはsizeが0の場合UV_EINVALを返す
2. プラットフォーム固有実装（uv__thread_getname）の呼び出し
3. プラットフォーム固有API呼び出し
   └─ Unix: pthread_getname_np() / pthread_get_name_np()
   └─ Windows: GetThreadDescription()（UTF-16からUTF-8変換）
4. 結果をバッファにコピー
   └─ strncpyでsize-1文字までコピーしNUL終端保証
```

### フローチャート

```mermaid
flowchart TD
    A[uv_thread_setname 呼び出し] --> B{name == NULL?}
    B -->|Yes| C[UV_EINVAL返却]
    B -->|No| D[uv__thread_setname呼び出し]
    D --> E{プラットフォーム判定}
    E -->|AIX/MVS/PASE| F[UV_ENOSYS返却]
    E -->|macOS| G[namebufにコピー・切り詰め]
    G --> H[pthread_setname_np]
    E -->|Linux/FreeBSD等| I[namebufにコピー・切り詰め]
    I --> J[pthread_setname_np]
    E -->|Windows| K{pSetThreadDescription有効?}
    K -->|No| L[UV_ENOSYS返却]
    K -->|Yes| M[UTF-8からUTF-16変換]
    M --> N[SetThreadDescription呼び出し]
    H --> O[結果返却]
    J --> O
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-131-01 | 現スレッド限定設定 | uv_thread_setname()は現在のスレッドの名前のみ設定可能 | 常時 |
| BR-131-02 | 名前長制限 | スレッド名はUV_PTHREAD_MAX_NAMELEN_NP-1文字に切り詰められる | 名前がプラットフォーム固有の上限を超える場合 |
| BR-131-03 | NUL終端保証 | 出力バッファは必ずNUL終端される | 常時 |
| BR-131-04 | スレッド有効性チェック | Windows版getname()では対象スレッドが生存中であることを確認する | Windows環境 |

### 計算ロジック

UV_PTHREAD_MAX_NAMELEN_NPの値はプラットフォームにより異なる：

| プラットフォーム | 値 | 定義元 |
|-----------------|-----|--------|
| Windows | 32767 | src/uv-common.h L442 |
| macOS | 64 | src/uv-common.h L444 |
| NetBSD/illumos | PTHREAD_MAX_NAMELEN_NP | src/uv-common.h L446 |
| Linux | 16 | src/uv-common.h L448 |
| FreeBSD/OpenBSD/DragonFly | MAXCOMLEN + 1 | src/uv-common.h L450 |
| その他 | 16 | src/uv-common.h L452 |

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

該当なし（データベースは使用しない）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_EINVAL | パラメータエラー | name==NULL、size==0、無効なtid | 正しいパラメータで再呼び出し |
| UV_ENOSYS | 未サポート | AIX/MVS/PASE環境、Windows APIが利用不可 | プラットフォーム制約として受け入れる |
| UV_ENOENT | スレッド不在 | Windows版getname()で対象スレッドが終了済み | 有効なスレッドを指定する |
| UV_ENOBUFS | バッファ不足 | Windows版getname()でバッファが不足 | より大きなバッファを使用する |

### リトライ仕様

リトライは不要。

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

該当なし。

## パフォーマンス要件

システムコール1回分のコスト。Windows版ではUTF-8/UTF-16変換のオーバーヘッドが追加される。通常はスレッド起動時に1回呼び出す程度であり、パフォーマンスへの影響は無視できる。

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

スレッド名はプロセス内の他スレッドからも参照可能であり、機密情報を含めるべきではない。バッファオーバーフローはstrncpyとNUL終端保証により防止されている。

## 備考

- uv_thread_setname()は現在のスレッドの名前のみ設定できる設計である。これはmacOSのpthread_setname_np()が自スレッドのみ対応であることに起因する。
- Windows版はSetThreadDescription APIを動的に解決するため、Windows 10 1607以前ではUV_ENOSYSが返る。
- OpenBSDのpthread_set_name_np()は戻り値がvoidであるため、常に成功として扱われる。

---

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

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

### 推奨読解順序

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

スレッド名の長さ上限を定義するマクロと、スレッドID型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv-common.h | `src/uv-common.h` | UV_PTHREAD_MAX_NAMELEN_NPの定義（L441-453、プラットフォーム別の名前長上限） |
| 1-2 | uv.h | `include/uv.h` | uv_thread_setname/getname API宣言（L1925-1926） |

**読解のコツ**: UV_PTHREAD_MAX_NAMELEN_NPは条件コンパイルにより各プラットフォームで異なる値を持つ。Windowsでは32767、Linuxでは16と大きく異なる点に注意。

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

公開APIの入口関数でのパラメータ検証と内部関数への委譲。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | thread.c (Unix) | `src/unix/thread.c` | uv_thread_setname()（L303-307）/ uv_thread_getname()（L309-314） |
| 2-2 | thread.c (Win) | `src/win/thread.c` | uv_thread_setname()（L295-323）/ uv_thread_getname()（L326-367） |

**主要処理フロー**:
1. **L303-307 (Unix setname)**: NULLチェック後、uv__thread_setnameへ委譲
2. **L309-314 (Unix getname)**: NULLチェック・サイズチェック後、uv__thread_getnameへ委譲
3. **L295-323 (Win setname)**: uv_once()でAPI解決、UTF-8→UTF-16変換後にSetThreadDescription呼び出し
4. **L326-367 (Win getname)**: GetThreadDescriptionで取得後UTF-16→UTF-8変換

#### Step 3: Unix版プラットフォーム固有実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | thread.c (Unix) | `src/unix/thread.c` | uv__thread_setname()のプラットフォーム分岐（L898-934） |
| 3-2 | thread.c (Unix) | `src/unix/thread.c` | uv__thread_getname()のプラットフォーム分岐（L936-973） |

**主要処理フロー**:
- **L898-901**: AIX/MVS/PASE - UV_ENOSYSを返す
- **L902-911**: macOS - namebufに切り詰めコピー後、pthread_setname_np(namebuf)
- **L912-918**: NetBSD - pthread_setname_np(pthread_self(), "%s", namebuf)
- **L919-926**: OpenBSD - pthread_set_name_np(pthread_self(), namebuf)
- **L927-933**: Linux等 - pthread_setname_np(pthread_self(), namebuf)
- **L940-941**: Android<26/AIX/MVS/PASE - UV_ENOSYS
- **L943-950**: OpenBSD - pthread_get_name_npで取得
- **L951-960**: macOS - pthread_getname_npで取得
- **L961-972**: Linux等 - pthread_getname_npで取得

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | thread.c (Win) | `src/win/thread.c` | uv__thread_name_init_once()によるAPI動的解決（L284-292） |
| 4-2 | thread.c (Win) | `src/win/thread.c` | setname: UTF-8→UTF-16変換とSetThreadDescription（L295-323） |
| 4-3 | thread.c (Win) | `src/win/thread.c` | getname: GetThreadDescriptionとUTF-16→UTF-8変換（L326-367） |

**主要処理フロー**:
- **L284-292**: GetModuleHandleWでapi-ms-win-core-processthreads-l1-1-3.dllから関数アドレスを動的解決
- **L301-304**: pSetThreadDescriptionがNULLならUV_ENOSYSを返す
- **L309-310**: namebufにUV_PTHREAD_MAX_NAMELEN_NP-1文字まで切り詰めコピー
- **L313**: uv__convert_utf8_to_utf16でUTF-16変換
- **L317**: pSetThreadDescriptionを呼び出し
- **L346**: GetExitCodeThreadでスレッド有効性チェック
- **L351**: pGetThreadDescriptionでUTF-16文字列を取得
- **L356-363**: UTF-16→UTF-8変換してバッファにコピー

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

```
uv_thread_setname(name)
    |
    +-- [パラメータ検証: name != NULL]
    |
    +-- [Unix] uv__thread_setname(name)
    |       +-- strncpy(namebuf, name, UV_PTHREAD_MAX_NAMELEN_NP - 1)
    |       +-- pthread_setname_np() / pthread_set_name_np()
    |
    +-- [Windows]
            +-- uv_once() -> uv__thread_name_init_once()
            |                  +-- GetModuleHandleW()
            |                  +-- GetProcAddress(SetThreadDescription)
            +-- strncpy(namebuf, name, UV_PTHREAD_MAX_NAMELEN_NP - 1)
            +-- uv__convert_utf8_to_utf16()
            +-- pSetThreadDescription()

uv_thread_getname(tid, name, size)
    |
    +-- [パラメータ検証: name != NULL, size > 0]
    |
    +-- [Unix] uv__thread_getname(tid, name, size)
    |       +-- pthread_getname_np() / pthread_get_name_np()
    |       +-- strncpy(name, thread_name, size - 1)
    |
    +-- [Windows]
            +-- uv_once() -> uv__thread_name_init_once()
            +-- GetExitCodeThread() [有効性チェック]
            +-- pGetThreadDescription()
            +-- uv__copy_utf16_to_utf8() / uv__convert_utf16_to_utf8()
```

### データフロー図

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

setname:
  name (const char*)  --> strncpy(切り詰め)              --> pthread_setname_np() / SetThreadDescription()
                          NUL終端保証                        [OSカーネルにスレッド名設定]

getname:
  tid (uv_thread_t*)  --> pthread_getname_np()           --> name バッファにコピー
  name (char*)            / GetThreadDescription()           NUL終端保証
  size (size_t)           strncpy(size - 1文字まで)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダ | API宣言（L1925-1926） |
| uv-common.h | `src/uv-common.h` | ヘッダ | UV_PTHREAD_MAX_NAMELEN_NP定義（L441-453） |
| thread.c (Unix) | `src/unix/thread.c` | ソース | Unix版: uv_thread_setname/getname（L303-314）、uv__thread_setname/getname（L898-973） |
| thread.c (Win) | `src/win/thread.c` | ソース | Windows版: uv_thread_setname/getname（L295-367）、uv__thread_name_init_once（L284-292） |
| test-thread-name.c | `test/test-thread-name.c` | テスト | スレッド名制御のテストケース |
