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

## はじめに

このガイドラインは、FreeBSDのコードベースを効率的に理解するための手引きです。
C言語やOSの内部構造に精通していないエンジニアでも、段階的に学習できるよう構成されています。

FreeBSDは30年以上の歴史を持つオープンソースのUnix系オペレーティングシステムであり、カーネル、ユーザランドコマンド、システムライブラリ、デバイスドライバなどで構成される大規模なCコードベースです。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者（特にC言語やOS内部に不慣れなエンジニア）
- コードレビューを行う担当者

---

## 1. 言語基礎

> このセクションでは、C言語（およびFreeBSDプロジェクトで使用されるその他の言語）の基本構文と概念を解説します。

### 1.1 プログラム構造

FreeBSDのソースコードは主にC言語（C99/C11準拠）で記述されています。典型的なカーネルソースファイルは以下の構造を持ちます。

1. ライセンスヘッダ（BSD License）
2. `#include` ディレクティブ（オプション機能のヘッダ、システムヘッダ）
3. ローカルな型定義・マクロ定義
4. スタティック関数のプロトタイプ宣言
5. グローバル変数の定義
6. 関数実装

```c
// ファイル: sys/kern/init_main.c:1-101
/*-
 * SPDX-License-Identifier: BSD-4-Clause
 * Copyright (c) 1995 Terrence R. Lambert
 * ...
 */

#include "opt_ddb.h"          /* オプション機能のヘッダ */
#include "opt_kdb.h"

#include <sys/param.h>        /* システムパラメータ */
#include <sys/systm.h>        /* システム関数 */
#include <sys/kernel.h>       /* カーネル定義 */
...

void mi_startup(void);        /* プロトタイプ宣言 */

static struct session session0; /* グローバル変数 */
struct proc proc0;
```

ユーザランドプログラム（`bin/`、`usr.bin/` 配下）は標準的なCプログラムの構造に従います。

```c
// ファイル: bin/cat/cat.c:35-59
#include <sys/capsicum.h>
#include <sys/param.h>
#include <sys/stat.h>
...
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
```

### 1.2 データ型と変数

FreeBSDでは標準Cの型に加え、カーネル固有の型を多用します。

| 型 | 説明 | 定義元 |
|---|---|---|
| `u_int`, `u_long`, `u_char` | 符号なし整数型のエイリアス | `<sys/types.h>` |
| `size_t`, `ssize_t` | サイズ型 | `<sys/types.h>` |
| `pid_t`, `uid_t`, `gid_t` | プロセス/ユーザ/グループID | `<sys/types.h>` |
| `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t` | 固定幅整数型 | `<sys/stdint.h>` |
| `bus_addr_t`, `bus_size_t` | バスアドレス型 | `<machine/bus.h>` |
| `vm_offset_t`, `vm_paddr_t` | 仮想/物理メモリアドレス型 | `<vm/vm.h>` |

カーネル内の変数宣言例:

```c
// ファイル: sys/kern/init_main.c:106-119
struct proc proc0;             /* プロセス0（カーネルプロセス）の構造体 */
struct vmspace vmspace0;       /* プロセス0のアドレス空間 */
struct proc *initproc;         /* initプロセスへのポインタ */
int boothowto = BOOTHOWTO;    /* ブート制御フラグ */
int bootverbose = BOOTVERBOSE; /* 詳細メッセージ制御 */
```

### 1.3 制御構造

FreeBSDでは標準Cの制御構造に加え、BSD style(9)に準拠したコーディングスタイルが採用されています。

- `if`/`else` の中括弧は必ず使用する（1行でも省略しない傾向）
- `switch` 文でのフォールスルーは `/* FALLTHROUGH */` コメントで明示
- カーネルコードでは `goto` を正常なエラーハンドリングパターンとして使用

```c
// カーネル内の一般的なエラーハンドリングパターン
int
some_function(void)
{
    int error;

    error = step1();
    if (error != 0)
        goto fail;

    error = step2();
    if (error != 0)
        goto fail2;

    return (0);

fail2:
    cleanup_step1();
fail:
    return (error);
}
```

### 1.4 関数/メソッド定義

FreeBSDのCコードは、BSDカーネルの伝統的な関数定義スタイルに従います。戻り値の型は関数名と同じ行に記述します。

```c
// ファイル: sys/kern/init_main.c:175-176
static int
sysinit_compar(struct sysinit *a, struct sysinit *b, void *thunk __unused)
{
    ...
}
```

重要なポイント:
- `static` 関数はファイルスコープ（ファイル内のみから呼び出し可能）
- `__unused` アトリビュートで未使用パラメータを明示
- 戻り値として `(0)` のように括弧付きで return する慣習

### 1.5 モジュール/インポート

FreeBSD C言語のモジュールシステムは `#include` ディレクティブに基づきます。

**カーネルヘッダのインクルードパターン:**

