# 機能設計書 1-プロセス管理

## 概要

本ドキュメントは、FreeBSDカーネルにおけるプロセス管理機能の設計を記述する。プロセスの生成（fork）、実行イメージの置換（exec）、終了（exit）、スケジューリング、およびコンテキスト切替を含むプロセスライフサイクル全般を対象とする。

### 本機能の処理概要

**業務上の目的・背景**：プロセス管理はオペレーティングシステムの最も根幹となる機能であり、ユーザプログラムおよびシステムサービスの実行単位であるプロセスのライフサイクルを制御する。マルチタスク環境において、複数のプログラムを安全かつ効率的に並行実行するために不可欠である。

**機能の利用シーン**：シェルからのコマンド実行時（fork+exec）、デーモンプロセスの起動、Webサーバのワーカープロセス生成、バッチジョブの実行、プロセスの正常終了・異常終了処理、CPU時間の公平な配分など、システム運用のあらゆる場面で利用される。

**主要な処理内容**：
1. **プロセス生成（fork/vfork/rfork）**: 現在のプロセスを複製して新しいプロセスを生成する。`fork1()`が中核関数であり、プロセス構造体の割り当て、アドレス空間の複製（COW: Copy-on-Write）、ファイルディスクリプタテーブルの複製、資格情報の継承を行う。
2. **実行イメージ置換（execve/fexecve）**: プロセスのアドレス空間を新しいプログラムイメージで置換する。ELFバイナリの読み込み、アドレス空間の再構築、レジスタの初期化を行う。
3. **プロセス終了（exit/wait）**: プロセスのリソース解放、親プロセスへの通知（SIGCHLD）、ゾンビ状態への遷移、および`wait`系システムコールによる終了ステータスの回収を行う。
4. **スケジューリング（ULEスケジューラ）**: CPU実行キューの管理、優先度計算、タイムスライスの割り当て、CPU間のロードバランシングを行う。
5. **コンテキスト切替**: `getcontext`/`setcontext`/`swapcontext`によるユーザレベルのコンテキスト保存・復元を提供する。

**関連システム・外部連携**：仮想メモリサブシステム（vm_map, pmap）、ファイルディスクリプタ管理（filedesc）、シグナル処理（signalvar）、セキュリティ監査（audit）、MAC（Mandatory Access Control）フレームワーク、DTraceトレーシングフック、jailサブシステムとの連携がある。

**権限による制御**：プロセス生成時にはリソース制限（maxproc）による制御が行われる。非特権ユーザは最大プロセス数の最後の10個を使用できない。execve時にはsetuid/setgidビットによる資格情報の変更、MACポリシーによる実行可否判定が行われる。プロセス終了時にはinitプロセス（PID 1）の終了を防止するpanicメカニズムが存在する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | プロセス管理はカーネル内部機能であり、直接的なUI画面は存在しない |

## 機能種別

カーネル基盤機能（プロセスライフサイクル管理・CPUスケジューリング）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fork_args.dummy | int | No | fork()は引数なし | - |
| rfork_args.flags | int | Yes | rforkのフラグ（RFPROC, RFFDG等） | 未定義フラグはEINVAL |
| execve_args.fname | char * | Yes | 実行ファイルパス | NULL不可、パス解決必須 |
| execve_args.argv | char ** | Yes | 引数配列 | NULL終端 |
| execve_args.envv | char ** | Yes | 環境変数配列 | NULL終端 |
| exit_args.rval | int | Yes | 終了ステータス | 下位8ビットが親プロセスに通知される |
| wait4_args.pid | pid_t | Yes | 待機対象プロセスID | -1:任意の子, 0:同一プロセスグループ, >0:特定PID |
| wait4_args.options | int | Yes | 待機オプション | WNOHANG, WUNTRACED等 |

### 入力データソース

