Everything

第11章  スケジューリング機能


本章では,RI78V4が提供しているスケジューリング機能について解説しています。
11.1 概  要
RI78V4におけるスケジューリング機能では,動的に変化していくタスクの遷移状態を観察することにより,タスクの実行順序を管理/決定し,最適なタスクにCPUの利用権を与える機能を提供しています。
11.2 駆動方式
RI78V4では,スケジューラの駆動方式として“何らかの事象(きっかけ)”が発生した際に起動する事象駆動方式を採用しています。
- 事象駆動方式
RI78V4における事象駆動方式では,以下に示した事象が発生した場合に“スケジューラ”を起動し,ディスパッチ処理(タスクのスケジューリング処理)を実行します。
- タスクの状態遷移を引き起こす可能性があるサービス・コールの発行
- 非タスク(周期ハンドラ,割り込みハンドラなど)からの復帰命令の発行
- 時間管理機能を実現する際に利用しているクロック割り込みの発生
11.3 スケジューリング方式
RI78V4では,タスクのスケジューリング方式として“各タスクに定義されている優先度”を利用した優先度方式,および,RI78V4のスケジューリング対象となってからの経過時間を利用したFCFS方式を採用しています。
- 優先度方式
RI78V4における優先度方式では,実行可能な状態(RUNNING状態,またはREADY状態)へと遷移している全タスクの中から“最も高い優先度を持つタスク”を選び出し,CPUの利用権を与えます。
備考 RI78V4における優先度は,その値が小さいほど,高い優先度であることを意味します。
- FCFS方式
RI78V4では,同一の優先度を“複数のタスク”に対して定義することが可能です。このため,優先度方式におけるタスクを選び出す基準である“最も高い優先度を持つタスク”が複数存在する場合があります。
そこで,RI78V4では,このような場合には,FCFS方式(First Come First Service方式)によるディスパッチ処理(タスクのスケジューリング処理)を実行し,実行可能な状態(READY状態)へと遷移してから“最も時間が経過しているタスク”を選び出し,CPUの利用権を与えます。
11.4 レディ・キュー
RI78V4では,タスクのスケジューリング方式を実現する手段として“レディ・キュー”を利用しています。
なお,RI78V4におけるレディ・キューは,優先度をキーとしたハッシュ・テーブルであり,実行可能な状態(RUNNING状態,またはREADY状態)へと遷移したタスクがFIFO順でキューイングされます。このため,スケジューラは,起動された際にレディ・キューの優先度高位から“タスクの検出処理”を実行し,キューイングされているタスクを検出した際には,該当優先度の先頭タスクにCPUの利用権を与えることにより,タスクのスケジューリング方式(優先度方式,FCFS方式)を実現しています。
以下に,複数のタスクがレディ・キューにキューイングされている場合を示します。
図11-1  スケジューリング方式(優先度方式,FCFS方式)の実現
11.4.1 レディ・キューの生成
RI78V4では,レディ・キューの生成方法を“カーネル初期化部において静的に生成する”に限定しています。
したがって,RI78V4では,レディ・キューを処理プログラムからサービス・コールを発行するなどして動的に生成することはできません。
- 静的な生成
レディ・キューの静的な生成は,システム・コンフィギュレーション・ファイルに優先度情報を定義することにより実現されます。
RI78V4では,カーネル初期化部において,情報ファイルに格納されているデータをもとにレディ・キューの生成処理を実行し,管理対象とします。
11.4.2 レディ・キューの削除
RI78V4では,カーネル初期化部において静的に生成されたレディ・キューを処理プログラムからサービス・コールを発行するなどして動的に削除することはできません。
11.4.3 レディ・キューの回転
RI78V4では,処理プログラムからタスクのキューイング順序を変更し,“タスクの実行順序”を明示的に入れ替える機能を提供しています。
以下に,タスクのキューイング順序を変更した際の状態変化を示します。
図11-2  レディ・キューの回転
なお,レディ・キューの回転は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- rot_rdqirot_rdq
パラメータtskpriで指定された優先度に対応したレディ・キューの先頭タスクを最後尾につなぎかえ,タスクの実行順序を明示的に変更します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_cychdr ( void )
 {
         PRI     tskpri = 8;             /*変数の宣言,初期化*/
 
         ............
         ............
 
         irot_rdq ( tskpri );            /*レディ・キューの回転*/
 
         ............
         ............
 
         return;                         /*周期ハンドラの終了*/
 }
 
