この章では、SunOS 5.x のスケジューラについて説明します。この章の概要は次のとおりです。
「スケジューラ」(またはディスパッチャー) は、プロセスへの CPU 割り当てを制御するカーネルの一部です。スケジューラは、プロセスを実行するタイミングと実行時間を、それに割り当てられた優先順位に従って決定します。優先順位は、スケジューリングクラスとプロセスの動作に基づきます。デフォルトでは、タイムシェアリング、システム、リアルタイム、対話型という 4 つのスケジューリングクラスがサポートされています。
スケジューラはシステム性能に大きな影響を与えます。
基本的なスケジューリングエンティティはカーネルスレッドです。1 つのスレッドからなるプロセスの場合、カーネルスレッドのスケジューリングは、プロセスのスケジューリングと同じです。
SunOS 5.x のスケジューラは、プロセスの実行順序と、別のプロセスの前に、各プロセスが使用できる CPU 時間の量を制御します。
スケジューラは、スケジューリングクラスごとに定義されたスケジューリングポリシーに従って、プロセスに CPU 時間を割り当てます。各スケジューリングクラスには、一連の優先レベルまたは待ち行列が割り当てられています。実行準備ができたプロセスは、これらの待ち行列間を移動します。クラス内では、これらの待ち行列を連続する優先レベルセットと見なすことができます。これらの優先レベルは、グローバルスケジューリング優先順位セットにマップされます。
プロセスのグローバル優先順位によって、いつ実行するかが決まります。スケジューラは、実行準備ができていて最上位のグローバル優先順位を持つプロセスを実行します。優先順位の数値が大きいプロセスが最初に実行され、同じ優先順位を持つプロセスはラウンドロビン方式のスケジューリングポリシーを使用して実行されます。
スケジューラがプロセスを CPU に割り当てると、プロセスは次のいずれかのイベントが発生するまで実行されます。
プロセスがタイムスライスを使い果たす。
プロセスブロックがイベント (入出力など) または中断されたロックを待機中である。
優先順位の高い別のプロセスによってプロセスが横取りされる。
デフォルトでは、すべてのリアルタイムプロセスは、システムプロセスよりも上位の優先順位を持ち、すべてのシステムプロセスはタイムシェアリングプロセスよりも上位の優先順位を持ちます。
プロセスは、スケジューラクラスやそのクラス内での優先順位など、スケジューラパラメタを親プロセスから継承します。ユーザーが (priocntl コマンドやシステムコールを使用して) 要求した場合にのみ、プロセスはクラスを変更します。システムは、ユーザー要求とプロセスのスケジューリングクラスに関連付けられたポリシーに基づいて、プロセスの優先順位を管理します。
この後の各節では、タイムシェアリング、システム、リアルタイムという 3 つのデフォルトクラスのスケジューリングポリシーについて説明します。
デフォルト構成では、初期化プロセス (init) はタイムシェアリングクラスに属します。プロセスはスケジューラパラメタを継承するので、すべてのユーザーログインシェルと、各シェルから実行されるプロセスは、タイムシェアリングプロセスとして起動されます。
タイムシェアリングポリシーの目標は、対話型プロセスの応答時間を短縮し、大量の CPU 時間を使用するプロセスのスループットを適正化することです。スケジューラは、各プロセスに関連付けられた優先順位に従って、CPU 時間をプロセス間で適正に分割しようとします。優先順位が上位のプロセスは、下位のプロセスよりも優先して扱われます。しかし、あるジョブ (プロセス) が CPU を独占しないように、スケジューラはジョブを優先順位の上位から下位へ、または下位から上位へ移動できます。
スケジューラは、応答時間を短縮する一方で切り替えによって時間が無駄にならない程度の頻度で CPU 割り当てを切り替えます。通常、タイムスライスは 1/100 秒単位程度です。
タイムシェアリングポリシーは、優先順位を動的に変更し、さまざまな長さのタイムスライスを割り当てます。プロセスが起動されると、そのタイムシェアリング優先順位は、取得する CPU 時間や待ち行列内で費やす時間などの要素に従って変動します。スケジューラは、「休眠状態」になっているプロセスの優先順位を上げます (たとえば、端末の読み取りやディスクの読み取りなどの入出力処理が始まると、プロセスは休眠状態になります)。単純なシェルコマンドの編集や実行などの対話型作業では、頻繁に休眠状態になります。これに対して、タイムシェアリングポリシーは、休眠状態にならずに長期間 CPU を使用するプロセスの優先順位を下げます。
デフォルトのタイムシェアリングポリシーは、優先順位が低いプロセスに大きいタイムスライスを与えます。優先順位の低いプロセスほど CPU 内にたまる傾向があります。他のプロセスが最初に CPU を取得しますが、優先順位の低いプロセスが最終的に CPU を取得するときには大きなタイムスライスを取得します。タイムスライス中に優先順位の高いプロセスの実行準備ができると、実行中のプロセスを横取りします。
スケジューラは、タイムシェアリングパラメタテーブル ts_dptbl 内のパラメタを使用してタイムシェアリングプロセスを管理します。このテーブルには、タイムシェアリングクラスに固有の情報が入っています。このテーブルは、ディレクトリ /kernel/sched 内のロード可能モジュール TS_DPTBL から、コアメモリーに自動的にロードされます。
システムクラスは、固定優先順位ポリシーを使用して、サーバーなどのカーネルプロセスや、ページデーモンなどの準備作業プロセスを実行します。それぞれの優先順位は、タイムシェアリングプロセスのように動的に調整されません。システムクラスはカーネル用に予約されており、ユーザーがシステムクラスからプロセスを追加または削除することはできません。システムクラスのプロセスの優先順位は、カーネルプロセス用のカーネルコード内で設定されます。これらの優先順位は、一度確立された後は変化しません (カーネルモードで実行されるユーザープロセスはシステムクラスではありません)。
SunOS 5.x オペレーティングシステムは、タイムシェアリングポリシーだけでなくリアルタイムのスケジューリングポリシーを使用します。リアルタイムスケジューリングを使用すると、ユーザーはプロセスごとに固定優先順位を設定できるので、重要なプロセスを事前に決めておいた順序で実行できます。リアルタイムスケジューラは優先順位間でジョブを移動しません。リアルタイム優先順位は、ユーザーが (priocntl コマンドを使用して) 要求したときにのみ変化します。この固定優先順位ポリシーはタイムシェアリングポリシーと同じで、対話型の応答時間を短縮するためにシステムが優先順位を変更します。
リアルタイム優先順位が最上位のユーザープロセスは、他のプロセスの実行準備ができていても、実行できるようになると必ず CPU を取得します。リアルタイムプロセスにとってオペレーティングシステムからの応答時間が保証されるようなアプリケーションを作成できます。
リアルタイムプロセスの実行準備ができていると、プロセスやタイムシェアリングプロセスは実行されません。他のリアルタイムプロセスは、優先順位が上位の場合にのみ実行できます。リアルタイムプロセスを慎重に管理しないと、タイムシェアリングプロセスの性能に重大な悪影響を及ぼすことがあります。
リアルタイムポリシーは、デフォルトでは優先順位が高いプロセスに小さいタイムスライスを割り当てます。優先順位が高いプロセスは、外部イベントによって駆動されるリアルタイムプロセスに割り当てられます。オペレーティングシステムは、入出力に瞬間的に応答できなければなりません。優先順位の低いリアルタイムプロセスとは、より長い処理時間を必要とするプロセスです。優先順位の最も高いプロセスがタイムスライスを使い果たすと、そのプロセスを横取りできるような優先順位のより高いプロセスは存在しないので再び実行されます。
スケジューラは、リアルタイムパラメタテーブル rt_dptbl 内のパラメタを使用してリアルタイムプロセスを管理します。このテーブルには、リアルタイムクラスに固有の情報が入っています。このテーブルは、ディレクトリ /kernel/sched 内のロード可能モジュール RT_DPTBL から、コアメモリーに自動的にロードされます。
この節では、スケジューラの構成を制御するパラメタとテーブルについて説明します。CPU、メモリー、入出力などのシステム資源の作業負荷が妥当であるものと仮定します。資源不足で需要を満たせない場合は、スケジューラを構成し直しても問題は解決しません。
dispadmin コマンドを使用すると、タイムシェアリングクラスとリアルタイムクラスに関して、実行中のシステム内のスケジューラパラメタを表示または変更 (微調整) できます。スケジューラ構成に永続的な変更を加えるには、それに該当するロード可能モジュール、つまり、ディレクトリ /kernel/sched 内の TS_DPTBL または RT_DPTBL 内で、スケジューラパラメタテーブルを変更しなければなりません。これらのモジュールを置き換える方法については、ts_dptbl(4) と rt_dptbl(4) のマニュアルページを参照してください。
プロセススケジューリングを制御する基本ユーザーコマンドは、priocntl(1) です。このコマンドを使用すると、ユーザーは指定した優先順位でプロセスを起動したり、実行中のプロセスの優先順位を操作したりできます。priocntl -l コマンドを使用すると、システム上で構成されているクラスを調べることができます。プロセススケジューリングを制御する基本関数コールは、priocntl(2) です。
priocntl コマンドの使用例については、第 63 章「プロセスの管理手順」を参照してください。リアルタイムプログラミング、dispadmin(1M) コマンド、priocntl(1) コマンドについての詳細は、『システムインタフェース』を参照してください。
次の表は、各スケジューラクラスのグローバル優先順位のスケジューリング順序と範囲を示しています。
表 67-1 スケジューリング順序とグローバル優先順位| 
 スケジューリング順序  | 
 グローバル優先順位  | 
 スケジューラクラス  | 