システムコール経由のユーザ空間からの呼び出し。fork/exec/exitはユーザプログラムまたはlibc経由で発行される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| fork戻り値 | pid_t | 親プロセスには子のPID、子プロセスには0を返す |
| execve戻り値 | int | 成功時は戻らない（EJUSTRETURNで新イメージへ遷移）、失敗時はerrno |
| exit戻り値 | void | 戻らない（プロセス終了） |
| wait4戻り値 | pid_t | 終了した子プロセスのPID、status経由で終了ステータス |

### 出力先

カーネル内プロセステーブル（allproc/zombproc リスト）、ユーザ空間への戻り値。

## 処理フロー

### 処理シーケンス

```
1. fork処理
   ├─ sys_fork() → fork1() 呼び出し
   │    ├─ プロセス数制限チェック（maxproc）
   │    ├─ proc構造体のUMA割り当て
   │    ├─ 資格情報・ファイルディスクリプタの複製
   │    ├─ vmspace_fork()によるアドレス空間のCOW複製
   │    ├─ do_fork()による子プロセスの初期化
   │    └─ スケジューラへの登録（sched_fork）
   │
2. exec処理
   ├─ sys_execve() → kern_execve() → do_execve()
   │    ├─ 実行ファイルのvnode取得（namei）
   │    ├─ イメージアクティベータの選択（ELF等）
   │    ├─ 新アドレス空間の構築
   │    ├─ 引数・環境変数のコピー
   │    └─ レジスタの初期化・新エントリポイントへの遷移
   │
3. exit処理
   ├─ exit1()
   │    ├─ 他スレッドの停止（thread_single）
   │    ├─ リソース解放（ファイル、メモリ、シグナル）
   │    ├─ 子プロセスのreaperへの委譲
   │    ├─ ゾンビ状態への遷移
   │    └─ 親プロセスへSIGCHLD送信
   │
4. スケジューリング
   └─ ULEスケジューラ
        ├─ CPU別実行キュー管理
        ├─ 優先度ベースのプリエンプション
        └─ SMP環境でのロードバランシング
```

### フローチャート

