# 機能設計書 47-Fiberクラス

## 概要

本ドキュメントは、mruby-fiber gemが提供するFiberクラスの機能設計を記述する。軽量な協調的並行処理（コルーチン）を実現するファイバー機能を提供し、resume/yieldによる明示的な制御フローの切り替えとtransferによる任意のファイバー間の制御移譲をサポートする。

### 本機能の処理概要

mruby-fiber gemは、協調的マルチタスク（コルーチン）のためのFiberクラスを提供する。全てC言語(src/fiber.c)で実装されている。各Fiberは独自のVMスタックとコールスタックを持ち、resume/yieldまたはtransferによって実行コンテキストを切り替える。Fiberは明示的にresumeされるまで実行が中断され、yieldによって呼び出し元に制御を戻す。

**業務上の目的・背景**：協調的並行処理は、イテレータ、ジェネレータ、コルーチンなどのプログラミングパターンを実現するための基盤技術である。Enumeratorクラスの外部イテレーション機能は内部的にFiberを使用しており、mrubyの重要な基盤機能である。

**機能の利用シーン**：Enumeratorの内部イテレーション制御、ジェネレータパターンの実装、協調的タスクスケジューリング、非同期処理のシミュレーション、ステートマシンの実装に使用される。

**主要な処理内容**：
1. Fiber.new - ブロックからファイバーを生成
2. Fiber#resume - ファイバーの実行を再開（または初回開始）
3. Fiber.yield - 現在のファイバーから呼び出し元に制御を戻す
4. Fiber#transfer - 任意のファイバーに制御を移譲
5. Fiber#alive? - ファイバーが実行可能かどうかを判定
6. Fiber.current - 現在実行中のファイバーを取得

**関連システム・外部連携**：mrubyコアのVMコンテキスト管理(mrb_context)に直接依存する。

**権限による制御**：なし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はライブラリ機能であり、画面との関連はない |

## 機能種別

並行処理基盤（協調的コルーチン）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| block (Fiber.new) | Block | Yes | ファイバーで実行するブロック | C定義関数ブロックは不可 |
| args (resume) | Any | No | yieldの戻り値として渡す引数（複数可） | - |
| args (Fiber.yield) | Any | No | resumeの戻り値として渡す引数（複数可） | - |
| args (transfer) | Any | No | 転送先ファイバーに渡す引数 | - |

### 入力データソース

メソッド呼び出し時の引数およびブロック

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| resume戻り値 | Object | Fiber.yieldに渡された値、またはブロックの最終値 |
| Fiber.yield戻り値 | Object | 次のresumeに渡された値 |
| alive?戻り値 | Boolean | ファイバーが実行可能かどうか |
| Fiber.current戻り値 | Fiber | 現在実行中のファイバー |
| transfer戻り値 | Object | 転送先からの戻り値 |

### 出力先

メソッドの戻り値として呼び出し元に返却

## 処理フロー

### 処理シーケンス

```
1. Fiber.new { |args| ... }
   ├─ RFiber構造体を割り当て
   ├─ mrb_context構造体を割り当て
   ├─ VMスタック(FIBER_STACK_INIT_SIZE=64)を割り当て
   ├─ コールスタック(FIBER_CI_INIT_SIZE=4)を割り当て
   └─ ステータスをMRB_FIBER_CREATEDに設定

2. fiber.resume(args)
   ├─ ファイバーのステータスを確認（TERMINATED等でエラー）
   ├─ C関数境界チェック
   ├─ 現在のコンテキストをRESUMEDに設定
   ├─ ファイバーのコンテキストに切り替え
   ├─ 初回の場合: 引数をスタックにセット
   └─ 継続の場合: yield戻り値として引数を設定

3. Fiber.yield(args)
   ├─ prevコンテキストの存在確認
   ├─ ルートファイバーからのyield禁止
   ├─ C関数境界チェック
   ├─ ステータスをSUSPENDEDに設定
   ├─ prevコンテキストに切り替え
   └─ 引数をresume戻り値として設定
```

### フローチャート