|---|---|---|
| 
 159  | 
 
  | 
|
| 
 
  | 
 .  | 
 
  | 
| 
 
  | 
 .  | 
 リアルタイム  | 
| 
 
  | 
 .  | 
 
  | 
| 
 
  | 
 100  | 
 
  | 
| 
 
  | 
 
  | 
|
| 
 
  | 
 .  | 
 
  | 
| 
 
  | 
 .  | 
 システム  | 
| 
 
  | 
 .  | 
 
  | 
| 
 
  | 
 60  | 
 
  | 
| 
 
  | 
 
  | 
|
| 
 
  | 
 .  | 
 
  | 
| 
 
  | 
 .  | 
 タイムシェアリング  | 
| 
 
  | 
 .  | 
 
  | 
| 
 最後  | 
 0  | 
 
  | 
オペレーティングシステムが構築されるときに、この後の各節で説明する調整可能パラメタとスケジューラパラメタのテーブルから、グローバル優先順位を作成します。このグローバル優先順位テーブル全体を表示するコマンドはありません。ただし、dispadmin コマンドを使用すると、リアルタイムクラスとタイムシェアリングクラスに固有の優先順位 (0 から n まで) が表示されます。ps -cl コマンドを使用すると、有効なプロセスのグローバル優先順位を表示できます。
タイムシェアリングプロセスは、スケジューリングクラスと優先順位を親プロセスから継承します。init プロセスは、タイムシェアリングクラス全体で最初のプロセスです。
システムプロセスは、最初はプロセスの重要性 (カーネルにプログラムされている重要性) に応じた優先順位で実行されます。最も重要なシステムプロセスは、システムクラス範囲の最上位か、それに近い優先順位で開始されます。
この節では、スケジューラの構成を制御する調整可能パラメタについて説明します。これらのカーネルパラメタを変更するには、次の書式の 1 行を /etc/system ファイルに入力します。
set パラメタ=value
詳細は、system(4) のマニュアルページを参照してください。
この節で説明するパラメタは、プロセススケジューリング、タイムシェアリングポリシー、およびリアルタイムポリシーについて詳細に制御します。
リアルタイムプロセスの初期優先順位は、そのプロセスがリアルタイムスケジューリングクラスに入れられるときに決定されます。
priocntl -p コマンドを使用すると、リアルタイムクラス内で相対優先順位を指定できます。
これは、リアルタイムクラスの基本優先順位に追加されます。基本優先順位のデフォルトは 100 です。たとえば、
priocntl -e -c RT -p 20 command
上記のように入力すると、リアルタイム優先順位 120 でコマンドが実行されることになります。
次のカーネルパラメタは、プロセススケジューリングについて詳細に制御します。
maxclsyspri
maxclsyspri は、システムクラス内のプロセスの最大グローバル優先順位です。カーネルがシステムプロセスを起動するときに、参照ポイントとして maxclsyspri の値を使用して優先順位を割り当てます。カーネルはシステムクラスの優先順位全体の範囲が少なくとも 40 であると見なすので、maxclsyspri の値は 39 以上でなければなりません。
このパラメタを変更する場合は、割り当てる最大優先順位に対応する値を使用して、スケジューリングクラステーブルを再構築しなければなりません。
次のパラメタは、タイムシェアリングポリシーを制御するロード可能モジュール TS 内で指定します。
ts_maxupri
ts_maxupri は、ユーザーが priocntl(l) コマンドや priocntl(2) システムコールを使用してタイムシェアリングプロセスの優先順位を調整できる範囲を指定します。タイムシェアリングクラス内でユーザーが与える優先順位の有効な範囲は、+ts_maxupri から -ts_maxupri までです。ts_maxupri のデフォルト値は 20 です (この場合、古くてあまり一般的でないスケジューラインタフェース nice と setpriority の動作をエミュレートして、+20 から -20 までの範囲を設定します)。
ts_maxupri の値は、構成されているグローバルタイムシェアリング優先順位の数の影響を受けません。デフォルト構成では、0 から 59 までのタイムシェアリングポリシーがあります。しかし、ユーザーはシステムで計算されたプロセスの優先順位に対して、-20 から +20 までの範囲内でのみ優先順位を調整できます。詳細は、「優先順位を指定する方法」を参照してください。
このパラメタの値を変更するには、次の書式の 1 行を /etc/system に入力します。
set TS:ts_maxupri=value
次のパラメタは、リアルタイムポリシーを制御するロード可能モジュール RT 内で指定します。
rt_maxpri
rt_maxpri は、リアルタイムプロセスに割り当てる最大優先順位を指定します。rt_maxpri のデフォルト値は 159 です。
このパラメタを変更する場合は、割り当てる最大優先順位に対応する値を使用して、スケジューリングクラステーブルを再構築しなければなりません。
このパラメタの値を変更するには、次の書式の 1 行を /etc/system ファイルに入力します。
set RT:rt_maxupri=value
表 67-2 に、スケジューラテーブルを示します。
表 67-2 スケジューラテーブル| 
 テーブル  | 
 管理対象  | 
