openSUSE® Leap のような現代型のオペレーティングシステムでは、通常の状態でも複数の処理を同時に動作させることができます。たとえばテキストファイル内を検索しながら、同時に電子メールを受信し、さらに外付けのハードディスクから巨大なファイルをコピーしたりすることができます。また、これらのようなシンプルな処理であっても、システム内では様々な追加のプロセスが動作します。それぞれの処理に対して必要なリソースを提供するため、 Linux カーネルではツールを利用して、個別の処理にリソースを配分することができます。これが タスクスケジューラ の仕組みです。
下記の章では、プロセスのスケジューリングに関する最も重要な用語について説明しているほか、 openSUSE Leap で使用されているタスクスケジューラのポリシーやスケジューリングのアルゴリズム、タスクスケジューラに関する説明なども提供しています。また、関連する情報源へのリンクも用意されています。
Linux カーネルは、システム内で管理されているタスク (もしくはプロセス) の管理方法を制御します。タスクスケジューラは プロセススケジューラ と呼ばれることもありますが、これは次に動作させるタスクを決定するカーネル内の構成部品を指します。複数のタスクが同時に実行できることを保証するため、システムのリソースを最適に使用する責任を負っています。このような構造により、タスクスケジューラはマルチタスク型のオペレーティングシステムの中枢を成しています。
タスクスケジューリングでの考え方はシンプルです。システム内に動作可能なプロセスが存在すれば、それらのうちの少なくとも 1 つを動作させます。また、プロセッサ数よりも多く動作可能なプロセスが存在した場合、同時にそれら全てを動作させることはできません。
そのため、プロセスによっては一時的に停止させる (サスペンドさせる) 必要があることになり、後で実行させる必要があることになります。タスクスケジューラは、キュー内にあるどのプロセスを次に実行させるのかを決定します。
上述のとおり、他の Unix 系オペレーティングシステムと同様に、 Linux は マルチタスク型の (複数のタスクを同時に動作させることのできる) オペレーティングシステムです。 Linux は プリエンプティブ マルチタスクと呼ばれる構造で、スケジューラ側でプロセスの一時停止を決定します。このような強制的な一時停止を プリエンプション (横取り等の意味) と呼びます。全ての Unix 系オペレーティングシステムは、その登場当初からプリエンプティブマルチタスクを提供しています。
それぞれのプロセスに対して与えられる時間枠で、その時間が経過するまではタスクスケジューラ側から一時停止を指示されない、最小単位の時間を指します。タイムスライスとは、各プロセスに対して提供されるプロセッサ時間の量を表す値でもあります。タイムスライスを割り当てておくことで、タスクスケジューラは動作中のシステムに対して大まかに決定を下しながら、かつプロセスがプロセッサを占有しないようにすることができます。
スケジューラは各プロセスに割り当てられた優先順位を元にして判断を行います。プロセスの現在の優先順位を計算するにあたって、タスクスケジューラは複雑なアルゴリズムを使用します。その結果、各プロセスにはプロセッサの能力に応じた実行の 「許可」 が与えられます。
プロセスは目的や振る舞いに応じて分類されます。明確な区切りがあるとは限りませんが、一般的には 2 種類の分類が行われます。これらの基準はそれぞれ個別に判断されるべきもので、お互いに排他関係にあるわけではありません。
1 つの考え方として、 I/O バウンド と プロセッサバウンド に分類するやり方があります。
I/O とは入出力の意味で、キーボードやマウス、光学ドライブやハードディスクなどを意味します。 I/O バウンドプロセス とは、リクエストの送受信の待機に多くの時間を費やすプロセスの意味で、非常に頻繁に動作するものの、同様に I/O リクエストを待機している他のプロセスの動作を妨害することがないよう、その動作は短くなります。
プロセッサバウンド のタスクでは、コードの実行に多くの時間を費やし、スケジューラによって一時停止させられるまで動き続けるようなものを指します。 I/O 要求を待機しているようなプロセスの動作を妨害することはありませんが、より長い時間にわたって動作し続ける特徴があります。
もう 1 つの考え方として、プロセスを 対話型, バッチ, リアルタイム の 3 種類に分類するやり方もあります。
対話型 のプロセスでは、キーボードやマウス操作など、 I/O のリクエスト待機に多くの時間を費やします。スケジューラはユーザ側からの要求が届き次第、すぐにこれらのプロセスを起床させなければなりません。そうでないと、ユーザ側にはプログラムの応答が無くなったかのように見えてしまうからです。一般的には 100 [ミリ秒] 程度の許容遅延が設定されます。対話型プロセスには、たとえばオフィスアプリケーションやテキストエディタ、イメージ操作プログラムなどが該当します。
バッチ のプロセスは裏で動作するものであり、応答性については特に求められません。通常はスケジューラ側で低い優先順位が設定されます。バッチプロセスには、マルチメディアデータの変換処理やデータベースの検索エンジン、ログファイルの検索機能などが該当します。
リアルタイム のプロセスは、低い優先順位のプロセスによって動作を妨害されてはならないプロセスで、スケジューラ側では短い応答時間となるように設定されます。リアルタイムプロセスには、マルチメディアコンテンツの編集アプリケーションなどが該当します。
Linux カーネルバージョン 2.6.23 およびそれ以降では、プロセスの実行を制御するスケジューリングに対して新しいアプローチが追加され、完全公平型スケジューラ (Completely Fair Scheduler (CFS)) が既定の Linux カーネルのスケジューラとして設定されるようになりました。それ以降重要な変更や改善が行われていますが、本章での説明は openSUSE Leap のカーネルバージョン 2.6.32 およびそれ以降 (バージョン 3.x を含む) に対応しています。スケジューラ環境は複数のパーツから構成されていますが、主として 3 種類の機能が追加されています:
スケジューラの中枢部分は スケジューリングクラス で拡張されています。これらのクラスはモジュール型で、それぞれがスケジューリングポリシーを表しています。
カーネルバージョン 2.6.23 で追加され、 2.6.24 で拡張された CFS は、プロセッサ時間をプロセッサに対して 「公平に」 分け与える機能をもたらすものです。
たとえばプロセスをユーザごとに分けてグループ化することで、 CFS はユーザ単位で公平なプロセッサ時間を提供するように設定することができます。
これらのことから、 CFS はサーバ環境でもデスクトップ環境でも最適なスケジューリングを提供できるようになっています。
CFS は実行可能なそれぞれのタスクに対して、公平な割り振りを行おうとします。タスクスケジューリングで最も公平なやり方として、 CFS は 赤黒木 の考え方を採用しています。赤黒木は平衡二分探索木の一種で、項目の挿入や削除を合理的な方法で提供し、平衡性を保ったままにすることができるものです。
CFS がタスクをスケジュールする際、 「仮想ランタイム」 もしくは 「vruntime」 と呼ばれる値を足していきます。実行する次のタスクを選択する際には、それまでに足された最小の vruntime のタスクを使用します。タスクが 実行キュー (次に実行すべきプロセスの予定時刻表) 内に挿入された場合、赤黒木は平衡を保つように動作するため、最小の vruntime 値を持つタスクが赤黒木内では最初の項目となるように動きます。
タスクに対して足される vruntime の量は、その優先順位に対応して決められます。高い優先順位のタスクは、低い優先順位のタスクよりも遅い頻度で vruntime が足される仕組みであるため、より高い優先順位のタスクほど、より頻繁に処理が行われることになります。
Linux カーネルバージョン 2.6.24 では、 CFS が個別のタスクよりもグループに対して公平となるよう調整されました。実行可能なタスクはエンティティ (タスクの集合) としてグループ化され、 CFS では個別のタスクではなく、エンティティに対して公平になるように動作するようになっています。なおスケジューラ側では、エンティティ内の個別タスクに対しても、公平になるように処理を行います。
カーネルスケジューラは、コントロールグループを利用して実行可能なタスクをグループ化しています。詳しくは 第10章 「カーネルコントロールグループ」 をお読みください。
タスクスケジューラの基本的な動作に関わる要素は、カーネルの設定オプションを介して設定することができます。これらのオプションの設定は、カーネルのコンパイル時のオプションとして用意されています。カーネルのコンパイル作業は複雑な作業となるため、ここでは説明していません。詳しくは別途の資料をお探しください。
openSUSE Leap に同梱されていないカーネル (たとえばご自身でコンパイルしたカーネル) をお使いの場合、サポートを全く受けられなくなることにご注意ください。
タスクスケジューリングポリシーに関する文書では、いくつかの技術用語を用いる箇所があります。これらの用語の意味を知っておくことで、正しく文書を読み取ることができるようになります。下記にそれらのうちのいくつかを示します:
プロセスに対して実行するようにスケジュールされてから、実際にその実行が行われるまでの遅延時間を意味します。
粒度と遅延の関係は、下記の数式で表すことができます:
gran = ( lat / rtasks ) - ( lat / rtasks / rtasks )
gran は粒度を、 lat は遅延を、 rtasks は実行中のタスク数をそれぞれ表しています。
Linux カーネルは下記のスケジューリングポリシーに対応しています:
特別なタイムクリティカルな (時間的に制約の厳しい) アプリケーション向けのスケジューリングポリシーです。先入れ先出し (First In-First Out; FIFO) のスケジューリングアルゴリズムを使用します。
CPU に負荷が集中するタスク向けに設計されたスケジューリングポリシーです。
非常に 優先順位の低いタスク向けのスケジューリングポリシーです。
ほとんどのプロセスに対して適用される、既定の Linux 時間共有スケジューリングポリシーです。
SCHED_FIFO
に似ていますが、ラウンドロビン型のスケジューリングアルゴリズムを使用するポリシーです。
chrt
によるプロセスのリアルタイム属性の変更 #Edit sourcechrt
コマンドは、実行中のプロセスに対するリアルタイムスケジューリング属性を設定したり取得したりすることができるほか、指定した属性で指定したコマンドを実行することもできます。プロセスのスケジューリングポリシーのほか、優先順位の取得や設定も行うことができます。
下記の例では、 PID が 16244 のプロセスを対象にしています。
既存のタスクからリアルタイム属性を 取得 するには、下記のように入力して実行します:
#
chrt -p 16244
pid 16244's current scheduling policy: SCHED_OTHER
pid 16244's current scheduling priority: 0
プロセスに対して新しいスケジューリングポリシーを設定する前に、まずは各スケジューリングアルゴリズムで設定可能な最小および最大の優先順位を確認しておきます:
#
chrt -m
SCHED_SCHED_OTHER min/max priority : 0/0
SCHED_SCHED_FIFO min/max priority : 1/99
SCHED_SCHED_RR min/max priority : 1/99
SCHED_SCHED_BATCH min/max priority : 0/0
SCHED_SCHED_IDLE min/max priority : 0/0
上記の例では、 SCHED_OTHER, SCHED_BATCH, SCHED_IDLE の各ポリシーに対しては優先順位 0 のみを設定することができ、 SCHED_FIFO, SCHED_RR の各ポリシーに対しては 1 から 99 までを設定することができることを表しています。
SCHED_BATCH スケジューリングポリシーを設定するには、下記のようにします:
#
chrt -b -p 0 16244
pid 16244's current scheduling policy: SCHED_BATCH
pid 16244's current scheduling priority: 0
chrt
に関する詳細については、マニュアルページ ( man 1 chrt
) をお読みください。
sysctl
による稼働中のチューニング #Edit source稼働中にカーネルのパラメータを調査したり変更したりすることのできる sysctl
インターフェイスを利用して変数を変更することで、タスクスケジューラの既定の動作を変更することができます。 sysctl
の書式はシンプルですが、いずれのコマンドとも root
で実行しなければなりません。
カーネル変数の値を表示するには、下記のように入力して実行します:
#
sysctl 変数名
値を設定するには、下記のように入力して実行します:
#
sysctl 変数名=値
スケジューラ関連の変数を全て表示したい場合は sysctl
コマンドを利用し、 grep
で出力をフィルタリングします:
#
sysctl -A | grep "sched" | grep -v "domain"
kernel.sched_cfs_bandwidth_slice_us = 5000 kernel.sched_child_runs_first = 0 kernel.sched_compat_yield = 0 kernel.sched_latency_ns = 24000000 kernel.sched_migration_cost_ns = 500000 kernel.sched_min_granularity_ns = 8000000 kernel.sched_nr_migrate = 32 kernel.sched_rr_timeslice_ms = 25 kernel.sched_rt_period_us = 1000000 kernel.sched_rt_runtime_us = 950000 kernel.sched_schedstats = 0 kernel.sched_shares_window_ns = 10000000 kernel.sched_time_avg_ms = 1000 kernel.sched_tunable_scaling = 1 kernel.sched_wakeup_granularity_ns = 10000000
なお、 「_ns」 や 「_us」 で終わる名前の変数は、値をナノ秒単位やマイクロ秒単位で指定するものであることを示しています。
最も重要なタスクスケジューラ関連の sysctl
チューニング変数 (/proc/sys/kernel/
からもアクセスすることができます) と、その簡潔な説明を下記に示します:
sched_cfs_bandwidth_slice_us
CFS の帯域制御が使用されている場合、このパラメータはタスクのコントロールグループの帯域プールから実行キューに転送されるランタイムの量 (帯域幅) を制御することができます。小さい値であるほど、全体の帯域幅をタスク間できめ細かく共有できるようになりますし、大きい値であるほど、転送にかかるオーバーヘッドを減らすことができます。詳しくは https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt (英語) をお読みください。
sched_child_runs_first
新しく fork された子プロセスは、親プロセスの実行が再開されるよりも早く実行が行われます。このパラメータを 1
にすると、子プロセスが fork 後すぐに処理を始めるような場合に有用となります。
sched_compat_yield
古い O(1) スケジューラに存在していた、放棄タスクを実行可能キューの末尾 (赤黒木で一番右側) に移動させる積極的な CPU の yielding 動作を有効にするかどうかを設定します。 sched_yield(2)
システムコールの動作に依存するアプリケーションでは、競合の激しいリソース (たとえばロックなど) が存在するような場合、他のプロセスに対して実行のチャンスを与えることになることから、性能面での改善をもたらす場合があります。ただし、このシステムコールはコンテキストスイッチによって発生するものであるため、誤って使用してしまうと逆に性能が落ちてしまう場合があります。そのため、性能面での改善が確実である場合にのみ設定してください。既定値は 0
です。
sched_migration_cost_ns
直近の実行が行われたのち、特定のタスクがマイグレーションの決定に際して 「キャッシュホット」 であると判断する時間量を設定します。 「ホット」 なタスクほど、他の CPU にマイグレーション (移行) することが少なくなりますので、この値を増やすことでタスクマイグレーションを少なくすることができます。既定値は 500000
[ナノ秒] です。
実行可能なプロセスが存在しているにもかかわらず、 CPU のアイドル時間が予想よりも長い場合は、この値を小さくすることをお勧めします。逆に、 CPU 間やノード間でのタスクのマイグレーションが過剰である場合、大きくすることをお勧めします。
sched_latency_ns
CPU バウンドのタスクに対して、ターゲットとするプリエンプション遅延を指定します。この値を増やすと、 CPU バウンドのタスクのタイムスライスが長くなります。タスクのタイムスライスは、スケジューリングの間隔と重み付けの設定から、下記のように公平な共有が行われます:
タイムスライス = スケジュール間隔 * (タスクの重み / 実行キュー内にあるタスクの重みの合計)
タスクの重みはタスクの nice レベルとスケジューリングポリシーによって決まります。 SCHED_OTHER の場合、最小のタスクの重みは 15 で、これは nice 値 19 に対応します。最大のタスクの重みは 88761 で、これは nice 値 -20 に対応します。
タイムスライスは負荷が増えるほど小さくなります。実行可能なタスクの数が sched_latency_ns
/ sched_min_granularity_ns
を越えると、タイムスライスは 実行可能なタスクの数 * sched_min_granularity_ns
になります。それより前に、タイムスライスは sched_latency_ns
に等しくなります。
この値は、実行権情報の計算のために、休眠中のタスクが実行中であると見なされる最大の時間幅を指定することにもなります。また、この値を増やすことで、動作中のタスクが消費する可能性のある時間を増やすことになります。そのため、 CPU バウンドのタスクに対しては、スケジューラによる遅延を増やすことになります。既定値は 6000000
[ナノ秒] です。
sched_min_granularity_ns
CPU バウンドのタスクに対するプリエンプションの粒度です。詳しくは sched_latency_ns
をご覧ください。既定値は 4000000
[ナノ秒] です。
sched_wakeup_granularity_ns
起床プリエンプション粒度を表します。この変数の値を増やすと、起床時のプリエンプションを減らし、計算処理が主となるタスクの乱れを減らすことになります。この値を減らすと、起床の遅延を改善することができますので、遅延の回避が重要となるタスクではスループットを改善することができます。特に短いデューティサイクルの負荷コンポーネントが、 CPU バウンドのコンポーネントと確実に競合するような場合に有用です。既定値は 2500000
[ナノ秒] です。
sched_latency_ns
の半分よりも大きな値を設定してしまうと、起床時のプリエンプションが発生しなくなってしまいます。また、短いデューティサイクルのタスクが CPU を多く使用するタスクに打ち勝てなくなります。
sched_rr_timeslice_ms
SCHED_RR のタスクが、他のタスクに奪われたり、タスクリストの末尾に回されたりすることなく実行できる時間単位を表します。
sched_rt_period_us
リアルタイムタスクの帯域強制を測定する時間を表します。既定値は 1000000
[マイクロ秒] です。
sched_rt_runtime_us
sched_rt_period_us の間にリアルタイムタスクに割り当てられる時間単位です。 -1 を設定すると、リアルタイムタスクの帯域強制を行わなくなります。既定では、リアルタイムタスクは 95 [%CPU/sec] を消費するため、 5 [%CPU/sec] もしくは 0.05 [s] が SCHED_OTHER のタスクに残されることになります。既定値は 950000
[マイクロ秒] です。
sched_nr_migrate
負荷分散の目的で、プロセッサ間でタスクをマイグレーション (移行) できるタスクの数を制御します。負荷分散では割り込みを無効化 (ソフト IRQ) して実行キューを列挙するため、リアルタイムのタスクに対しては IRQ 遅延のペナルティを招く可能性があります。そのため、この値を増やすと、巨大な SCHED_OTHER のスレッドに対して性能を向上させる代わりに、リアルタイムタスクの IRQ 遅延が増えることになります。既定値は 32
です。
sched_time_avg_ms
このパラメータは、リアルタイムのタスクの実行に費やす時間の平均値を設定します。この平均値は CFS に対して、負荷分散の決定を支援する値となるほか、 CPU が高い優先順位のリアルタイムタスクでどれだけ忙しくなっているのかを表す値にもなっています。
このパラメータに対する最適な設定値は、負荷の内容に大きく依存するものであるほか、リアルタイムのタスクをどれだけ頻繁に、どれだけ長く実行するのかにもよります。
debugfs
に移行されている件についてお使いのシステムで、既定の Linux カーネルバージョンが 5.13 もしくはそれ以降の場合 (rpm -q kernel-default
コマンドを実行すると確認できます) 、下記のようなメッセージがカーネルログ内に記録されていることに気がつくかもしれません:
[ 20.485624] The sched.sched_min_granularity_ns sysctl was moved to debugfs in kernel 5.13 for CPU scheduler debugging only. This sysctl will be removed in a future SLE release. [ 20.485632] The sched.sched_wakeup_granularity_ns sysctl was moved to debugfs in kernel 5.13 for CPU scheduler debugging only. This sysctl will be removed in a future SLE release.
上記のメッセージは、 6 種類のスケジューラ関連パラメータが /proc/sys/kernel/sched_*
から /sys/kernel/debug/sched/*
に移動している旨を表したメッセージです。 6 種類のパラメータは下記のとおりです:
sched_latency_ns
sched_migration_cost_ns
sched_min_granularity_ns
sched_nr_migrate
sched_tunable_scaling
sched_wakeup_granularity_n
上述のメッセージのとおり、これらのスケジューラ関連パラメータは移行期間中として現行の openSUSE Leap の sysctl
内で提供され続けています。ですが、将来的には CPU スケジューラの実装が更新される予定であることから、将来バージョンの openSUSE Leap で上記パラメータが sysctl
で提供され続ける保証はなく、 debugfs
経由で利用する必要があるかもしれないことに注意してください。
もしもお使いのシステム内で、これら 6 種類のパラメータのうちいずれかを使用している場合は、目的に合わせて別の方式を使用するようにし、特に本番環境ではこれらに依存した作りにしないようにすることを強くお勧めします。
CFS では新しく改善されたデバッグインターフェイスが用意され、稼働中の統計情報を提供することができるようになっています。これらのファイルは /proc
ファイルシステム内に用意されていますので、 cat
や less
などのコマンドを使用することで、簡単に調べることができるようになっています。下記にはタスクスケジューラ関連の /proc
ファイルと、その簡潔な説明を示しています:
/proc/sched_debug
タスクスケジューラの動作に関わる全てのチューニング可能な変数 (詳しくは 14.3.6項 「sysctl
による稼働中のチューニング」 をご覧ください) のほか、 CFS の統計情報や全てのプロセッサでの実行キュー (CFS, RT, deadline) に対する現在の値を含んでいるファイルです。各プロセッサで動作しているタスクの概要についても、タスク名と PID 、そしてスケジューラ固有の統計情報を表示することができます。最初の列には tree-key
列が表示されていますが、これはタスクの仮想ランタイムを示すもので、その名前は赤黒木内で全ての実行可能なタスクを並べ替える際のキーでもあります。また switches
列には、スイッチの合計数 (involuntary であるものを含む) を示しています。さらに、 prio
列にはプロセスの優先順位が、 wait-time
にはタスクがスケジュールされるまでに待機した時間の合計値が、 sum-exec
と sum-sleep
には、それぞれそのタスクをプロセッサ内で実行した時間の合計と、休眠 (スリープ) していた時間の合計がナノ秒単位で示されています。
#
cat /proc/sched_debug
Sched Debug Version: v0.11, 6.4.0-150600.9-default #1
ktime : 23533900.395978
sched_clk : 23543587.726648
cpu_clk : 23533900.396165
jiffies : 4300775771
sched_clock_stable : 0
sysctl_sched
.sysctl_sched_latency : 6.000000
.sysctl_sched_min_granularity : 2.000000
.sysctl_sched_wakeup_granularity : 2.500000
.sysctl_sched_child_runs_first : 0
.sysctl_sched_features : 154871
.sysctl_sched_tunable_scaling : 1 (logarithmic)
cpu#0, 2666.762 MHz
.nr_running : 1
.load : 1024
.nr_switches : 1918946
[...]
cfs_rq[0]:/
.exec_clock : 170176.383770
.MIN_vruntime : 0.000001
.min_vruntime : 347375.854324
.max_vruntime : 0.000001
[...]
rt_rq[0]:/
.rt_nr_running : 0
.rt_throttled : 0
.rt_time : 0.000000
.rt_runtime : 950.000000
dl_rq[0]:
.dl_nr_running : 0
task PID tree-key switches prio wait-time [...]
------------------------------------------------------------------------
R cc1 63477 98876.717832 197 120 0.000000 ...
/proc/schedstat
現在の実行キューに関連する統計情報を表示します。 SMP システムの場合、接続されている全てのプロセッサに対して、ドメイン固有の統計情報も表示することができます。出力形式はわかりにくい形式であるため、詳しくは /usr/src/linux/Documentation/scheduler/sched-stats.txt
をお読みください。
/proc/PID/sched
PID で指定したプロセスのスケジューリング情報を表示することができます。
#
cat /proc/$(pidof gdm)/sched
gdm (744, #threads: 3)
-------------------------------------------------------------------
se.exec_start : 8888.758381
se.vruntime : 6062.853815
se.sum_exec_runtime : 7.836043
se.statistics.wait_start : 0.000000
se.statistics.sleep_start : 8888.758381
se.statistics.block_start : 0.000000
se.statistics.sleep_max : 1965.987638
[...]
se.avg.decay_count : 8477
policy : 0
prio : 120
clock-delta : 128
mm->numa_scan_seq : 0
numa_migrations, 0
numa_faults_memory, 0, 0, 1, 0, -1
numa_faults_memory, 1, 0, 0, 0, -1
Linux のタスクスケジューリングに関して、よりコンパクトな知識を得たい場合は、下記のような情報源をお読みになることをお勧めします:
タスクスケジューラ関連のシステムコールの説明については、それぞれ対応するマニュアルページ (例: man 2 sched_setaffinity
) をお読みください。
Linux のスケジューラポリシーおよびアルゴリズムに関するわかりやすい説明については、 https://www.inf.fu-berlin.de/lehre/SS01/OS/Lectures/Lecture08.pdf (英語) をお読みになることをお勧めします。
Linux のプロセススケジューリングに関する概要については、 Robert Love 氏による Linux Kernel Development (ISBN-10: 0-672-32512-8) (英語) がよいでしょう。詳しくは https://www.informit.com/articles/article.aspx?p=101760 をご覧ください。
Linux カーネルの内部に関する広範囲な概要を知りたい場合は、 Daniel P. Bovet 氏と Marco Cesati 氏による Understanding the Linux Kernel (ISBN 978-0-596-00565-8) (英語) がよいでしょう。
タスクスケジューラに関する技術的な情報については、 /usr/src/linux/Documentation/scheduler
内にあるファイルをお読みください。