```mermaid
flowchart TD
    A[Fiber.new block] --> B[コンテキスト割り当て]
    B --> C[CREATED状態]

    D[fiber.resume args] --> E{ステータス?}
    E -->|CREATED| F[初回実行: argsをスタックに]
    E -->|SUSPENDED| G[継続: argsをyield戻り値に]
    E -->|TERMINATED| H[FiberError]
    E -->|RUNNING/RESUMED| I[double resume Error]
    F --> J[コンテキスト切り替え]
    G --> J

    K[Fiber.yield args] --> L{prevあり?}
    L -->|No| M[FiberError]
    L -->|Yes| N[SUSPENDED設定]
    N --> O[prevコンテキストに切り替え]
    O --> P[argsをresume戻り値に]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-01 | C関数境界禁止 | resume/yieldはC関数の境界を越えられない | cci > 0のフレームがある場合 |
| BR-47-02 | 二重resume禁止 | RUNNING/RESUMED状態のファイバーはresumeできない | resume呼び出し時 |
| BR-47-03 | 死んだファイバー禁止 | TERMINATED状態のファイバーはresumeできない | resume呼び出し時 |
| BR-47-04 | ルートyield禁止 | ルートファイバー(mrb->root_c)からyieldできない | Fiber.yield呼び出し時 |
| BR-47-05 | transfer/resume分離 | transferされたファイバーはresumeできない | resume呼び出し時 |
| BR-47-06 | 引数渡し | 15以上の引数は配列にパックされる | resume/yield時 |

### 計算ロジック

fiber_result: 引数0個はnil、1個はそのまま、2個以上は配列にパック

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | FiberError | C定義メソッドからFiber.newを試みた場合 | Rubyブロックを渡す |
| - | FiberError | 未初期化ファイバーにアクセスした場合 | initializeを先に呼ぶ |
| - | FiberError | 死んだファイバーをresumeした場合 | alive?で確認する |
| - | FiberError | 二重resumeした場合 | 状態管理を適切に行う |
| - | FiberError | C関数境界を越えようとした場合 | 構造を見直す |
| - | FiberError | ルートファイバーからyieldした場合 | ファイバー内でyieldする |
| - | RuntimeError | 二重初期化した場合 | 一度だけ初期化する |

### リトライ仕様

リトライは不要

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

該当なし

## パフォーマンス要件

- Fiber生成: VMスタック(64要素)とコールスタック(4要素)のメモリ割り当て
- コンテキスト切り替え: VMレベルのコンテキストスイッチ（OSスレッド切り替えより軽量）
- resume/yield: 定数時間O(1)

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

ファイバーは独自のスタックを持つが、メモリ空間はプロセス内で共有される。ファイバー間でオブジェクトの共有が可能なため、データ競合に注意（ただし協調的スケジューリングのため実際の競合は発生しにくい）。

## 備考

- ファイバーのステータス: CREATED, RUNNING, RESUMED, SUSPENDED, TRANSFERRED, TERMINATED
- MRB_TT_FIBER型を使用
- FiberErrorクラスはStandardErrorのサブクラスとして定義
- vmexecフラグによりC呼び出し時のmrb_vm_exec直接実行モードをサポート
- 15以上の引数は配列にパックされる（n = 15として処理）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fiber.c | `mrbgems/mruby-fiber/src/fiber.c` | 定数定義（13-16行目） |

**読解のコツ**: `struct RFiber`はmrubyコアで定義されており、`cxt`フィールドに`struct mrb_context`へのポインタを持つ。`mrb_context`はVMの実行コンテキスト全体（スタック、コールスタック、ステータス等）を保持する。`mrb->c`は現在のコンテキストを指し、ファイバー切り替えはこのポインタの付け替えで実現される。

#### Step 2: ファイバー初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | fiber.c | `mrbgems/mruby-fiber/src/fiber.c` | init_fiber関数（18-75行目） |

**主要処理フロー**:
1. **23-25行目**: 二重初期化チェック、C関数ブロック禁止
2. **30-31行目**: mrb_context構造体をmallocで割り当て
3. **35-38行目**: VMスタック割り当て（最低64要素 + nregs）
4. **57-58行目**: コールスタック割り当て（4要素）
5. **63-69行目**: 初期callinfo設定（ターゲットクラス、proc、スタック）
6. **72行目**: ステータスをMRB_FIBER_CREATEDに設定

#### Step 3: resume/yieldを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fiber.c | `mrbgems/mruby-fiber/src/fiber.c` | fiber_switch関数（213-303行目） |
| 3-2 | fiber.c | `mrbgems/mruby-fiber/src/fiber.c` | mrb_fiber_yield関数（470-494行目） |

**主要処理フロー**:
- **213-303行目**: `fiber_switch` - resume/transferの共通実装
  - **220-222行目**: 自身へのresume禁止
  - **225-240行目**: ステータスチェック（TRANSFERRED, RUNNING, RESUMED, TERMINATED）
  - **242-250行目**: resume時はRESUMED設定+prev設定、transfer時はTRANSFERRED設定
  - **252-283行目**: CREATED時の初回実行処理（引数セット）
  - **292-297行目**: vmexec時のmrb_vm_exec直接実行
- **470-494行目**: `mrb_fiber_yield` - prevがない場合エラー、SUSPENDED設定、prevに切り替え

#### Step 4: transferとその他メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | fiber.c | `mrbgems/mruby-fiber/src/fiber.c` | transfer, alive?, current, to_s |

**主要処理フロー**:
- **441-467行目**: `fiber_transfer` - cfunc再帰チェック後、resume=FALSEでfiber_switch呼び出し
- **347-352行目**: `fiber_alive_p` - ステータスがTERMINATED以外ならtrue
- **528-538行目**: `fiber_current` - mrb->c->fibを返す（なければ新規作成）
- **376-427行目**: `fiber_to_s` - ファイバー情報文字列（クラス名、アドレス、ファイル:行番号、ステータス）

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

```
mrb_mruby_fiber_gem_init
    |
    +-- mrb_define_class("Fiber")
    +-- MRB_SET_INSTANCE_TT(MRB_TT_FIBER)
    +-- fiber_init (initialize)
    |       +-- init_fiber
    |               +-- mrb_malloc (context)
    |               +-- mrb_malloc (stack)
    |               +-- mrb_malloc (callinfo)
    +-- fiber_resume (resume)
    |       +-- fiber_switch(resume=TRUE)
    |               +-- fiber_check
    |               +-- fiber_check_cfunc
    |               +-- fiber_switch_context
    |               +-- mrb_vm_exec (vmexec時)
    +-- fiber_yield (Fiber.yield)
    |       +-- mrb_fiber_yield
    |               +-- fiber_check_cfunc
    |               +-- fiber_switch_context
    +-- fiber_transfer (transfer)
    |       +-- fiber_check_cfunc_recursive
    |       +-- fiber_switch(resume=FALSE)
    +-- fiber_alive_p (alive?)
    +-- fiber_current (Fiber.current)
    +-- fiber_to_s (to_s / inspect)
```

### データフロー図

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

Block            --> Fiber.new(&block)                   --> Fiber (CREATED)
Fiber + args     --> fiber.resume(*args)                 --> yield値 or ブロック最終値
args             --> Fiber.yield(*args)                   --> resume値
Fiber + args     --> fiber.transfer(*args)               --> transfer先の値
Fiber            --> fiber.alive?                         --> true/false
(なし)           --> Fiber.current                        --> current Fiber
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fiber.c | `mrbgems/mruby-fiber/src/fiber.c` | ソース | 全メソッドのC実装 |
| mrbgem.rake | `mrbgems/mruby-fiber/mrbgem.rake` | 設定 | gem定義ファイル |
| fiber.rb | `mrbgems/mruby-fiber/test/fiber.rb` | テスト | Fiberクラスのテスト |
| fiber2.rb | `mrbgems/mruby-fiber/test/fiber2.rb` | テスト | 追加テスト |
| fibertest.c | `mrbgems/mruby-fiber/test/fibertest.c` | テスト | C APIテスト |