備考1 本サービス・コールでは,回転要求のキューイングが行われません。このため,該当優先度に対応したレディ・キューにタスクが1つもキューイングされていなかった場合には,何も処理は行わず,エラーとしても扱いません。
備考2 本サービス・コールを周期ハンドラなどから一定周期で発行することにより,ラウンドロビン・スケジューリングを実現することができます。
11.4.4 優先度の変更
RI78V4では,処理プログラムからタスクの優先度を変更し,“タスクの実行順序”を明示的に入れ替える機能を提供しています。
以下に,タスクの優先度を変更した際の状態変化を示します。
図11-3  優先度の変更
なお,優先度の変更は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- chg_priichg_pri
パラメータtskidで指定されたタスクの優先度(現在優先度)をパラメータtskpriで指定された値に変更します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
         PRI     tskpri = 9;             /*変数の宣言,初期化*/
 
         ............
         ............
 
         chg_pri ( tskid, tskpri );      /*優先度の変更*/
 
         ............
         ............
 }
 
備考 本サービス・コールを発行した際,対象タスクがRUNNING状態,またはREADY状態であった場合には,優先度の変更処理を実行したのち,パラメータtskpriで指定された優先度に対応したレディ・キューの最後尾にキューイングし直す処理もあわせて実行されます。
11.5 スケジューリングの抑制
RI78V4では,処理プログラムからシステム状態を操作し,ディスパッチ処理(タスクのスケジューリング処理)を明示的に禁止することにより,スケジューラの起動を抑制する機能を提供しています。
以下に,スケジューリングの抑制機能を利用した際の処理の流れを示します。
図11-4  スケジューリングの抑制機能
11.5.1 ディスパッチ禁止状態への移行
ディスパッチ禁止状態への移行は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- dis_dsp
システム状態種別をディスパッチ禁止状態へと変更します。
これにより,本サービス・コールの発行からena_dspが発行されるまでの間,ディスパッチ処理(タスクのスケジューリング処理)が禁止されます。
なお,RI78V4では,本サービス・コールの発行からena_dspが発行されるまでの間に“ディスパッチ処理を伴うサービス・コール(chg_prisig_semなど)”が発行された場合には,キュー操作,カウンタ操作などといった処理を行うだけであり,実際のディスパッチ処理は,ena_dspが発行されるまで遅延され,一括して行うようにしています。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ............
         ............
 
         dis_dsp ( );                    /*ディスパッチ禁止状態への移行*/
 
         ............                    /*ディスパッチ禁止状態*/
         ............
 
         ena_dsp ( );                    /*ディスパッチ禁止状態の解除*/
 
         ............
         ............
 }
 
備考1 本サービス・コールでは,禁止要求のキューイングが行われません。このため,システム状態種別がディスパッチ禁止状態であった場合には,何も処理は行わず,エラーとしても扱いません。
備考2 本サービス・コールの発行により変更したディスパッチ禁止状態の解除は,本サービス・コールを発行したタスクがDORMANT状態へと遷移する以前に行う必要があります。
11.5.2 ディスパッチ禁止状態の解除
ディスパッチ禁止状態の解除は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- ena_dsp
システム状態種別をディスパッチ許可状態へと変更します。
これにより,dis_dspの発行により禁止されていたディスパッチ処理(タスクのスケジューリング処理)が許可されます。
なお,RI78V4では,dis_dspの発行から本サービス・コールが発行されるまでの間に“ディスパッチ処理を伴うサービス・コール(chg_prisig_semなど)”が発行された場合には,キュー操作,カウンタ操作などといった処理を行うだけであり,実際のディスパッチ処理は,本サービス・コールが発行されるまで遅延され,一括して行うようにしています。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ............
         ............
 
         dis_dsp ( );                    /*ディスパッチ禁止状態への移行*/
 
         ............                    /*ディスパッチ禁止状態*/
         ............
 
         ena_dsp ( );                    /*ディスパッチ禁止状態の解除*/
 
         ............
         ............
 }
 