```mermaid
flowchart TD
    A[ユーザプログラム] --> B{システムコール種別}
    B -->|fork| C[sys_fork]
    B -->|execve| D[sys_execve]
    B -->|exit| E[sys_exit]
    B -->|wait| F[sys_wait4]
    C --> C1[fork1: プロセス複製]
    C1 --> C2[do_fork: 子プロセス初期化]
    C2 --> C3[sched_fork: スケジューラ登録]
    D --> D1[kern_execve]
    D1 --> D2[do_execve: イメージ読み込み]
    D2 --> D3[exec_new_vmspace: アドレス空間構築]
    E --> E1[exit1: リソース解放]
    E1 --> E2[proc_reap: ゾンビ化]
    F --> F1[kern_wait6: 子プロセス待機]
    F1 --> F2[終了ステータス回収]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | プロセス数上限 | maxprocを超えるプロセス生成はEAGAINで拒否 | fork1()実行時 |
| BR-02 | 非特権ユーザ制限 | 非特権ユーザはmaxproc-10を超えるプロセス生成不可 | fork1()でpriv_check失敗時 |
| BR-03 | initプロセス保護 | PID 1が終了しようとした場合panicを発生 | exit1()でp==initproc時 |
| BR-04 | ゾンビ回収 | 親プロセスがwait系を呼ぶまでゾンビ状態で残留 | exit後、親がwait未実行の場合 |
| BR-05 | setuid/setgid実行 | execve時にファイルのsetuidビットに応じて実効ユーザIDを変更 | 実行ファイルにSUIDビットが設定されている場合 |
| BR-06 | COWセマンティクス | forkで仮想メモリは書き込み時にのみ物理的にコピー | fork時のアドレス空間複製 |

### 計算ロジック

ULEスケジューラの優先度計算: CPUのインタラクティブ性スコアに基づく動的優先度調整。CPU使用率の高いプロセスは優先度が下げられ、I/O待ちが多いプロセスは優先度が上げられる。

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

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

本機能はカーネル内データ構造を操作するため、RDBMSのようなデータベースは使用しない。代わりに以下のカーネル内データ構造を操作する。

| 操作 | 対象データ構造 | 操作種別 | 概要 |
|-----|-------------|---------|------|
| fork | allproc リスト | INSERT | 新プロセスをグローバルプロセスリストに追加 |
| fork | pidhash テーブル | INSERT | PIDハッシュテーブルに新プロセスを登録 |
| exit | allproc リスト | UPDATE | プロセスをzombprocリストへ移動 |
| wait | zombproc リスト | DELETE | ゾンビプロセスの回収・削除 |
| exec | proc構造体 | UPDATE | 実行イメージ情報の更新 |

### テーブル別操作詳細

#### struct proc（プロセス構造体）

| 操作 | 項目（フィールド名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| fork/INSERT | p_pid | 新規PID割り当て | pidalloc()で取得 |
| fork/INSERT | p_pptr | 親プロセスへのポインタ | fork元プロセス |
| fork/INSERT | p_ucred | 資格情報コピー | crhold()で参照カウント増加 |
| fork/INSERT | p_state | PRS_NEW → PRS_NORMAL | 生成完了後に遷移 |
| exit/UPDATE | p_state | PRS_ZOMBIE | ゾンビ状態への遷移 |
| exec/UPDATE | p_comm | 新プログラム名 | 実行ファイル名の先頭MAXCOMLEN文字 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EAGAIN | リソース制限 | プロセス数がmaxprocに到達 | プロセス終了を待って再試行 |
| ENOMEM | メモリ不足 | proc構造体やvmspaceの割り当て失敗 | メモリ解放後に再試行 |
| EINVAL | 引数不正 | rforkの無効なフラグ指定 | フラグの修正 |
| ENOEXEC | 実行不可 | 認識できないバイナリ形式 | 正しいバイナリを指定 |
| EACCES | 権限不足 | 実行権限がないファイルのexecve | ファイル権限の確認・修正 |
| EFAULT | 不正アドレス | ユーザ空間ポインタが無効 | 正しいポインタを渡す |
| ETXTBSY | テキストビジー | 書き込みオープン中のファイルのexec | ファイルを閉じてから再実行 |

### リトライ仕様

fork失敗時（EAGAIN）はユーザ空間で適切な間隔を置いて再試行する。カーネル内ではリトライは行わない。

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

プロセス操作はカーネルロック（proc lock, allproc_lock等）により排他制御される。fork1()ではプロセス割り当て中にkillsx_lockedフラグで排他制御を管理する。exit1()ではPROC_LOCKおよびthread_single()によりプロセス内の全スレッドを停止させてからリソース解放を行う。これらの操作はアトミックではないが、各段階でのロック取得により一貫性を保証する。

## パフォーマンス要件

- fork: COW（Copy-on-Write）によりアドレス空間の物理コピーを遅延させ、fork時間を最小化
- exec: 実行ファイルの読み込みはページデマンドロードにより必要なページのみ読み込み
- スケジューリング: ULEスケジューラはO(1)の計算量でスケジューリング決定を行う
- コンテキスト切替: マイクロ秒オーダーの切替時間

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

- execve時のsetuid/setgid処理により、特権昇格が制御される
- MACフレームワーク（mac_framework.h）による強制アクセス制御の適用
- セキュリティ監査（audit）によるfork/exec/exit操作の記録
- jail環境下でのプロセス隔離
- ASLR（Address Space Layout Randomization）によるアドレス空間ランダム化
- Capsicumケイパビリティモードとの統合

## 備考

- FreeBSDではrfork()がLinuxのclone()に相当する柔軟なプロセス生成を提供する
- vfork()は子プロセスが親のアドレス空間を一時的に共有し、exec後に解放するため高速
- DTraceフックにより、proc:::createやproc:::exitプローブでプロセスイベントをトレース可能
- kern_fork.cの40行目でEXTERR_CATEGORY EXTERR_CAT_FORKが定義され、拡張エラー報告カテゴリが設定される

---

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

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

### 推奨読解順序

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

まず、プロセスを表現する中核データ構造を把握することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | proc.h | `sys/sys/proc.h` | struct procの定義（653行目〜）。p_state列挙型（PRS_NEW, PRS_NORMAL, PRS_ZOMBIE）、p_pid、p_pptr、p_childrenなどプロセスツリー構造を理解する |
| 1-2 | proc.h | `sys/sys/proc.h` | struct threadの定義。td_proc（所属プロセス）、td_sigmask（シグナルマスク）を確認する |
| 1-3 | sched.h | `sys/sys/sched.h` | スケジューリング関連の構造体定義 |
| 1-4 | imgact.h | `sys/sys/imgact.h` | struct image_paramsの定義。exec時のイメージアクティベータパラメータ |

**読解のコツ**: proc.hのstruct procは非常に大きな構造体であり、各フィールドのコメントに記載されたロック注釈（(c)=proc lock, (b)=birth time only, (d)=allproc_lock, (e)=proctree_lock等）がどのロックで保護されるかを示している。

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

処理の起点となるシステムコールハンドラを特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | kern_fork.c | `sys/kern/kern_fork.c` | sys_fork()（100行目）、sys_vfork()（145行目）、sys_rfork()（162行目）がシステムコールエントリポイント |
| 2-2 | kern_exec.c | `sys/kern/kern_exec.c` | sys_execve()（225行目）、sys_fexecve()（250行目）がエントリポイント |
| 2-3 | kern_exit.c | `sys/kern/kern_exit.c` | exit1()（225行目）がプロセス終了の主処理。kern_wait6()（1393行目）が子プロセス待機処理 |

**主要処理フロー**:
1. **100行目**: sys_fork()はfork_reqを初期化しfork1()を呼び出す
2. **145行目**: sys_vfork()はRFMEM|RFPDSHAREフラグでfork1()を呼び出す（アドレス空間共有）
3. **225行目**: sys_execve()はpre_execve()→exec_copyin_args()→kern_execve()の順で実行
4. **225行目（kern_exit.c）**: exit1()はinitプロセスチェック（244行目）、スレッド停止（269-292行目）を行う

#### Step 3: fork処理の詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | kern_fork.c | `sys/kern/kern_fork.c` | fork1()（894行目〜）: フラグバリデーション、プロセス数制限チェック、proc構造体割り当て |
| 3-2 | kern_fork.c | `sys/kern/kern_fork.c` | do_fork()（409行目〜）: 子プロセスの初期化、ファイルディスクリプタ複製、スケジューラ登録 |

**主要処理フロー**:
- **894-957行目**: fork1()のフラグバリデーションとRFPROCなしの場合の早期リターン
- **965-973行目**: プロセス数制限チェック（非特権ユーザはmaxproc-10が上限）
- **409-411行目**: do_fork()の引数（親スレッド、fork要求、子proc、子thread、vmspace）

#### Step 4: exec処理の詳細を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | kern_exec.c | `sys/kern/kern_exec.c` | do_execve()（393行目〜）: nameiによるvnode解決、イメージアクティベータの実行 |
| 4-2 | imgact_elf.c | `sys/kern/imgact_elf.c` | ELFバイナリのロード処理 |

**主要処理フロー**:
- **225-239行目**: sys_execve()がpre_execve()で旧vmspaceを保存し、失敗時のロールバックに備える
- **393行目〜**: do_execve()がnameiでファイルを検索し、各イメージアクティベータを試行

#### Step 5: スケジューリングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | sched_ule.c | `sys/kern/sched_ule.c` | ULEスケジューラの実装。CPU別実行キュー（tdq構造体）の管理 |
| 5-2 | kern_switch.c | `sys/kern/kern_switch.c` | mi_switch()によるコンテキスト切替の共通処理 |

**主要処理フロー**:
- **29-38行目（sched_ule.c）**: ULEスケジューラの概要コメント。独立CPUランキューと細粒度ロックをサポート

#### Step 6: コンテキスト切替を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | kern_context.c | `sys/kern/kern_context.c` | sys_getcontext()（60行目）、sys_setcontext()（79行目）、sys_swapcontext()（100行目）の実装 |

**主要処理フロー**:
- **60-77行目**: sys_getcontext()はget_mcontext()でマシンコンテキストを取得し、シグナルマスクとともにユーザ空間にコピーアウト
- **79-98行目**: sys_setcontext()はcopyin後にset_mcontext()でレジスタを復元し、シグナルマスクを設定

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

```
sys_fork() / sys_vfork() / sys_rfork()
    |
    +-- fork1()
    |       +-- fork_norfproc()  [RFPROCなしの場合]
    |       +-- proc_alloc()  [UMAゾーンからproc構造体割当]
    |       +-- vmspace_fork()  [COWアドレス空間複製]
    |       +-- do_fork()
    |               +-- filedesc_fork()  [FDテーブル複製]
    |               +-- sched_fork()  [スケジューラ登録]
    |               +-- thread_create()  [子スレッド作成]