1. `"opt_xxx.h"` -- カーネルコンフィグオプション（コンパイル時生成）
2. `<sys/xxx.h>` -- カーネル共通ヘッダ（`sys/sys/` ディレクトリ）
3. `<machine/xxx.h>` -- アーキテクチャ固有ヘッダ
4. `<vm/xxx.h>` -- 仮想メモリサブシステムヘッダ
5. `<dev/xxx/xxx.h>` -- デバイスドライバ固有ヘッダ

```c
// ファイル: sys/dev/ahci/ahci.c:29-51
#include <sys/param.h>        /* 基本パラメータ（必ず最初） */
#include <sys/module.h>       /* カーネルモジュールAPI */
#include <sys/systm.h>        /* システム関数 */
#include <sys/kernel.h>       /* カーネル定義 */
#include <sys/bus.h>          /* バスフレームワーク */
#include <machine/resource.h> /* アーキテクチャ固有リソース */
#include <machine/bus.h>      /* バスアクセスマクロ */
#include "ahci.h"             /* ローカルヘッダ */
```

**重要:** `<sys/param.h>` は必ず最初にインクルードします。多くの基本マクロや型定義がここに含まれています。

---

## 2. プロジェクト固有の概念

> このセクションでは、FreeBSDプロジェクト特有の概念を解説します。

### 2.1 フレームワーク固有の概念

#### SYSINIT -- カーネル初期化フレームワーク

FreeBSDカーネルの初期化はSYSINITフレームワークで管理されます。各サブシステムは `SYSINIT` マクロを使い、初期化関数とその実行順序を宣言します。

```c
// ファイル: sys/sys/kernel.h:95-179（抜粋）
enum sysinit_sub_id {
    SI_SUB_TUNABLES     = 0x0700000,  /* 調整パラメータ設定 */
    SI_SUB_VM           = 0x1000000,  /* 仮想メモリシステム初期化 */
    SI_SUB_KMEM         = 0x1800000,  /* カーネルメモリ */
    SI_SUB_KLD          = 0x2000000,  /* KLD/モジュールセットアップ */
    SI_SUB_DRIVERS      = 0x3100000,  /* ドライバ初期化 */
    SI_SUB_VFS          = 0x4000000,  /* 仮想ファイルシステム */
    SI_SUB_PROTO_DOMAIN = 0x8800000,  /* プロトコルドメイン */
    SI_SUB_LAST         = 0xfffffff,  /* 最終 */
};
```

数値が小さい順に初期化が実行されるため、サブシステム間の依存関係が数値順序で表現されます。

#### デバイスドライバフレームワーク (newbus)

FreeBSDのデバイスドライバは `newbus` フレームワークに基づいています。ドライバは `device_method_t` 配列でメソッドテーブルを定義し、バス階層に登録されます。

#### カーネルモジュール (KLD)

FreeBSDはカーネルモジュール（KLD: Kernel Loadable module）をサポートします。`DECLARE_MODULE` マクロにより、動的にロード/アンロード可能なモジュールを定義できます。

#### SYSCTL -- ランタイムカーネルパラメータ

`sysctl` インタフェースにより、カーネルパラメータを実行時に読み書きできます。

```c
// ファイル: sys/kern/init_main.c:132-140
SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0,
    "Boot control flags, passed from loader");
SYSCTL_INT(_debug, OID_AUTO, bootverbose, CTLFLAG_RW, &bootverbose, 0,
    "Control the output of verbose kernel messages");
```

- `CTLFLAG_RD`: 読み取り専用
- `CTLFLAG_RW`: 読み書き可能

### 2.2 プロジェクト独自のパターン

#### ロッキングプリミティブ

FreeBSDカーネルは複数のロック機構を使い分けます:

| ロック種別 | ヘッダ | 用途 |
|---|---|---|
| `struct mtx` (mutex) | `<sys/mutex.h>` | 短時間の排他制御 |
| `struct sx` (shared/exclusive lock) | `<sys/sx.h>` | 読み書きロック |
| `struct rwlock` | `<sys/rwlock.h>` | 読み書きロック（割り込みコンテキスト不可） |
| `struct rmlock` | `<sys/rmlock.h>` | 読み取り側がロックフリーに近いロック |
| `epoch` | `<sys/epoch.h>` | RCU類似の読み取り側ロックフリー機構 |

#### メモリ割り当て

カーネル内のメモリ割り当ては `malloc(9)` / `free(9)` を使用しますが、ユーザランドとは異なるインタフェースです。

```c
// カーネル内のmalloc使用例
// MALLOC_DECLARE でメモリタイプを宣言し、用途別に統計を取る
MALLOC_DECLARE(M_AHCI);
ptr = malloc(size, M_AHCI, M_WAITOK | M_ZERO);
free(ptr, M_AHCI);
```

- `M_WAITOK`: メモリが確保できるまで待機可能
- `M_NOWAIT`: 待機不可（割り込みコンテキストなど）
- `M_ZERO`: 確保したメモリをゼロクリア

