# 機能設計書 71-Errnoモジュール

## 概要

本ドキュメントは、mrubyにおけるErrnoモジュールおよびSystemCallErrorクラスの設計について記述する。システムコールエラー番号（errno）に対応する例外クラスを動的に定義し、Rubyレベルでの例外処理を可能にする機能である。

### 本機能の処理概要

Errnoモジュールは、POSIX標準のerrno定数（ENOENT、EPERM、EACCES等）をRubyの例外クラスとして提供する。各errno定数はSystemCallErrorのサブクラスとしてErrnoモジュール配下に動的に定義され、raise/rescue構文で捕捉できる。

**業務上の目的・背景**：mrubyをシステムプログラミングやファイルI/O、ソケット通信等の低レベル操作で利用する際、OSが返すエラーコード（errno）をRubyの例外体系にマッピングする必要がある。本モジュールにより、C言語レベルのシステムエラーをRubyの構造的な例外処理として扱うことが可能になる。

**機能の利用シーン**：ファイルオープン失敗時のErrno::ENOENT、パーミッションエラー時のErrno::EACCES、ソケット接続拒否時のErrno::ECONNREFUSEDなど、I/O操作やシステムコールに失敗した際に利用される。mruby-io、mruby-socket、mruby-dir等の他gemが依存する基盤機能である。

**主要な処理内容**：
1. SystemCallErrorクラスの定義とerrno属性の管理
2. Errnoモジュール配下への各errno例外クラスの遅延定義（const_missing）
3. errno番号からの例外クラス自動解決とインスタンス生成
4. プラットフォーム依存のerrno定数の有無判定と条件付き登録
5. SystemCallError._sys_failによるC APIからの例外発生

**関連システム・外部連携**：OS固有のerrno.hヘッダから定義されるerrno定数に依存する。プラットフォームごとにサポートされるerrno定数が異なるため、ビルド時にknown_errors_def.cstubが生成される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLI/ライブラリとして利用。画面なし |

## 機能種別

例外処理 / エラーハンドリング基盤

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| message | String | No | SystemCallError.newの追加メッセージ | 文字列型チェック |
| errno | Integer | No | SystemCallError.newのエラー番号 | 整数型チェック |
| name | Symbol | Yes | Errno.const_missing等で参照される定数名 | シンボル型チェック |

### 入力データソース

- Cレベルのerrno変数（システムコール失敗時にOS側が設定）
- Rubyコードからの明示的なerrno指定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 例外オブジェクト | Errno::Exxx | SystemCallErrorのサブクラスインスタンス |
| errno値 | Integer | SystemCallError#errnoの戻り値 |
| エラーメッセージ | String | strerror(errno)から生成されるメッセージ文字列 |

### 出力先

例外として発生（raise）され、rescue節で捕捉される。

## 処理フロー

### 処理シーケンス

```
1. gem初期化（mrb_mruby_errno_gem_init）
   ├─ SystemCallErrorクラスをStandardError配下に定義
   ├─ Errnoモジュールを定義
   ├─ Errno::NOERRORクラスを定義（Errno=0）
   └─ Errno::ENOMEMを事前定義（メモリ不足対策）

2. errno例外クラスの遅延定義
   ├─ Errno::ENOENT等の未定義定数参照
   ├─ const_missing → __errno_define(name)呼び出し
   ├─ e2c配列からerrno番号を検索
   ├─ mrb_errno_define_exxxでクラス定義
   └─ Errno定数にerrno番号をセット

3. 例外発生（_sys_fail）
   ├─ errno番号から対応クラスを検索
   ├─ SystemCallErrorインスタンスを生成
   ├─ strerror()でメッセージ生成
   └─ mrb_exc_raiseで例外を発生
```

### フローチャート

```mermaid
flowchart TD
    A[Errno定数参照] --> B{const_missing}
    B --> C[__errno_define呼び出し]
    C --> D{e2c配列に存在?}
    D -->|Yes| E[errno例外クラスを定義]
    D -->|No| F{noe2c配列に存在?}
    F -->|Yes| G[NOERRORクラスを返す]
    F -->|No| H[superに委譲]
    E --> I[Errno定数をセット]
    I --> J[クラスオブジェクトを返す]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-1 | 遅延定義 | errno例外クラスは初回参照時に遅延定義される | Errno配下の未定義定数が参照された場合 |
| BR-71-2 | プラットフォーム依存 | errno定数はビルドプラットフォームで利用可能なもののみ定義される | known_errors_def.cstubによりコンパイル時に決定 |
| BR-71-3 | 未定義errno | プラットフォームで未定義のerrnoはNOERRORクラスにマッピングされる | noe2c配列に含まれるerrno名の場合 |
| BR-71-4 | ENOMEM事前定義 | ENOMEMのみgem初期化時に事前定義される | メモリ不足時の例外発生に備えるため |

### 計算ロジック

特になし。

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

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | SystemCallError | errno番号がe2c配列に存在しない場合 | "Unknown error: N"メッセージで例外生成 |
| - | NameError | errno定数がe2cにもnoe2cにも存在しない場合 | superのconst_missingに委譲 |

### リトライ仕様

リトライは不要。例外はrescueで捕捉される。

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

該当なし。

## パフォーマンス要件

- errno例外クラスの遅延定義により、初期化時のオーバーヘッドを最小化
- e2c/noe2c配列は線形探索（定数個のためO(N)で十分高速）

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

特になし。

## 備考

- known_errors.defには157個のerrno定数名が定義されている
- gen.rbスクリプトでknown_errors_def.cstubが生成され、プラットフォームごとにifdeffedされる
- mruby-io、mruby-socket、mruby-dir等多数のgemが本gemに依存する

---

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

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

### 推奨読解順序

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

まず、errno定数とクラスのマッピングデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | known_errors.def | `mrbgems/mruby-errno/src/known_errors.def` | 全157個のerrno定数名リスト |
| 1-2 | gen.rb | `mrbgems/mruby-errno/src/gen.rb` | defからcstubへの変換ロジック（ifdef生成） |
| 1-3 | errno.c | `mrbgems/mruby-errno/src/errno.c` | e2c/noe2c配列のデータ構造（14-38行目） |

**読解のコツ**: gen.rbが各errno名に対して`#ifdef NAME / itsdefined(NAME, MRB_SYM(NAME)) / #else / itsnotdefined(NAME, MRB_SYM(NAME)) / #endif`を生成する。itsdefined/itsnotdefinedマクロはerrno.cでe2c/noe2c配列の初期化子として展開される。

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

