# 機能設計書 5-タイマー・クロック管理

## 概要

本ドキュメントは、FreeBSDカーネルにおけるタイマー・クロック管理機能の設計を記述する。システムクロック、タイマー割り込み、時刻管理、イベントタイマー、およびフィードフォワードクロックを対象とする。

### 本機能の処理概要

**業務上の目的・背景**：正確な時刻管理はオペレーティングシステムの基盤機能であり、プロセススケジューリング、タイムアウト処理、ファイルタイムスタンプ、ネットワークプロトコル（TCP再送タイマー等）、ユーザ空間のtimer API等すべてに不可欠である。

**機能の利用シーン**：プロセスCPU時間の計測、calloutタイマーの発火、NTPによる時刻同期、アプリケーションのsleep/nanosleep、cronジョブのスケジューリング、ネットワークプロトコルのタイムアウト処理で利用される。

**主要な処理内容**：
1. **hardclock**: ハードウェアタイマー割り込みによる定期的なシステムクロック更新。プロセスCPU時間計測、calloutタイマー処理、スケジューラへのtick通知を行う。
2. **statclock**: 統計的クロック。プロセスのCPU使用率統計情報の収集に使用される。
3. **イベントタイマー（ET）**: kern_et.cによるハードウェアイベントタイマーの抽象化層。ワンショット・周期タイマーを提供する。
4. **クロックソース管理**: kern_clocksource.cによるシステムクロックソースの選択・管理。timecounterフレームワークとの統合。
5. **フィードフォワードクロック**: kern_ffclock.cによる高精度時刻同期機構。RADclockアルゴリズムのサポート。

**関連システム・外部連携**：スケジューラ（sched_ule.c）、calloutサブシステム、NTPデーモン（ntpd）、タイムゾーン設定（tzsetup）、DTraceプロファイルプロバイダとの連携。

**権限による制御**：settimeofday()やclock_settime()によるシステム時刻変更にはスーパーユーザ権限が必要。NTP adjtime()も同様。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 22 | タイムゾーン選択画面 | 主機能 | tzsetupによるタイムゾーンの選択・/etc/localtime設定 |
| 23 | 日付設定画面 | 主機能 | カレンダーUIによる日付選択・dateコマンドでのシステム日付設定 |
| 24 | 時刻設定画面 | 主機能 | 時刻入力UIによる時刻選択・dateコマンドでのシステム時刻設定 |
| 30 | 最終設定メニュー画面 | 遷移先機能 | Time Zone選択時のタイムゾーン設定画面への遷移 |

## 機能種別

カーネル基盤機能（時刻管理・タイマー割り込み処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| clock_settime_args.clock_id | clockid_t | Yes | クロック種別（CLOCK_REALTIME等） | 有効なclockid |
| clock_settime_args.tp | struct timespec * | Yes | 設定する時刻 | 有効な時刻値 |
| nanosleep_args.rqtp | struct timespec * | Yes | スリープ時間 | 非負の値 |
| setitimer_args.which | int | Yes | タイマー種別（ITIMER_REAL等） | 有効なタイマー種別 |

### 入力データソース

ハードウェアタイマー割り込み、システムコール（clock_gettime, clock_settime, nanosleep, setitimer等）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| clock_gettime戻り値 | struct timespec | 現在時刻 |
| gettimeofday戻り値 | struct timeval | 現在時刻（マイクロ秒精度） |

### 出力先

ユーザ空間への時刻値返却、カーネル内部の時刻変数更新。

## 処理フロー

### 処理シーケンス

```
1. hardclock処理（タイマー割り込み毎）
   ├─ hardclock_itimer(): プロセスインターバルタイマー処理
   ├─ callout_process(): calloutタイマーの発火チェック
   ├─ tc_windup(): timecounter更新
   └─ sched_clock(): スケジューラへのtick通知

2. statclock処理（統計クロック割り込み毎）
   ├─ CPU使用率統計の更新
   └─ プロファイリングデータの収集

3. イベントタイマー設定
   ├─ et_init(): タイマーハードウェアの初期化
   ├─ et_start(): タイマー開始
   └─ et_stop(): タイマー停止
```

### フローチャート

