# 機能設計書 71-プロセス制御

## 概要

本ドキュメントは、Julia言語におけるプロセス制御機能の設計を記述する。`getpid`、`kill`、`detach`、`setenv`、`addenv`、`setcpuaffinity` などの関数を通じて、外部プロセスの生成後のライフサイクル管理を提供する機能である。

### 本機能の処理概要

プロセス制御機能は、Julia から生成された外部プロセスに対して、PID取得、シグナル送信、プロセスの切り離し（デタッチ）、環境変数設定、CPU アフィニティ設定などの制御操作を提供する。

**業務上の目的・背景**：外部コマンドの実行だけでなく、実行中のプロセスに対するきめ細かい制御が必要な場面は多い。例えばサーバープロセスの起動・停止、長時間実行タスクの中断、プロセスごとの環境分離、高性能コンピューティングでのCPUバインディングなど、システムプログラミングにおいて不可欠な機能群である。Julia がシステムプログラミング言語としても利用されるために、POSIXライクなプロセス制御APIを提供する。

**機能の利用シーン**：外部プロセスの起動後のライフサイクル管理全般で使用される。具体的には、バックグラウンドジョブの管理、プロセスの正常終了・強制終了の制御、子プロセスへの環境変数の受け渡し、マルチプロセス環境でのCPUリソース割り当てなどのシーンで利用される。

**主要な処理内容**：
1. `getpid(process)` - 子プロセスのPIDを取得する（libuv経由）
2. `kill(process, signum)` - プロセスへシグナルを送信する（デフォルトはSIGTERM）
3. `detach` - `Cmd`の`detach`フラグを設定し、プロセスを新しいプロセスグループで実行する
4. `setenv` / `addenv` - プロセス実行時の環境変数を設定・追加する
5. `setcpuaffinity` - プロセスのCPUアフィニティマスクを設定する
6. `process_running` / `process_exited` - プロセスの実行状態を確認する
7. `wait(process)` - プロセスの終了を待機する
8. `success(process)` - プロセスの正常終了を確認する

**関連システム・外部連携**：libuv ライブラリを介してOSのプロセス管理API（POSIX signals、Windows process API）と連携する。`uv_process_kill`、`jl_uv_process_pid` などのC関数を`ccall`で呼び出す。

**権限による制御**：プロセスへのシグナル送信はOSレベルの権限に依存する。`setuid`/`setgid` の設定はUnix系OSでroot権限が必要な場合がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | シェルモード（shell>） | 補助機能 | ignorestatus()でプロセス終了コードを無視した実行。kill等によるプロセス制御 |

## 機能種別

プロセス管理・制御処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| p | Process | Yes | 制御対象のプロセスオブジェクト | process_running(p)がtrueであること（kill時） |
| signum | Integer | No | 送信するシグナル番号（デフォルト: SIGTERM=15） | 有効なシグナル番号であること |
| env | Union{Dict,Array,Nothing} | No | 環境変数の設定 | 文字列のキー値ペア |
| cpus | Vector{UInt16} | No | CPUアフィニティマスク | 有効なCPU番号のリスト |
| uid | Union{Nothing,UInt32} | No | プロセスのユーザーID（Unix） | 有効なUID |
| gid | Union{Nothing,UInt32} | No | プロセスのグループID（Unix） | 有効なGID |

### 入力データソース

- Juliaプログラムからの直接呼び出し
- REPLシェルモードからの間接的な利用

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pid | Int32 | getpid()が返すプロセスID |
| exitcode | Int64 | プロセスの終了コード |
| termsignal | Int32 | プロセスを終了させたシグナル番号 |
| running | Bool | プロセスが実行中かどうか |
| success | Bool | プロセスが正常終了したかどうか |

### 出力先

- 戻り値としてJuliaプログラムに返却
- プロセスの標準出力・標準エラー出力はリダイレクト設定に依存

## 処理フロー

### 処理シーケンス