備考 本サービス・コールでは,許可要求のキューイングが行われません。このため,システム状態種別がディスパッチ許可状態であった場合には,何も処理は行わず,エラーとしても扱いません。
11.6 スケジューリングの遅延
RI78V4では,非タスク(周期ハンドラ,割り込みハンドラなど)内の処理を高速に終了させる目的から,非タスク内の処理が完了するまでの間に“ディスパッチ処理(タスクのスケジューリング処理)を伴うサービス・コール(ichg_priisig_semなど)”が発行された場合には,キュー操作,カウンタ操作などといった処理を行うだけであり,実際のディスパッチ処理は,非タスクからの復帰命令(return命令の発行など)が発行されるまで遅延され,一括して行うようにしています。
以下に,非タスク内でディスパッチ処理を伴うサービス・コールを発行した際の処理の流れを示します。
図11-5  スケジューリングの遅延
11.7 アイドル・ルーチン
アイドル・ルーチンは,CPUが提供しているスタンバイ機能を有効活用(低消費電力システムの実現)するためにユーザ・オウン・コーディング部として切り出されたアイドル処理専用ルーチンであり,RI78V4のスケジューリング対象となるタスク(RUNNING状態,またはREADY状態のタスク)がシステム内に1つも存在しなくなった際にスケジューラから呼び出されます。
11.7.1 アイドル・ルーチンの登録
RI78V4では,アイドル・ルーチンの登録方法を“カーネル初期化部において静的に登録する”に限定しています。
したがって,RI78V4では,アイドル・ルーチンを処理プログラムからサービス・コールを発行するなどして動的に登録することはできません。
- 静的な登録
アイドル・ルーチンの静的な登録は,規定された関数名idle_handlerでアイドル・ルーチンを記述することにより実現されます。
RI78V4では,カーネル初期化部において,該当シンボル情報をもとにアイドル・ルーチンの登録処理を実行し,管理対象とします。
11.7.2 アイドル・ルーチンの登録解除
RI78V4では,カーネル初期化部において静的に登録されたアイドル・ルーチンを処理プログラムからサービス・コールを発行するなどして動的に登録解除することはできません。
11.7.3 アイドル・ルーチンの基本型
アイドル・ルーチンを記述する場合,引き数を持たないvoid型の関数(関数名:idle_handler)として記述します。
以下に,アイドル・ルーチンの基本型を示します。
【 C言語で記述する場合 】
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 idle_handler ( void )
 {
         ............                    /*アイドル・ルーチンの本体処理*/
         ............
 
         return;                         /*アイドル・ルーチンの終了*/
 }
 
【 アセンブリ言語で記述する場合】
 $INCLUDE        (kernel.inc)            ;標準ヘッダ・ファイルの定義
 $INCLUDE        (kernel_id.inc)         ;システム情報ヘッダ・ファイルの定義
 
         .PUBLIC  _idle_handler
 
         .SECTION .textf, TEXTF
 _idle_handler:
         ............                    ;アイドル・ルーチンの本体処理
         ............
 
         RET                             ;アイドル・ルーチンの終了
 
11.7.4 アイドル・ルーチン内での処理
RI78V4では,アイドル・ルーチンを“非タスク(タスクとは独立したもの)”として位置づけています。
また,RI78V4では,アイドル・ルーチンに制御を移す際に“独自の前処理”を,アイドル・ルーチンから制御を戻す際にも“独自の後処理”を実行しています。
このため,アイドル・ルーチンを記述する際には,以下に示す注意点があります。
- 記述方法
アイドル・ルーチンは,「11.7.3 アイドル・ルーチンの基本型」で示された関数形式でC言語,またはアセンブリ言語を用いて記述します。
- スタックの切り替え
RI78V4では,アイドル・ルーチンに制御を移す際に“システム・スタックへの切り替え処理”を,アイドル・ルーチンから制御を戻す際に“切り替え先の処理プログラム用スタック(システム・スタック,またはタスク・スタック)への切り替え処理”を実行しています。
したがって,ユーザは,アイドル・ルーチン内でスタックの切り替えに関する処理を記述する必要はありません。
- 割り込み状態
RI78V4では,アイドル・ルーチンに制御を移す際に“マスカブル割り込みの受け付けが許可された状態”としています。
したがって,ユーザは,アイドル・ルーチン内でマスカブル割り込みの受け付けに関する処理を記述する必要はありません。
- サービス・コールの発行
RI78V4では,アイドル・ルーチン内でサービス・コールを発行することを禁止しています。
以下に,アイドル・ルーチンとして実行すべき処理の一覧を示します。
- CPUが提供しているスタンバイ機能の有効活用