|---|---|
| 
 rt_dptbl  | 
 リアルタイムプロセス  | 
| 
 ts_dptbl  | 
 タイムシェアリングプロセス  | 
| 
 ts_kmdpris  | 
 重要な資源を所有する休眠中のタイムシェアリングプロセス  | 
これらのテーブルは、リアルタイムプロセスとタイムシェアリングプロセスに使用するスケジューリングパラメタを設定して、スケジューリングポリシーを定義します。パラメタは、さまざまな優先レベルでプロセスが取得する CPU 時間の長さを指定します。
優先レベルのデフォルトのタイムスライスは、ts_dptbl 構成テーブルと rt_dptbl 構成テーブル内で指定されます。この 2 つのテーブルは、ロード可能モジュール TS_DPTBL および RT_DPTBL 内で定義されます。この 2 つのモジュールは、必要に応じてディレクトリ /kernel/sched からカーネルに自動的にロードされます。
タイムスライスは、「resolution」行で定義された解像度の単位数 (quanta) で指定されます。デフォルトの解像度は 1000 であり、タイムカンタムの値はミリ秒数として解釈されます。これは、秒数単位で指定された解像度の逆数から求められます。タイムスライスの quanta 量はクロックの目盛り単位でシステムクロックの解像度の次の積分倍数に切り上げられます (システムクロックの目盛りは 1 秒当たり HZ 回です。この場合、HZ は param.h ヘッダファイル内で定義されたハードウェア依存定数です)。たとえば、クロックの目盛りが 10 ミリ秒単位の場合は、タイムスライス量 42 quanta は切り上げられ 50 ミリ秒となります。
ts_dptb のデフォルトバージョンは、/kernel/sched/TS_DPTBL 内のシステムから配信されます。デフォルト構成では、タイムシェアリング優先順位は 60 です。
次の dispadmin -c TS -g コマンドでは、ts_dptbl テーブルの例を表示します。
$ dispadmin -c TS -g
# Time Sharing Dispatcher Configuration
RES=1000
# ts_quantum  ts_tqexp  ts_slpret  ts_maxwait ts_lwait  PRIORITY LEVEL
       200         0        50           0        50        #     0
       200         0        50           0        50        #     1
       200         0        50           0        50        #     2
       200         0        50           0        50        #     3
       200         0        50           0        50        #     4
       200         0        50           0        50        #     5
       200         0        50           0        50        #     6
       200         0        50           0        50        #     7
       200         0        50           0        50        #     8
       200         0        50           0        50        #     9
       160         0        51           0        51        #    10
       160         1        51           0        51        #    11
       160         2        51           0        51        #    12
       160         3        51           0        51        #    13
       160         4        51           0        51        #    14
       160         5        51           0        51        #    15
       160         6        51           0        51        #    16
       160         7        51           0        51        #    17
       160         8        51           0        51        #    18
       160         9        51           0        51        #    19
       120        10        52           0        52        #    20
       120        11        52           0        52        #    21
       120        12        52           0        52        #    22
       120        13        52           0        52        #    23
       120        14        52           0        52        #    24
       120        15        52           0        52        #    25
       120        16        52           0        52        #    26
       120        17        52           0        52        #    27
       120        18        52           0        52        #    28
       120        19        52           0        52        #    29
        80        20        53           0        53        #    30
        80        21        53           0        53        #    31
        80        22        53           0        53        #    32
        80        23        53           0        53        #    33
        80        24        53           0        53        #    34
        80        25        54           0        54        #    35
        80        26        54           0        54        #    36
        80        27        54           0        54        #    37
        80        28        54           0        54        #    38
        80        29        54           0        54        #    39
        40        30        55           0        55        #    40
        40        31        55           0        55        #    41
        40        32        55           0        55        #    42
        40        33        55           0        55        #    43
        40        34        55           0        55        #    44
        40        35        56           0        56        #    45
        40        36        57           0        57        #    46
        40        37        58           0        58        #    47
        40        38        58           0        58        #    48
        40        39        58           0        59        #    49
        40        40        58           0        59        #    50
        40        41        58           0        59        #    51
        40        42        58           0        59        #    52
        40        43        58           0        59        #    53
        40        44        58           0        59        #    54
        40        45        58           0        59        #    55
        40        46        58           0        59        #    56
        40        47        58           0        59        #    57
        40        48        58           0        59        #    58
        20        49        59       32000        59        #    59