```
1. プロセス生成（_spawn_primitive）
   └─ libuv の jl_spawn を呼び出してプロセスを生成
2. プロセスの状態監視
   └─ process_running / process_exited で状態を確認
3. プロセスへのシグナル送信
   └─ kill() で uv_process_kill を呼び出し
4. プロセス終了待機
   └─ wait() で ThreadSynchronizer 経由で終了を待機
5. 終了ステータスの確認
   └─ success() / test_success() で exitcode と termsignal を確認
6. ハンドル解放
   └─ uvfinalize() でlibuv ハンドルを解放
```

### フローチャート

```mermaid
flowchart TD
    A[プロセス生成] --> B{プロセス実行中?}
    B -->|Yes| C{制御操作}
    C -->|kill| D[uv_process_kill呼び出し]
    C -->|getpid| E[jl_uv_process_pid呼び出し]
    C -->|wait| F[exitnotify待機]
    D --> G[シグナル送信完了]
    E --> H[PID返却]
    F --> I[uv_return_spawn コールバック]
    I --> J[exitcode/termsignal設定]
    J --> K[exitnotify通知]
    K --> L[プロセス終了]
    B -->|No| M[エラーまたは状態返却]
    L --> N[uvfinalize: ハンドル解放]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | シグナル定数 | SIGHUP=1, SIGINT=2, SIGQUIT=3, SIGKILL=9, SIGPIPE=13, SIGTERM=15 が定義済み | 全プラットフォーム共通（一部Windows非対応） |
| BR-71-02 | デフォルトシグナル | kill()のデフォルトシグナルはSIGTERM(15) | signum未指定時 |
| BR-71-03 | 終了判定 | exitcode==0 かつ termsignal==0 のとき成功と判定 | test_success() |
| BR-71-04 | ignorestatus | Cmdのignorestatusフラグがtrueの場合、非ゼロ終了でも例外を投げない | pipeline_error() |
| BR-71-05 | プロセスチェーン | ProcessChainは全プロセスに対して操作を伝播する | kill/wait/success |

### 計算ロジック

CPUアフィニティマスクの変換: `as_cpumask` 関数がVector{UInt16}をBoolの配列に変換し、各CPUインデックスに対応するビットを設定する。

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

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

該当なし（本機能はデータベースを使用しない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UV_ESRCH | UVError | プロセスが既に終了している状態でgetpid呼び出し | プロセスの存在を事前確認 |
| UV_ESRCH | UVError | kill時にプロセスが見つからない（正常終了扱い） | エラーは抑制される |
| ProcessFailedException | Exception | プロセスが非ゼロで終了した場合 | ignorestatus設定またはエラーハンドリング |
| _UVError | UVError | uv_process_kill が失敗（権限不足等） | 適切な権限で実行 |

### リトライ仕様

プロセス制御にリトライ機構は組み込まれていない。必要に応じて呼び出し側で実装する。

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

該当なし（OSプロセス操作のためトランザクション概念は適用されない）

## パフォーマンス要件

- kill()はlibuv経由の非同期操作であり、iolock内で実行される
- wait()はThreadSynchronizerによるブロッキング待機であり、他のタスクはブロックされない
- getpid()はiolock内で実行される軽量操作

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

- setuid/setgid の設定は Unix 系 OS でのみ有効であり、権限昇格のリスクがある
- 環境変数に機密情報（パスワード等）を含める場合はメモリ上の残存に注意
- kill シグナルの送信は OS の権限モデルに従う

## 備考

- Process構造体はmutableであり、ファイナライザ(uvfinalize)が登録される
- ProcessChainはパイプラインで接続された複数のProcessを管理する
- libuv のイベントループとの統合により、非同期的なプロセス終了通知が実現される

---

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

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

### 推奨読解順序

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

まず、プロセス制御に関わるデータ構造（Process、ProcessChain、Cmd）を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | cmd.jl | `base/cmd.jl` | Cmd構造体の定義（exec, ignorestatus, flags, env, dir, cpus, uid, gid フィールド）。UV_PROCESS_DETACHED等のフラグ定数を確認 |
| 1-2 | process.jl | `base/process.jl` | Process構造体（3-21行目）とProcessChain構造体（27-35行目）の定義。handle, exitcode, termsignal, exitnotifyフィールドの役割 |

**読解のコツ**: Process構造体の`handle`フィールド（`Ptr{Cvoid}`）はlibuvのuv_process_tへのポインタであり、C_NULLのときはプロセスが終了済みであることを示す。`exitnotify`はThreadSynchronizerで、プロセス終了の通知に使用される。

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

プロセス制御の主要なAPIエントリーポイントを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | process.jl | `base/process.jl` | kill関数（634-645行目）、getpid関数（657-667行目）、process_running/process_exited（676-687行目） |

**主要処理フロー**:
1. **634-645行目**: `kill(p::Process, signum)` - iolock内でprocess_runningを確認し、uv_process_killを呼び出す
2. **657-667行目**: `Libc.getpid(p::Process)` - iolock内でjl_uv_process_pidを呼び出し、PIDを取得
3. **676行目**: `process_running(s::Process)` - handle != C_NULLで判定

#### Step 3: プロセスライフサイクルコールバックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | process.jl | `base/process.jl` | uv_return_spawn（63-79行目）: プロセス終了時のコールバック。exitcode/termsignalを設定しexitnotifyで通知 |
| 3-2 | process.jl | `base/process.jl` | uvfinalize（49-60行目）: libuvハンドルの解放処理 |
| 3-3 | process.jl | `base/process.jl` | wait(x::Process)（698-720行目）: プロセス終了待機の実装 |

**主要処理フロー**:
- **63-79行目**: `uv_return_spawn` - libuvからのコールバック。exitcode/termsignalを設定し、exitnotifyをnotifyする
- **698-720行目**: `wait` - exitnotify上でwaitし、syncdタスクの完了も待つ

#### Step 4: 終了ステータスの判定を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | process.jl | `base/process.jl` | test_success（558-565行目）、success（567-572行目）、pipeline_error（608-624行目） |

**主要処理フロー**:
- **558-565行目**: `test_success` - exitcode==0 && termsignal==0 で成功判定
- **608-624行目**: `pipeline_error` - ignorestatus でないプロセスの失敗時にProcessFailedExceptionをthrow

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

```
kill(p::Process, signum)
    |
    +-- iolock_begin()
    +-- process_running(p)   // handle != C_NULL チェック
    +-- ccall(:uv_process_kill)  // libuvへのシグナル送信
    +-- iolock_end()