#### キューマクロ

FreeBSDは `<sys/queue.h>` で定義されるキュー/リストマクロを広範囲に使用します:

- `SLIST_*`: 単方向リンクリスト
- `LIST_*`: 双方向リンクリスト
- `STAILQ_*`: 単方向テールキュー
- `TAILQ_*`: 双方向テールキュー

```c
// ファイル: sys/kern/init_main.c:167-169
static STAILQ_HEAD(sysinitlist, sysinit) sysinit_list;
static struct sysinitlist sysinit_done_list =
    STAILQ_HEAD_INITIALIZER(sysinit_done_list);
```

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `kern_*.c` | カーネルコア機能の実装 | `kern_proc.c`, `kern_malloc.c`, `kern_clock.c` |
| `init_*.c` | 初期化関連コード | `init_main.c`, `init_sysent.c` |
| `imgact_*.c` | イメージアクティベータ（実行形式ハンドラ） | `imgact_elf.c`, `imgact_shell.c` |
| `vfs_*.c` | 仮想ファイルシステム層 | `vfs_mount.c`, `vfs_lookup.c` |
| `if_*.c` / `if_*.h` | ネットワークインタフェース関連 | `if_bridge.c`, `if_vlan.c`, `if_loop.c` |
| `vm_*.c` / `vm_*.h` | 仮想メモリサブシステム | `vm_map.c`, `vm_page.c`, `vm_kern.c` |
| `*_if.m` | デバイスインタフェース定義（M4マクロ） | `device_if.m`, `bus_if.m` |
| `opt_*.h` | カーネルコンフィグオプション（ビルド時生成） | `opt_ddb.h`, `opt_inet.h` |
| `*.9` | Section 9 マニュアルページ（カーネルAPI文書） | `malloc.9`, `mutex.9` |

### 3.2 クラス・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `kern_*()` | カーネル内部実装関数 | `kern_open()`, `kern_close()` |
| `sys_*()` | システムコールエントリポイント | `sys_open()`, `sys_read()` |
| `*_init()` / `*_fini()` | 初期化/終了処理 | `ahci_ch_init()`, `ahci_ch_deinit()` |
| `*_attach()` / `*_detach()` | デバイスの接続/切断 | ドライバの probe/attach/detach パターン |
| `*_probe()` | デバイス検出 | ドライバがハードウェアの存在を確認 |
| `*_intr()` | 割り込みハンドラ | `ahci_intr()`, `ahci_ch_intr()` |
| `*_timeout()` | タイムアウトハンドラ | `ahci_timeout()` |
| `SI_SUB_*` | SYSINIT サブシステムID | `SI_SUB_VM`, `SI_SUB_DRIVERS` |
| `M_*` | malloc メモリタイプ | `M_AHCI`, `M_TEMP` |
| `CTLFLAG_*` | sysctl フラグ | `CTLFLAG_RD`, `CTLFLAG_RW` |
| `TDP_*` | スレッドプライベートフラグ | `TDP_NOFAULTING` |

### 3.3 プログラム分類一覧