gem初期化関数がクラス/モジュールの定義を行う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | errno.c | `mrbgems/mruby-errno/src/errno.c` | mrb_mruby_errno_gem_init関数（312-330行目） |

**主要処理フロー**:
1. **312-317行目**: SystemCallErrorクラス定義、_sys_fail/errno/initializeメソッド登録
2. **319-322行目**: Errnoモジュール定義、__errno_defined?/__errno_define/__errno_listメソッド登録
3. **324-325行目**: Errno::NOERRORクラス定義（Errno=0）
4. **329行目**: Errno::ENOMEMの事前定義

#### Step 3: 遅延定義メカニズムを理解する

Rubyレベルのconst_missingとCレベルの__errno_defineの連携を追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | errno.rb | `mrbgems/mruby-errno/mrblib/errno.rb` | const_missing/const_defined?/constantsのRuby実装 |
| 3-2 | errno.c | `mrbgems/mruby-errno/src/errno.c` | mrb_errno_define関数（108-129行目） |
| 3-3 | errno.c | `mrbgems/mruby-errno/src/errno.c` | mrb_errno_define_exxx関数（40-58行目） |

**主要処理フロー**:
- **errno.rb 29-31行目**: const_missingが__errno_define(name)を呼び出し
- **errno.c 115-118行目**: e2c配列を線形探索し、マッチしたらerrno例外クラスを定義
- **errno.c 121-126行目**: noe2c配列にマッチした場合はNOERRORクラスを返す
- **errno.c 54-55行目**: SystemCallError配下にクラスを定義し、Errno定数をセット

#### Step 4: 例外発生メカニズムを理解する

SystemCallErrorの生成と_sys_failの動作を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | errno.c | `mrbgems/mruby-errno/src/errno.c` | mrb_sce_sys_fail関数（292-309行目） |
| 4-2 | errno.c | `mrbgems/mruby-errno/src/errno.c` | mrb_sce_init関数（161-193行目） |
| 4-3 | errno.c | `mrbgems/mruby-errno/src/errno.c` | mrb_sce_errno関数（265-280行目） |

**主要処理フロー**:
- **299行目**: 引数としてerrno番号とオプションメッセージを受取
- **306行目**: mrb_sce_initでクラス解決とメッセージ生成
- **307行目**: mrb_exc_raiseで例外を投げる
- **171-177行目**: e2c配列からerrno番号に一致するクラスを検索し、strerror(n)でメッセージ生成

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

```
mrb_mruby_errno_gem_init
    ├─ mrb_define_class_id (SystemCallError)
    ├─ mrb_define_module_id (Errno)
    ├─ mrb_define_class_under_id (NOERROR)
    └─ mrb_errno_define_exxx (ENOMEM事前定義)

Errno::ENOENT (定数参照)
    └─ Errno.const_missing (Ruby)
        └─ Errno.__errno_define (Ruby→C)
            └─ mrb_errno_define (C)
                └─ mrb_errno_define_exxx (C)
                    ├─ mrb_define_class_under_id
                    └─ mrb_define_const_id (Errno定数)

SystemCallError._sys_fail (C API)
    ├─ mrb_obj_alloc (例外オブジェクト生成)
    ├─ mrb_sce_init (クラス解決・メッセージ生成)
    │   ├─ mrb_errno_define_exxx (クラス動的定義)
    │   └─ strerror (メッセージ取得)
    └─ mrb_exc_raise (例外発生)
```

### データフロー図

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

errno番号 ───────▶ e2c配列検索 ──────────▶ 対応クラス発見
  (int)              │                          │
                     ▼                          ▼
              strerror(errno) ──────▶ エラーメッセージ生成
                                        │
メッセージ(opt) ─────────────────────────┘
  (String)                               │
                                         ▼
                               SystemCallError例外インスタンス
                                         │
                                         ▼
                               mrb_exc_raise → rescue節へ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| errno.c | `mrbgems/mruby-errno/src/errno.c` | ソース | Errnoモジュール・SystemCallErrorクラスのC実装 |
| errno.rb | `mrbgems/mruby-errno/mrblib/errno.rb` | ソース | const_missing等のRuby実装 |
| known_errors.def | `mrbgems/mruby-errno/src/known_errors.def` | 定義 | 全157個のerrno定数名リスト |
| gen.rb | `mrbgems/mruby-errno/src/gen.rb` | ツール | known_errors_def.cstub生成スクリプト |
| known_errors_def.cstub | `mrbgems/mruby-errno/src/known_errors_def.cstub` | 生成物 | プラットフォーム依存のifdef付きerrno定義 |
| mrbgem.rake | `mrbgems/mruby-errno/mrbgem.rake` | 設定 | gem定義ファイル |
| errno.rb (test) | `mrbgems/mruby-errno/test/errno.rb` | テスト | テストコード |