Libc.getpid(p::Process)
    |
    +-- iolock_begin()
    +-- ccall(:jl_uv_process_pid)  // libuv経由でPID取得
    +-- iolock_end()

wait(x::Process)
    |
    +-- process_exited(x)    // 終了済みチェック
    +-- iolock_begin()
    +-- preserve_handle(x)
    +-- lock(x.exitnotify)
    +-- wait(x.exitnotify)   // ThreadSynchronizerで待機
    +-- unlock(x.exitnotify)
    +-- unpreserve_handle(x)
```

### データフロー図

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

Process +            kill()                    シグナル送信結果
signum  ────────▶    uv_process_kill  ────────▶ (nothing / UVError)

Process ────────▶    getpid()         ────────▶ Int32 (PID)
                     jl_uv_process_pid

Process ────────▶    wait()           ────────▶ nothing
                     exitnotify待機             (副作用: exitcode/termsignal設定)

Process ────────▶    success()        ────────▶ Bool
                     test_success()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| process.jl | `base/process.jl` | ソース | Process/ProcessChain構造体定義、kill/getpid/wait/success等のAPI実装 |
| cmd.jl | `base/cmd.jl` | ソース | Cmd構造体定義、detach/setenv/addenv/setcpuaffinity等のCmd構築API |
| pipe.jl | `base/pipe.jl` | ソース | Pipe/PipeEndpoint のI/Oインフラ |
| stream.jl | `base/stream.jl` | ソース | libuvストリーム基盤 |
| libuv.jl | `base/libuv.jl` | ソース | libuv統合の基盤ユーティリティ |