$ 
表 67-3 に、ts_dptbl テーブル内のフィールドを示します。
表 67-3 ts_dptbl テーブル内のフィールド| 
 フィールド名  | 
 説明  | 
|---|---|
| 
 ts_quantum (実行時)  | 
 スケジューラが、あるプロセスの優先順位を評価し直す前に、そのプロセスを与えられた優先順位で実行できるタイムスライス (デフォルトではミリ秒単位) が入っている。プロセスがそのタイムスライス全体を使い果たすと、期間満了レベル (ts_tqexp) 待ち行列に入る。タイムスライスは、最上位の待ち行列の 40 ミリ秒 (59) から最下位の優先順位の 200 ミリ秒 (0) までになる。  | 
| 
 ts_tqexp (期間満了レベル)  | 
 タイムスライスが期間満了したプロセスの新しいプロセス優先順位を決定する。プロセスが休眠状態に入らずに全タイムスライスを使い果たすと、スケジューラはその優先順位を ts_tqexp カラムに示されたレベルに変更する。期間満了レベルは前のレベルよりも低くなる。たとえば、優先順位が 30 のプロセスがタイムスライス (80 ミリ秒) を使い果たすと、その新しい優先順位は 20 になる。  | 
| 
 ts_slpret (休眠レベル)  | 
 休眠状態から戻るときにプロセスに割り当てられる優先順位を決定する。プロセスは、特定のシステムコール中や、入出力の待機中 (ページフォルトのサービス中やロックの待機中など) に休眠状態になることがある。プロセスが休眠状態から戻るときは、常に優先順位 59 が与えられる。  | 
