# 機能設計書 91-タスクスケジューラ

## 概要

本ドキュメントは、Julia言語ランタイムにおけるタスクスケジューラ機能の設計を記述する。タスクスケジューラは、複数のワーカースレッド間でJuliaタスク（軽量コルーチン）を効率的にスケジューリングし、実行を管理するランタイムの中核機能である。

### 本機能の処理概要

**業務上の目的・背景**：Juliaは対称コルーチン方式の軽量タスク（グリーンスレッド）を採用しており、ユーザが`@spawn`や`@async`で生成したタスクをOSスレッド上に効率的にマッピングする必要がある。タスクスケジューラは、スレッドの起床・休眠を管理し、ワークスティーリングによるタスク分配を実現することで、並列処理の性能を最大化する。

**機能の利用シーン**：Juliaプログラムにおいてマルチスレッド並列処理が行われる際に、全てのタスクスケジューリングがこの機能を通じて実施される。REPL起動時のワーカースレッド初期化、`Threads.@spawn`によるタスク生成時のスレッド割り当て、I/Oイベントループとの協調動作などが代表的な利用シーンである。

**主要な処理内容**：
1. スレッドの初期化とスケジューラインフラストラクチャのセットアップ
2. タスクキューからの次実行タスク取得（`jl_task_get_next`）
3. スレッドの休眠判定と休眠状態への遷移（sleep threshold管理）
4. 休眠スレッドの起床処理（`wakeup_thread`）
5. libuvイベントループとの協調（I/Oスレッド管理）
6. スレッドの削除処理（`scheduler_delete_thread`）

**関連システム・外部連携**：libuvイベントループとの協調動作、GCセーフポイント機構との連携、シグナル処理機構との連携が存在する。

**権限による制御**：特にロール・権限による制御はないが、スレッド0（メインスレッド）はI/Oイベントループの処理において特別な役割を持ち、`io_loop_tid`で管理される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ランタイム内部機能のため関連画面なし |

## 機能種別

ランタイムスケジューリング / スレッド管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| trypoptask | jl_value_t* | Yes | タスクキューからタスクを取得するJulia関数 | NULLでないこと |
| q | jl_value_t* | Yes | タスクキューオブジェクト | NULLでないこと |
| checkempty | jl_value_t* | Yes | キューが空かどうかを確認するJulia関数 | NULLでないこと |
| JULIA_THREAD_SLEEP_THRESHOLD | 環境変数 | No | スレッド休眠閾値（ナノ秒） | 数値または"infinite" |

### 入力データソース

- Juliaタスクキュー（Julia側の`Base.Workqueue`など）
- 環境変数`JULIA_THREAD_SLEEP_THRESHOLD`
- libuvイベントループの状態

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 次実行タスク | jl_task_t* | スケジューリングされた次のタスク |
| スレッド状態 | int8_t | not_sleeping(0), sleeping(1), sleeping_like_the_dead(2) |

### 出力先

内部的にタスク実行コンテキストの切り替えとして出力される。

## 処理フロー

### 処理シーケンス

```
1. スレッド初期化（jl_init_threadinginfra）
   └─ sleep_thresholdの設定、環境変数からの読み込み
2. スレッドスケジューラの初期化（jl_init_thread_scheduler）
   └─ sleep_lock, wake_signalの初期化、n_threads_runningのインクリメント
3. タスク取得ループ（jl_task_get_next）
   ├─ get_next_task: キューからタスクをポップ
   ├─ check_empty: キューが空かチェック
   ├─ sleep_check_after_threshold: 閾値超過でスリープ判定
   ├─ libuvイベントループの処理（UV_RUN_ONCE）
   └─ スリープ/ウェイクアップ遷移
4. スレッド起床（wakeup_thread）
   └─ sleep_check_stateの遷移とcond_signal
5. スレッド削除（scheduler_delete_thread）
   └─ sleeping_like_the_deadへの遷移とクリーンアップ
```

### フローチャート