| 分類 | ディレクトリ | 説明 | 例 |
|------|-------------|------|-----|
| カーネルコア | `sys/kern/` | プロセス管理、メモリ、スケジューラ等 | `kern_proc.c`, `kern_malloc.c` |
| デバイスドライバ | `sys/dev/` | ハードウェアドライバ | `ahci/`, `usb/`, `pci/` |
| ファイルシステム | `sys/fs/` | ファイルシステム実装 | `tmpfs/`, `ext2fs/`, `nullfs/` |
| ネットワーク | `sys/net/`, `sys/netinet/` | ネットワークプロトコル | `if.c`, `tcp_input.c` |
| システムコマンド | `bin/`, `sbin/` | 基本コマンド | `cat`, `ls`, `mount` |
| ユーザコマンド | `usr.bin/`, `usr.sbin/` | ユーザ/管理コマンド | `awk`, `top`, `cron` |
| システムライブラリ | `lib/` | 共有ライブラリ | `libc`, `libpthread` |
| ブートローダ | `stand/` | ブートローダソース | EFI/BIOS ブートコード |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
freebsd-src/
├── bin/          ... 基本システムコマンド (/bin に配置)
├── sbin/         ... 基本システム管理コマンド (/sbin に配置)
├── usr.bin/      ... ユーザコマンド (/usr/bin に配置)
├── usr.sbin/     ... システム管理コマンド (/usr/sbin に配置)
├── lib/          ... システムライブラリ
│   ├── libc/     ... C標準ライブラリ
│   └── ...
├── libexec/      ... システムデーモン
├── include/      ... システムインクルードファイル (/usr/include に配置)
├── sys/          ... カーネルソース
│   ├── kern/     ... カーネルコア (プロセス管理, メモリ, VFS等)
│   ├── dev/      ... デバイスドライバ
│   ├── net/      ... ネットワーク基盤
│   ├── netinet/  ... IPv4/TCP/UDP プロトコル
│   ├── netinet6/ ... IPv6 プロトコル
│   ├── fs/       ... ファイルシステム実装
│   ├── vm/       ... 仮想メモリサブシステム
│   ├── cam/      ... CAM (Common Access Method) SCSIフレームワーク
│   ├── geom/     ... GEOM ストレージフレームワーク
│   ├── conf/     ... カーネルコンフィグ・ビルド設定
│   ├── modules/  ... ロード可能カーネルモジュールのMakefile
│   ├── amd64/    ... AMD64アーキテクチャ固有コード
│   ├── arm64/    ... ARM64アーキテクチャ固有コード
│   ├── i386/     ... i386アーキテクチャ固有コード
│   └── sys/      ... カーネル共通ヘッダ (sys/*.h)
├── etc/          ... /etc のテンプレートファイル
├── share/        ... 共有リソース (man pages, locale等)
│   └── man/      ... マニュアルページ
│       └── man9/ ... Section 9: カーネルAPI リファレンス
├── contrib/      ... サードパーティのソフトウェア
├── crypto/       ... 暗号関連コード
├── cddl/         ... CDDLライセンスのコード (DTrace, ZFS等)
├── gnu/          ... GPLライセンスのコード
├── stand/        ... ブートローダソース
├── tests/        ... 回帰テスト (Kyua)
├── tools/        ... ビルドツール・ユーティリティ
├── release/      ... リリースビルド用Makefile
├── rescue/       ... 静的リンク版レスキューユーティリティ
├── targets/      ... 実験的 DIRDEPS_BUILD サポート
├── Makefile      ... トップレベルMakefile
└── Makefile.inc1 ... ビルドシステムの中核ロジック
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `sys/kern/` | カーネルコア機能（プロセス管理、メモリ、同期、タイマー等） | `init_main.c`, `kern_proc.c`, `kern_malloc.c` |
| `sys/dev/` | デバイスドライバ（各デバイスごとにサブディレクトリ） | `ahci/ahci.c`, `usb/`, `pci/` |
| `sys/net/` | ネットワーク基盤（インタフェース、BPF、ルーティング等） | `if.c`, `bpf.c`, `route.c` |
| `sys/netinet/` | IPv4/TCP/UDP プロトコルスタック | `tcp_input.c`, `ip_input.c` |
| `sys/fs/` | ファイルシステム実装（各FSごとにサブディレクトリ） | `tmpfs/`, `ext2fs/`, `nullfs/` |
| `sys/vm/` | 仮想メモリサブシステム | `vm_map.c`, `vm_page.c`, `uma_core.c` |
| `sys/conf/` | カーネルコンフィグ・ビルド設定 | `files`, `options`, `Makefile.amd64` |
| `lib/libc/` | C標準ライブラリ（FreeBSD実装） | syscallラッパー、stdio等 |
| `bin/` | 基本コマンド（`/bin` にインストールされる） | `cat/`, `cp/`, `ls/`, `sh/` |
| `share/man/man9/` | カーネルAPI リファレンスマニュアル | `malloc.9`, `mutex.9` |

---

## 5. アーキテクチャ

> このセクションでは、FreeBSDカーネルのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

FreeBSDはモノリシックカーネルアーキテクチャを採用していますが、KLD（Kernel Loadable Module）による動的モジュールロード機構を持ち、機能の動的追加が可能です。

```
┌─────────────────────────────────────────────────────────┐
│                   ユーザランド                            │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐               │
│  │ bin/     │  │ usr.bin/ │  │ lib/     │               │
│  │ (基本cmd)│  │ (user cmd)│  │ (ライブラリ)│              │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘               │
├───────┼─────────────┼─────────────┼─────────────────────┤
│       │  システムコール (sys/kern/syscalls.master)        │
├───────┼─────────────┼─────────────┼─────────────────────┤
│                   カーネル空間                            │
│  ┌─────────────────────────────────────────────────┐     │
│  │ sys/kern/ -- カーネルコア                         │     │
│  │  (プロセス管理, スケジューラ, メモリ管理)           │     │
│  ├─────────────────────────────────────────────────┤     │
│  │ sys/vm/  -- 仮想メモリサブシステム (UMA, pmap)    │     │
│  ├──────────────┬──────────────┬────────────────────┤     │
│  │ sys/net/     │ sys/fs/      │ sys/dev/           │     │
│  │ sys/netinet/ │ VFS層        │ デバイスドライバ     │     │
│  │ ネットワーク   │ ファイルシステム│ (newbusフレームワーク)│     │
│  ├──────────────┴──────────────┴────────────────────┤     │
│  │ アーキテクチャ固有層 (sys/amd64/, sys/arm64/ 等)  │     │
│  │  (pmap, トラップ処理, コンテキストスイッチ)         │     │
│  └─────────────────────────────────────────────────┘     │
│  ┌─────────────────────────────────────────────────┐     │
│  │ sys/modules/ -- ロード可能カーネルモジュール (KLD) │     │
│  └─────────────────────────────────────────────────┘     │
├─────────────────────────────────────────────────────────┤
│                   ハードウェア                            │
└─────────────────────────────────────────────────────────┘
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| ユーザランド | ユーザ向けコマンド・ライブラリ | `bin/cat/cat.c`, `lib/libc/` |
| システムコールインタフェース | ユーザランドとカーネルの境界 | `sys/kern/syscalls.master`, `sys/kern/init_sysent.c` |
| カーネルコア | プロセス管理・メモリ管理・スケジューリング | `sys/kern/kern_proc.c`, `sys/kern/kern_malloc.c` |
| VFS (仮想ファイルシステム) | ファイルシステムの抽象化層 | `sys/kern/vfs_mount.c`, `sys/kern/vfs_lookup.c` |
| ネットワークスタック | プロトコル処理・インタフェース管理 | `sys/net/if.c`, `sys/netinet/` |
| デバイスドライバ (newbus) | ハードウェア抽象化・ドライバ | `sys/dev/ahci/ahci.c`, `sys/dev/usb/` |
| 仮想メモリ (VM) | ページ管理・メモリアロケータ (UMA) | `sys/vm/vm_page.c`, `sys/vm/uma_core.c` |
| アーキテクチャ依存層 | CPU固有処理 (pmap, トラップ, コンテキストスイッチ) | `sys/amd64/amd64/pmap.c` |

### 5.3 データフロー

**システムコールのデータフロー例（read システムコール）:**

```
ユーザプロセス: read(fd, buf, len)
    ↓ (トラップ)
sys/kern/syscalls.master -- システムコール番号から関数を解決
    ↓
sys/kern/sys_generic.c: sys_read()
    ↓
sys/kern/vfs_vnops.c: vn_read()  -- VFS層
    ↓
各ファイルシステム実装: (例: sys/fs/tmpfs/ or sys/ufs/)
    ↓
sys/vm/ -- ページキャッシュ / バッファキャッシュ
    ↓
sys/dev/ -- デバイスドライバ (必要に応じてディスクI/O)
    ↓ (結果をユーザ空間にcopyout)
ユーザプロセス: read() 戻り値
```

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

**カーネルの起動エントリーポイント:**

カーネルの初期化は `mi_startup()` 関数から始まります。この関数はSYSINITリストをソートし、順番に初期化関数を実行します。

```c
// ファイル: sys/kern/init_main.c:101
void mi_startup(void);  /* Machine-Independent startup */
```

SYSINIT リストは `sys/sys/kernel.h` で定義された `enum sysinit_sub_id` の順序で実行されます（数値昇順）。最初のプロセス（proc0）と最初のスレッド（thread0）はここで初期化されます。

```c
// ファイル: sys/kern/init_main.c:103-117
/* Components of the first process -- never freed. */
static struct session session0;
static struct pgrp pgrp0;
struct proc proc0;
struct thread0_storage thread0_st __aligned(32) = {
    .t0st_thread = {
        .td_pflags = TDP_NOFAULTING,
    },
};
```

**ユーザランドコマンドのエントリーポイント:**

各コマンドは標準的な `main()` 関数を持ちます。

### 6.2 ビジネスロジック

FreeBSDの場合、「ビジネスロジック」はカーネルの各サブシステムに相当します。

- **プロセス管理**: `sys/kern/kern_proc.c`, `sys/kern/kern_fork.c`, `sys/kern/kern_exit.c`
- **メモリ管理**: `sys/kern/kern_malloc.c`, `sys/vm/vm_map.c`, `sys/vm/uma_core.c`
- **スケジューリング**: `sys/kern/sched_ule.c` (ULEスケジューラ)
- **ファイルシステム**: `sys/kern/vfs_*.c`, `sys/fs/` 配下
- **ネットワーク**: `sys/net/`, `sys/netinet/`, `sys/netinet6/`

### 6.3 データアクセス

FreeBSDにおけるデータアクセスは以下のサブシステムが担います:

- **VFS (Virtual File System)**: ファイルシステムの抽象化層。`sys/kern/vfs_*.c` で定義
- **GEOM**: ストレージ変換フレームワーク。`sys/geom/` で定義。ディスクI/Oのパイプライン（パーティション、暗号化、RAID等）を構成
- **CAM (Common Access Method)**: SCSI/ATA デバイスアクセスフレームワーク。`sys/cam/` で定義
- **バッファキャッシュ / ページキャッシュ**: `sys/kern/vfs_bio.c`, `sys/vm/` で管理

### 6.4 ユーティリティ/共通機能

| 機能 | ファイル | 説明 |
|------|---------|------|
| キューマクロ | `sys/sys/queue.h` | SLIST, LIST, STAILQ, TAILQ マクロ |
| sbuf (安全な文字列バッファ) | `sys/kern/subr_sbuf.c` | 動的文字列構築 |
| sysctl | `sys/kern/kern_sysctl.c` | ランタイムカーネルパラメータ |
| taskqueue | `sys/kern/subr_taskqueue.c` | 遅延実行タスクキュー |
| eventhandler | `sys/kern/subr_eventhandler.c` | イベント通知機構 |
| mbuf | `sys/kern/uipc_mbuf.c` | ネットワークバッファ管理 |
| uma (Universal Memory Allocator) | `sys/vm/uma_core.c` | スラブアロケータ |

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| SYSINIT 登録 | カーネルサブシステム初期化の宣言 | 高 | `sys/kern/` 全般 |
| デバイスドライバ構造 | probe/attach/detach パターン | 高 | `sys/dev/` 全般 |
| ロック取得/解放 | mutex/sx/rwlock の acquire/release | 高 | カーネルコード全般 |
| SYSCTL 登録 | ランタイムパラメータの宣言 | 高 | カーネルコード全般 |
| goto によるエラーハンドリング | リソース解放を伴うエラー処理 | 高 | カーネルコード全般 |
| MALLOC_DECLARE / MALLOC_DEFINE | メモリタイプの宣言と定義 | 中 | カーネルドライバ全般 |
| queue.h マクロ | リンクリスト操作 | 高 | カーネルコード全般 |
| 条件コンパイル (#ifdef) | オプション機能の条件付きコンパイル | 高 | カーネルコード全般 |

### 各パターンの詳細

#### パターン1: SYSINIT 登録

**目的:** カーネルの初期化順序を宣言的に管理する。

**実装例:**
```c
// ファイル: sys/kern/init_main.c:162
SET_DECLARE(sysinit_set, struct sysinit);
```

`SYSINIT(uniquifier, subsystem, order, func, ident)` マクロで初期化関数を登録すると、`mi_startup()` が起動時にサブシステム番号順にすべての初期化関数を呼び出します。

**解説:** リンカセットを利用しているため、各ファイルが独立して初期化関数を登録でき、明示的な呼び出し元の修正が不要です。

#### パターン2: デバイスドライバ構造 (newbus)

**目的:** ハードウェアデバイスの統一的な検出・初期化・管理。

**実装例:**
```c
// ファイル: sys/dev/ahci/ahci.c:53-79（プロトタイプ宣言部分）
static void ahci_intr(void *data);
static int ahci_ch_init(device_t dev);
static int ahci_ch_deinit(device_t dev);
static int ahci_ch_suspend(device_t dev);
static int ahci_ch_resume(device_t dev);
```

**解説:** ドライバは以下のライフサイクルメソッドを実装します:
1. `probe()` -- デバイスの存在確認
2. `attach()` -- デバイスの初期化とリソース割り当て
3. `detach()` -- リソース解放
4. `suspend()` / `resume()` -- 電源管理

#### パターン3: 条件コンパイル (#ifdef)

**目的:** カーネルコンフィグに基づいてオプション機能を選択的にコンパイルする。

**実装例:**
```c
// ファイル: sys/kern/init_main.c:44-47
#include "opt_ddb.h"
#include "opt_kdb.h"
#include "opt_init_path.h"
#include "opt_verbose_sysinit.h"
```

```c
// ファイル: sys/kern/init_main.c:142-155
#ifdef VERBOSE_SYSINIT
int verbose_sysinit = VERBOSE_SYSINIT;
#endif

#ifdef INVARIANTS
FEATURE(invariants, "Kernel compiled with INVARIANTS, may affect performance");
#endif
```

**解説:** `opt_*.h` ファイルはカーネルコンフィグ (`sys/conf/options`) から `config(8)` によって自動生成されます。`#ifdef` / `#ifndef` で囲まれたコードは、該当オプションが有効な場合のみコンパイルされます。

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイントを特定（システムコール、割り込み、初期化パス等）
2. 処理の流れを追跡（関数呼び出し、VFS/ドライバ層のディスパッチ）
3. データの変換を確認（ユーザ空間/カーネル空間のコピー、mbuf変換等）
4. 最終的な出力を確認（デバイスI/O、ネットワーク送信等）

### 8.2 フロー追跡の実例

#### 例1: カーネル起動シーケンス

**概要:** カーネルがブートローダから制御を受けた後、`mi_startup()` によりサブシステムが順次初期化される流れ。

**処理フロー:**
```
アーキテクチャ固有エントリ → mi_startup() → SYSINIT順次実行 → init プロセス起動
```

**詳細な追跡:**

1. **mi_startup() でSYSINITリストをソート** (`sys/kern/init_main.c:162-169`)
   ```c
   SET_DECLARE(sysinit_set, struct sysinit);
   static STAILQ_HEAD(sysinitlist, sysinit) sysinit_list;
   ```
   SYSINITのリンカセットからエントリを取り出し、`subsystem` と `order` でソートします。

2. **サブシステムの初期化順序** (`sys/sys/kernel.h:95-179`)
   ```c
   SI_SUB_VM       = 0x1000000,  /* 仮想メモリ */
   SI_SUB_KMEM     = 0x1800000,  /* カーネルメモリ */
   SI_SUB_DRIVERS  = 0x3100000,  /* ドライバ */
   SI_SUB_VFS      = 0x4000000,  /* VFS */
   ```
   この数値順に各初期化関数が呼び出されます。

3. **initプロセスの生成** (`sys/sys/kernel.h:129`)
   ```c
   SI_SUB_CREATE_INIT = 0x2500000,  /* create init process */
   ```
   カーネルの初期化が完了すると、PID 1の`init`プロセスが生成されユーザランドに遷移します。

#### 例2: デバイスドライバの登録と初期化

**概要:** AHCIドライバがカーネルに登録され、デバイスを検出・初期化する流れ。

**処理フロー:**
```
DRIVER_MODULE宣言 → probe() → attach() → 割り込み登録 → デバイス操作可能
```

**詳細な追跡:**

1. **ドライバ宣言** -- `DRIVER_MODULE` マクロでドライバをバスに登録
2. **probe関数** (`sys/dev/ahci/ahci.c`) -- PCI IDを確認しデバイス検出
3. **attach関数** -- リソース（メモリ、IRQ）を確保し、初期化を実行
   ```c
   // ファイル: sys/dev/ahci/ahci.c:57-58
   static int ahci_ch_init(device_t dev);
   static int ahci_ch_deinit(device_t dev);
   ```
4. **割り込み登録** -- `ahci_intr()` を割り込みハンドラとして登録
   ```c
   // ファイル: sys/dev/ahci/ahci.c:54-56
   static void ahci_intr(void *data);
   static void ahci_intr_one(void *data);
   static void ahci_intr_one_edge(void *data);
   ```

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイントを特定したか（mi_startup, main, syscallエントリ等）
- [ ] 呼び出し関係を把握したか（関数ポインタ、VFSオペレーションベクタ等に注意）
- [ ] データの変換ポイントを確認したか（copyin/copyout、mbuf変換等）
- [ ] ロック取得/解放のペアを確認したか
- [ ] エラーハンドリング（gotoパターン）を確認したか
- [ ] 条件コンパイル (#ifdef) の影響を考慮したか

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `README.md` -- プロジェクト概要とディレクトリ構成
2. `sys/sys/kernel.h` -- カーネル初期化順序（SYSINITサブシステム一覧）
3. `sys/conf/NOTES` -- カーネルコンフィグオプション一覧

#### 特定サブシステムを理解したい場合
1. `share/man/man9/` -- 該当APIのmanページ（例: `malloc.9`, `mutex.9`）
2. 該当サブシステムのヘッダファイル（`sys/sys/` 配下）
3. 該当サブシステムの実装ファイル（`sys/kern/` 等）

#### デバイスドライバを開発/理解したい場合
1. `share/man/man9/` -- ドライバAPI（`device.9`, `bus.9`）
2. `sys/dev/` 配下の既存ドライバ（参考実装として）
3. `sys/conf/files` -- カーネルビルドへのファイル登録方法

#### 改修作業を行う場合
1. 対象機能のmanページ（Section 2: システムコール、Section 9: カーネルAPI）
2. 該当ソースファイルのヘッダコメント
3. `tests/` 配下の関連テスト

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| `README.md` | プロジェクト概要・ディレクトリ構成 | 最初に読む |
| `CONTRIBUTING.md` | コントリビューションガイド | 変更を加える前に |
| `UPDATING` | アップグレード時の注意事項 | バージョン更新時 |
| `RELNOTES` | リリースノート | バージョン確認時 |
| `sys/conf/NOTES` | カーネルコンフィグオプション一覧 | カーネル設定時 |
| `sys/conf/options` | カーネルオプション定義 | カーネル設定時 |
| `share/man/man9/` | カーネルAPIリファレンス（malloc, mutex等） | API仕様確認時 |
| `share/man/man2/` | システムコールリファレンス | システムコール確認時 |
| `share/man/man4/` | デバイスドライバリファレンス | デバイス仕様確認時 |
| FreeBSD Handbook (外部) | 公式ハンドブック | 全般的な学習 |
| FreeBSD Architecture Handbook (外部) | カーネルアーキテクチャ詳細 | 深い理解が必要な時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: `opt_*.h` ファイルが見つからないが、`#include` されている
A: `opt_*.h` はカーネルビルド時に `sys/conf/options` ファイルの定義に基づいて自動生成されます。ソースツリーには存在しません。`sys/conf/options` と各アーキテクチャの `options.*` ファイルでオプション名を確認できます。

#### Q: 関数ポインタ経由の呼び出しで追跡が困難
A: FreeBSDカーネルでは関数ポインタテーブル（VFS ops, デバイスメソッド等）が多用されます。以下の手順で追跡してください:
1. ポインタが格納される構造体の型を特定
2. その型の定義ファイルで関数ポインタのフィールド名を確認
3. `grep` で該当フィールドへの代入箇所を検索

#### Q: `_if.m` ファイルとは何か
A: `sys/kern/` 配下の `*_if.m` ファイルは、デバイスインタフェースの定義に使用されるM4風のテンプレートです。ビルド時に `device_if.h` などのCヘッダとスタブ関数に変換されます。`bus_if.m`, `device_if.m` が代表例です。

#### Q: `__unused` / `__dead2` などのアトリビュートの意味
A: FreeBSD固有のコンパイラアトリビュートマクロです:
- `__unused`: 意図的に未使用であることを示す（警告抑制）
- `__dead2`: この関数は戻らないことを示す（`__attribute__((noreturn))` 相当）
- `__aligned(n)`: nバイトアラインメントを指定

### デバッグのヒント

- **DDB (in-kernel debugger)**: `opt_ddb.h` が有効なカーネルではカーネルデバッガが利用可能
- **KTR (Kernel Trace)**: `opt_ktr.h` でカーネルトレースを有効化
- **DTrace**: `cddl/contrib/dtrace` にDTraceの実装があり、動的トレーシングが可能
- **INVARIANTS**: カーネルコンフィグで `INVARIANTS` を有効にすると、アサーションチェックが有効化される（`sys/kern/init_main.c:153-155` 参照）
- **WITNESS**: ロック順序の検証機構。デッドロック検出に有用

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| KLD | Kernel Loadable Module。動的にロード/アンロード可能なカーネルモジュール |
| newbus | FreeBSDのデバイスドライバフレームワーク。バス階層構造でデバイスを管理 |
| SYSINIT | カーネルサブシステムの初期化順序を管理するフレームワーク |
| VFS | Virtual File System。ファイルシステムの抽象化層 |
| UMA | Universal Memory Allocator。FreeBSDのスラブアロケータ |
| GEOM | ストレージ変換フレームワーク。ディスクI/Oパイプラインを構築 |
| CAM | Common Access Method。SCSI/ATAデバイスアクセスフレームワーク |
| mbuf | ネットワークバッファの基本データ構造 |
| sysctl | カーネルパラメータの実行時読み書きインタフェース |
| DDB | in-kernel debugger。カーネルパニック時のデバッグ用 |
| pmap | Physical Map。仮想アドレスから物理アドレスへのマッピング管理 |
| epoch | RCU類似の読み取り側ロックフリー同期機構 |
| jail | FreeBSDのOSレベル仮想化機構（コンテナ類似） |
| vnet | 仮想ネットワークスタック。ネットワーク名前空間の分離 |
| DTrace | 動的トレーシングフレームワーク（CDDLライセンス） |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `sys/kern/init_main.c` | カーネル起動・初期化 | mi_startup(), proc0, thread0 |
| `sys/kern/kern_proc.c` | プロセス管理 | プロセス構造体操作 |
| `sys/kern/kern_malloc.c` | カーネルメモリアロケータ | malloc(9)/free(9) 実装 |
| `sys/sys/kernel.h` | カーネル定義 | SYSINIT列挙型、グローバル変数 |
| `sys/sys/proc.h` | プロセス構造体 | struct proc, struct thread |
| `sys/sys/param.h` | システムパラメータ | FreeBSDバージョン、基本定数 |
| `sys/sys/queue.h` | キューマクロ | SLIST, LIST, STAILQ, TAILQ |
| `sys/conf/files` | カーネルソースファイル一覧 | ビルド対象ファイルの登録 |
| `sys/conf/options` | カーネルオプション定義 | opt_*.h 生成元 |
| `sys/dev/ahci/ahci.c` | AHCIドライバ実装例 | 典型的なデバイスドライバ構造 |
| `sys/net/if.c` | ネットワークインタフェース | インタフェース管理の中核 |
| `Makefile` | トップレベルビルド | buildworld, buildkernel 等 |
| `Makefile.inc1` | ビルドシステムの中核 | ビルドステージの定義 |

### C. 参考資料

- [FreeBSD公式ハンドブック](https://docs.freebsd.org/en/books/handbook/)
- [FreeBSD Architecture Handbook](https://docs.freebsd.org/en/books/arch-handbook/) -- カーネル内部構造の詳細
- [FreeBSD Developer's Handbook](https://docs.freebsd.org/en/books/developers-handbook/) -- 開発者向けガイド
- [FreeBSD Manual Pages](https://man.freebsd.org/) -- オンラインmanページ
- [FreeBSD Porter's Handbook](https://docs.freebsd.org/en/books/porters-handbook/) -- portsシステム
- [The Design and Implementation of the FreeBSD Operating System](https://www.informit.com/store/design-and-implementation-of-the-freebsd-operating-9780321968975) -- Kirk McKusick他著、FreeBSD OS設計の教科書
- `style(9)` manpage -- FreeBSDカーネルコーディングスタイルガイド