| 
 ts_maxwait (待ち時間)  | 
 タイムスライスが期間満了しない状態でプロセスがディスパッチ待ち行列に残っている秒数を指定する。タイムスライスを使用しない場合 (ts_maxwait 秒以内) 、その新しい優先順位は ts_lwait に設定される。これは、優先順位の低いプロセスが CPU 時間が不足するのを防ぐために使用される。  | 
| 
 ts_lwait (待機レベル)  | 
 タイムスライスを完全に取得しないまま最大待ち時間 (ts_maxwait) を超えた、実行準備ができているプロセスの新しい優先順位が入っている。  | 
| 
 PRIORITY LEVEL  | 
 グローバル優先順位が入っている。より上位の優先レベルで待ち行列に入ったプロセスが最初に実行される。グローバル優先順位は、上位の 59 から下位の 0 までになる。これは、調整できないテーブル内の唯一のカラムである。  | 
rt_dptbl のデフォルトバージョンは、ロード可能モジュール/kernel/sched/RT_DPTBL 内でシステムと共に配信されます。
dispadmin -c RT -g コマンドは、次のような rt_dptbl 情報を表示します。
$ dispadmin -c RT -g
# Real Time Dispatcher Configuration
RES=1000
# TIME QUANTUM                    PRIORITY
# (rt_quantum)                      LEVEL
      1000                    #        0
      1000                    #        1
      1000                    #        2
      1000                    #        3
      1000                    #        4
      1000                    #        5
      1000                    #        6
      1000                    #        7
      1000                    #        8
      1000                    #        9
       800                    #       10
       800                    #       11
       800                    #       12
       800                    #       13
       800                    #       14
       800                    #       15
       800                    #       16
       800                    #       17
       800                    #       18
       800                    #       19
       600                    #       20
       600                    #       21
       600                    #       22
       600                    #       23
       600                    #       24
       600                    #       25
       600                    #       26
       600                    #       27
       600                    #       28
       600                    #       29
       400                    #       30
       400                    #       31
       400                    #       32
       400                    #       33
       400                    #       34
       400                    #       35
       400                    #       36
       400                    #       37
       400                    #       38
       400                    #       39
       200                    #       40
       200                    #       41
       200                    #       42
       200                    #       43
       200                    #       44
       200                    #       45
       200                    #       46
       200                    #       47
       200                    #       48
       200                    #       49
       100                    #       50
       100                    #       51
       100                    #       52
       100                    #       53
       100                    #       54
       100                    #       55
       100                    #       56
       100                    #       57
       100                    #       58
       100                    #       59