```mermaid
flowchart TD
    A[ハードウェアタイマー割り込み] --> B[hardclock]
    B --> C[hardclock_itimer: プロセスタイマー]
    B --> D[callout_process: calloutチェック]
    B --> E[tc_windup: timecounter更新]
    B --> F[sched_clock: スケジューラ通知]

    G[統計タイマー割り込み] --> H[statclock]
    H --> I[CPU使用率更新]
    H --> J[プロファイル記録]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 時刻単調増加 | CLOCK_MONOTONICは決して後退しない | clock_gettime(CLOCK_MONOTONIC)時 |
| BR-02 | NTP調整 | adjtime()による緩やかな時刻調整（ステッピングの回避） | NTPd動作時 |
| BR-03 | timecounter精度 | 最も精度の高いハードウェアカウンタを自動選択 | システム起動時 |
| BR-04 | SIGALRM配送 | ITIMER_REAL満了時にSIGALRMを配送 | setitimer設定時 |

### 計算ロジック

hardclock_itimer()（450行目）ではプロセスのインターバルタイマーをデクリメントし、0到達時にSIGALRM/SIGVTALRM/SIGPROFを配送する。statclock()（685行目）ではプロセスのユーザ/カーネルCPU時間をrusage構造体に累積する。

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

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

| 操作 | 対象データ構造 | 操作種別 | 概要 |
|-----|-------------|---------|------|
| hardclock | timecounter | UPDATE | システム時刻の更新 |
| statclock | rusage | UPDATE | CPU使用率統計の更新 |
| settimeofday | time_second | UPDATE | システム時刻の設定 |

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

#### timecounter

| 操作 | 項目（フィールド名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| UPDATE | tc_offset_count | ハードウェアカウンタ値 | tc_windup()で更新 |
| UPDATE | tc_offset_sec/nsec | 秒/ナノ秒オフセット | 割り込み毎に更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| EINVAL | 引数不正 | 無効なclock_id指定 | 有効なクロックIDを使用 |
| EPERM | 権限不足 | 非rootによる時刻設定 | root権限で実行 |
| EFAULT | 不正アドレス | timespec構造体のcopyin失敗 | 正しいポインタを渡す |

### リトライ仕様

タイマー割り込み処理はハードウェアにより保証される。ソフトウェアタイマー（callout）の遅延発火はbestなeffortで処理される。

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

timecounter更新はtc_windup()内でシーケンス番号を用いたロックフリーな読み取りを実現している（seqclock）。hardclock/statclockは割り込みコンテキストで実行されるため、通常のmutexではなくスピンロックを使用する。

## パフォーマンス要件

- hardclock: HZの頻度で実行（デフォルト1000Hz）
- timecounter読み取り: ロックフリーのナノ秒精度
- nanosleep精度: イベントタイマーの分解能に依存

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

- 時刻設定はsecurelevelおよびpriv_check()で制御
- NTP認証によるなりすまし防止
- タイムスタンプの一貫性はファイルシステム・ログ・監査に影響

## 備考

- FreeBSDのデフォルトtick rateはHZ=1000（1ms間隔）
- kern_clock.cの477行目にhardclock()が、685行目にstatclock()が定義されている
- kern_et.cは263行のコンパクトなファイルで、イベントタイマーの抽象化を提供
- kern_clocksource.cは984行でクロックソース管理を実装

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | time.h | `sys/sys/time.h` | struct timeval、struct timecounter等の時刻関連構造体 |
| 1-2 | timers.h | `sys/sys/timers.h` | POSIXタイマー関連の構造体定義 |
| 1-3 | eventtimer.h | `sys/sys/eventtimer.h` | struct eventtimer定義。イベントタイマー抽象化 |

**読解のコツ**: FreeBSDの時刻管理は「timecounter」（ハードウェアカウンタ抽象化）と「eventtimer」（タイマー割り込み抽象化）の二本柱で構成される。timecounterは時刻の読み取り、eventtimerは割り込みの発生を担当する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | kern_clock.c | `sys/kern/kern_clock.c` | hardclock()（477行目）とstatclock()（685行目）がタイマー割り込みハンドラ |

**主要処理フロー**:
1. **450行目**: hardclock_itimer()でプロセスインターバルタイマーの処理
2. **477行目**: hardclock()メイン処理。tc_windup()でtimecounter更新
3. **542行目**: hardclock_sync()でCPU間のクロック同期
4. **685行目**: statclock()でCPU使用率統計の更新

#### Step 3: イベントタイマーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | kern_et.c | `sys/kern/kern_et.c` | イベントタイマーの登録・管理（263行） |
| 3-2 | kern_clocksource.c | `sys/kern/kern_clocksource.c` | クロックソースの選択・管理（984行） |

#### Step 4: フィードフォワードクロックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | kern_ffclock.c | `sys/kern/kern_ffclock.c` | RADclockベースの高精度時刻同期 |

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

```
ハードウェアタイマー割り込み
    |
    +-- hardclock()
    |       +-- hardclock_itimer() [プロセスタイマー]
    |       +-- tc_windup() [timecounter更新]
    |       +-- callout_process() [callout発火]
    |       +-- sched_clock() [スケジューラ通知]
    |
    +-- statclock()
            +-- rusage更新 [CPU統計]

clock_gettime() [システムコール]
    |
    +-- kern_clock_gettime()
            +-- binuptime() [timecounter読み取り]

clock_settime() [システムコール]
    |
    +-- kern_clock_settime()
            +-- tc_setclock() [時刻設定]
```

### データフロー図

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

HWタイマー割込 ────> hardclock() ──────────────────> timecounter更新
                                                       callout発火

clock_gettime() ──> binuptime() ──────────────────> struct timespec
                    timecounter読取

NTP adjtime() ────> tc_adjtime() ─────────────────> 時刻微調整
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| kern_clock.c | `sys/kern/kern_clock.c` | ソース | hardclock/statclock実装（841行） |
| kern_clocksource.c | `sys/kern/kern_clocksource.c` | ソース | クロックソース管理（984行） |
| kern_et.c | `sys/kern/kern_et.c` | ソース | イベントタイマー抽象化（263行） |
| kern_ffclock.c | `sys/kern/kern_ffclock.c` | ソース | フィードフォワードクロック |
| kern_tc.c | `sys/kern/kern_tc.c` | ソース | timecounterフレームワーク |
| kern_time.c | `sys/kern/kern_time.c` | ソース | 時刻関連システムコール |
| kern_timeout.c | `sys/kern/kern_timeout.c` | ソース | calloutタイマーフレームワーク |
| time.h | `sys/sys/time.h` | ヘッダ | 時刻関連構造体定義 |
| eventtimer.h | `sys/sys/eventtimer.h` | ヘッダ | イベントタイマー定義 |