sys_execve() / sys_fexecve()
    |
    +-- pre_execve()
    +-- exec_copyin_args()
    +-- kern_execve()
            +-- do_execve()
                    +-- namei()  [ファイル検索]
                    +-- exec_check_permissions()  [権限チェック]
                    +-- imgact_elf()  [ELFローダ]
                    +-- exec_new_vmspace()  [新アドレス空間]
                    +-- exec_copyout_strings()  [引数コピー]

exit1()
    |
    +-- thread_single(SINGLE_EXIT)  [他スレッド停止]
    +-- EVENTHANDLER_INVOKE(process_exit)
    +-- fdescfree()  [FDテーブル解放]
    +-- vmspace_exit()  [アドレス空間解放]
    +-- proc_reparent()  [子プロセスの再親付け]

kern_context.c
    |
    +-- sys_getcontext() --> get_mcontext()
    +-- sys_setcontext() --> set_mcontext()
    +-- sys_swapcontext() --> get_mcontext() + set_mcontext()
```

### データフロー図

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

ユーザプログラム ───> fork()システムコール ───────> 子プロセスPID (親)
                                                       0 (子)

ファイルパス ────> execve()システムコール ──────> 新プログラムイメージ実行
argv, envv                                             (戻らない)

終了ステータス ──> exit()システムコール ────────> SIGCHLD (親へ)
                                                       ゾンビ状態

pid, options ───> wait4()システムコール ────────> 子PID + 終了ステータス
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| kern_fork.c | `sys/kern/kern_fork.c` | ソース | プロセス生成（fork/vfork/rfork）の実装 |
| kern_exec.c | `sys/kern/kern_exec.c` | ソース | 実行イメージ置換（execve）の実装 |
| kern_exit.c | `sys/kern/kern_exit.c` | ソース | プロセス終了・wait処理の実装 |
| kern_proc.c | `sys/kern/kern_proc.c` | ソース | プロセス検索・情報取得の補助関数群 |
| kern_context.c | `sys/kern/kern_context.c` | ソース | getcontext/setcontext/swapcontextの実装 |
| sched_ule.c | `sys/kern/sched_ule.c` | ソース | ULEスケジューラの実装 |
| kern_switch.c | `sys/kern/kern_switch.c` | ソース | コンテキスト切替共通処理 |
| proc.h | `sys/sys/proc.h` | ヘッダ | struct proc / struct thread定義 |
| sched.h | `sys/sys/sched.h` | ヘッダ | スケジューリングインタフェース定義 |
| imgact.h | `sys/sys/imgact.h` | ヘッダ | イメージアクティベータパラメータ定義 |
| imgact_elf.c | `sys/kern/imgact_elf.c` | ソース | ELFバイナリローダ |