```mermaid
flowchart TD
    A[jl_task_get_next開始] --> B[get_next_task]
    B -->|タスクあり| C[タスクを返却]
    B -->|タスクなし| D[check_empty]
    D -->|空でない| B
    D -->|空| E{sleep_check_after_threshold}
    E -->|閾値未満| F[jl_process_events]
    F --> B
    E -->|閾値超過| G[sleep_check_stateをsleepingに設定]
    G --> H[再度check_empty]
    H -->|空でない| I[set_not_sleeping]
    I --> B
    H -->|空| J{uvlockを取得可能か}
    J -->|Yes| K[uv_run UV_RUN_ONCE]
    K --> L{active or !may_sleep}
    L -->|Yes| I
    L -->|No| M[n_threads_running-1]
    M --> N[wake_signalで待機]
    N --> B
    J -->|No| O[thread0を起床]
    O --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-91-01 | スリープ閾値 | デフォルト閾値を超過した場合にスレッドをスリープ遷移させる | タスクキューが空のとき |
| BR-91-02 | I/Oスレッド特権 | threadedregion外ではスレッド0のみがI/Oイベントループを処理する | _threadedregionが0のとき |
| BR-91-03 | ストアバッファリング対策 | sleep状態遷移とキュー確認の間にsequentially-consistentフェンスを挿入する | スリープ/ウェイクアップ遷移時 |
| BR-91-04 | 最終スレッド通知 | 最後の実行スレッドがスリープする際にスレッド0を通知する | n_threads_running==1のとき |

### 計算ロジック

- `sleep_check_after_threshold`: `jl_hrtime() - start_cycles >= sleep_threshold`で閾値判定
- rr（record-and-replay）デバッガ下では即座にスリープ許可を返す

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

該当なし（ランタイム内部機能のためデータベース操作なし）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | SIGINT例外 | スリープ中にSIGINTを受信 | JL_CATCHブロックでn_threads_runningを復元しrethrow |
| - | タスク取得エラー | trypoptask関数が例外を投げた場合 | JL_CATCHブロックで状態を復元しrethrow |

### リトライ仕様

タスク取得は無限ループで再試行される。スリープ後の起床はcondition variableのシグナルにより行われ、自動的にリトライされる。

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

該当なし

## パフォーマンス要件

- スリープ閾値のデフォルト値は`DEFAULT_THREAD_SLEEP_THRESHOLD`で定義（環境変数で上書き可能）
- スレッドの起床レイテンシを最小化するため、`uv_cond_signal`を使用
- ビジーウェイト期間中は`jl_cpu_pause()`でCPU資源を節約

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

ランタイム内部機能であり、外部からの直接アクセスはない。アトミック操作とミューテックスによりスレッドセーフ性が保証される。

## 備考

- `JULIA_DEBUG_SLEEPWAKE`マクロが定義されている場合、各ステップでサイクルカウンタが記録されデバッグ用に利用可能
- DTrace/SystemTapプローブ（JL_PROBE_RT_SLEEP_CHECK_*）が各状態遷移に埋め込まれている

---

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

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

### 推奨読解順序

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

タスクとスレッドの状態を管理するデータ構造を把握することが最優先である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | julia_threads.h | `src/julia_threads.h` | jl_ptls_tの定義（sleep_check_state, sleep_lock, wake_signalフィールド） |
| 1-2 | julia_internal.h | `src/julia_internal.h` | n_threads_running, sleep_thresholdなどのグローバル変数宣言 |

**読解のコツ**: `jl_ptls_t`は「per-thread local state」の略で、各スレッドが固有に持つ状態構造体である。`sleep_check_state`の3つの状態（not_sleeping=0, sleeping=1, sleeping_like_the_dead=2）を理解することが鍵となる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | scheduler.c | `src/scheduler.c` | jl_task_get_next関数（365行目）が中核のスケジューリングループ |

**主要処理フロー**:
1. **365-373行目**: `jl_task_get_next`のメインループ開始、`get_next_task`でキューからタスク取得
2. **384-395行目**: スリープ閾値チェックと`sleep_check_state`の`sleeping`への遷移
3. **428-483行目**: libuvイベントループとの協調処理
4. **487-530行目**: スレッドのスリープ処理（`wake_signal`で待機）

#### Step 3: スレッド起床処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | scheduler.c | `src/scheduler.c` | wakeup_thread関数（243行目）とwake_thread関数（216行目） |

**主要処理フロー**:
- **216-233行目**: `wake_thread` - atomic CASでsleep_check_stateをnot_sleepingに遷移し`uv_cond_signal`で起床
- **243-296行目**: `wakeup_thread` - 自スレッドの場合はuv_stop、他スレッドの場合はwake_threadを呼び出し

#### Step 4: スレッド初期化と削除を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | scheduler.c | `src/scheduler.c` | jl_init_threadinginfra（85行目）、jl_init_thread_scheduler（127行目） |
| 4-2 | scheduler.c | `src/scheduler.c` | scheduler_delete_thread（554行目） |

**主要処理フロー**:
- **85-96行目**: sleep_thresholdの初期化（環境変数対応）
- **127-138行目**: スレッドごとのsleep_lock/wake_signal初期化
- **554-573行目**: スレッド削除時のsleeping_like_the_dead遷移

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

```
jl_task_get_next (scheduler.c:365)
    |
    +-- get_next_task (scheduler.c:306)
    |       +-- jl_gc_safepoint()
    |       +-- jl_apply_generic(trypoptask, ...)
    |       +-- jl_set_task_tid()
    |
    +-- check_empty (scheduler.c:318)
    |       +-- jl_apply_generic(checkempty, ...)
    |
    +-- sleep_check_after_threshold (scheduler.c:166)
    |       +-- jl_hrtime()
    |       +-- jl_running_under_rr()
    |
    +-- may_sleep (scheduler.c:354)
    |
    +-- wakeup_thread (scheduler.c:243)
    |       +-- wake_thread (scheduler.c:216)
    |       |       +-- uv_cond_signal()
    |       +-- wake_libuv (scheduler.c:236)
    |               +-- jl_wake_libuv()
    |
    +-- jl_safepoint_take_sleep_lock (safepoint.c:301)
    |
    +-- uv_run(loop, UV_RUN_ONCE)