$
表 67-4 に、リアルタイムパラメタテーブル内のフィールドを示します。
表 67-4 rt_dptbl テーブル内のフィールド| 
 フィールド名  | 
 説明  | 
|---|---|
| 
 rt_glbpri  | 
 グローバル優先順位が入っている。より上位の優先レベルで待ち行列に入ったプロセスが最初に実行される。dispadmin コマンドを使用するとテーブルを表示できるが、グローバル優先順位ではなくクラス内の相対優先順位しか表示されないので注意すること。このカラムを dispadmin で変更することはできない。  | 
| 
 rt_qntm  | 
 スケジューラが別のプロセスにチャンスを与える前に、この優先順位 (rt_glbpri) を持つプロセスを実行できるデフォルトのタイムスライス (ミリ秒単位) を示す。リアルタイムプロセスのタイムスライスは、priocntl -t コマンドで指定できる。  | 
スケジューラは、カーネルモードのパラメタテーブル ts_kmdpris を使用して、休眠中のタイムシェアリングプロセスを管理します。ts_kmdpris のデフォルトバージョンは、ロード可能モジュール /kernel/sched/TS_DPTBL 内でシステムと共に配信され、システム構成の一部としてカーネルに自動的に組み込まれます。詳細は、ts_dptbl(4) のマニュアルページを参照してください。
カーネルは、ts_kmdpris 内に少なくとも 40 の優先順位があるものと想定します。40 の優先順位がないとパニックになります。
カーネルモードのパラメタテーブルは、60 から 99 までのグローバル優先順位の一次元配列です。プロセスが重要な資源を所有する場合は、できる限り短時間で資源を解放できるようにカーネル優先順位が割り当てられます。重要な資源は次のとおりです。
SunOS 5.3 より前のバージョンまでは、プロセスには休眠中にカーネル優先順位が割り当てられていました。これにより、待機中の資源が再び実行される前にページアウトされないことが保証されていました。
これを SunOS 5.3 以降のバージョンで実行するために、休眠状態から戻ったプロセスは、最上位のタイムシェアリング優先順位 (59) に変換されます。