jl_init_threadinginfra (scheduler.c:85)
    +-- getenv(THREAD_SLEEP_THRESHOLD_NAME)

jl_init_thread_scheduler (scheduler.c:127)
    +-- uv_mutex_init()
    +-- uv_cond_init()

scheduler_delete_thread (scheduler.c:554)
    +-- wakeup_thread()
```

### データフロー図

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

Juliaタスクキュー ──────> jl_task_get_next ──────────────> 次実行タスク(jl_task_t*)
                             |
環境変数                     |
JULIA_THREAD_SLEEP_THRESHOLD > sleep_threshold設定
                             |
libuvイベントループ ────────> uv_run(UV_RUN_ONCE) ────────> I/Oイベント処理結果
                             |
wake_signal(他スレッド) ──> uv_cond_wait/signal ─────────> スレッド状態遷移
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| scheduler.c | `src/scheduler.c` | ソース | タスクスケジューラの中核実装 |
| task.c | `src/task.c` | ソース | タスク（軽量プロセス）の実装、コンテキストスイッチ |
| threading.c | `src/threading.c` | ソース | スレッド管理の基盤実装 |
| threading.h | `src/threading.h` | ヘッダ | スレッド関連の定義と宣言 |
| julia_threads.h | `src/julia_threads.h` | ヘッダ | jl_ptls_tなどスレッド状態構造体の定義 |
| julia_internal.h | `src/julia_internal.h` | ヘッダ | 内部関数・変数の宣言 |
| safepoint.c | `src/safepoint.c` | ソース | jl_safepoint_take_sleep_lockなどセーフポイント連携 |
| partr.jl | `base/partr.jl` | ソース | Julia側のスケジューラインターフェース |
