Everything

第9章  システム状態管理機能


本章では,RI600V4が提供しているシステム状態管理機能について解説しています。
9.1 概  要
RI600V4におけるシステム状態管理機能では,タスクの優先順位の回転,ディスパッチ禁止状態への遷移などといったシステムの状態を操作する機能のほかに,コンテキスト種別の参照,CPUロック状態の参照などといったシステムの状態を参照する機能も提供しています。
なお,システム・ダウン(vsys_dwnivsys_dwn)については「第13章 システム・ダウン」,RI600V4の起動(vsta_knlivsta_knl)については「第16章 システム初期化処理」を参照してください。
9.2 タスクの優先順位の回転
タスクの優先順位の回転は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- rot_rdqirot_rdq
パラメータtskpriで指定された優先度に対応したレディ・キューの先頭タスクを最後尾につなぎかえ,タスクの実行順序を明示的に変更します。
図9-1  タスク優先順位の回転
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void cychdr ( VP_INT exinf )       /*周期ハンドラ*/
 {
         PRI     tskpri = 8;             /*変数の宣言,初期化*/
 
         ............
         ............
 
         irot_rdq ( tskpri );            /*タスクの優先順位の回転*/
 
         ............
         ............
 
         return;                         /*周期ハンドラの終了*/
 }

備考1 本サービス・コールでは,レディ・キューの対象優先度にタスクが1つもキューイングされていなかった場合には,何も処理は行わず,エラーとしても扱いません。
備考2 本サービス・コールを周期ハンドラなどから一定周期で発行することにより,ラウンドロビン・スケジューリングを実現することができます。
備考3 RI600V4におけるレディ・キューは,優先度をキーとしたハッシュ・テーブルであり,実行可能な状態(RUNNING状態またはREADY状態)へと遷移したタスクがFIFO順でキューイングされます。このため,スケジューラは,起動された際にレディ・キューの優先度高位から検出処理を実行し,キューイングされているタスクを検出した場合には,該当優先度の先頭タスクにCPUの利用権を与えることにより,RI600V4のスケジューリング方式(優先度方式,FCFS方式)を実現しています。
備考4 tskpriTPRI_SELFを指定すると,自タスクのベース優先度を対象とします。
ミューテックスをロック中のタスクの現在優先度は,ベース優先度と異なる場合があります。この場合,そのタスクが本サービス・コールでtskpriTPRI_SELFを指定しても,自タスクが属する現在優先度のレディ・キューを回転することはできません。
9.3 RUNNING状態のタスクの参照
RUNNING状態のタスクの参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- get_tidiget_tid
RUNNING状態のタスクのIDをパラメータp_tskidで指定された領域に格納します。
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void inthdr ( void )                    /*割り込みハンドラ*/
 {
         ID      p_tskid;                /*変数の宣言*/
 
         ............
         ............
 
         iget_tid ( &p_tskid );          /*RUNNING状態のタスクの参照*/
 
         ............
         ............
 
         return;                         /*割り込みハンドラの終了*/
 }

備考 本サービス・コールでは,RUNNING状態へと遷移しているタスクが存在しなかった場合には,パラメータp_tskidで指定された領域にTSK_NONEを格納しています。
9.4 CPUロック状態への移行と解除
CPUロック状態では,タスクのスケジューリングは禁止され,カーネル管理割り込みもマスクされます。つまり,カーネル管理外割り込みハンドラを除くすべての処理プログラムに対して,排他的に処理を行うことができます。
以下のサービス・コールによって,CPUロック状態へ移行します。
- loc_cpuiloc_cpu
システムをCPUロック状態へ移行させます。
ただし,CPUロック状態では,発行可能なサービス・コールは以下に制限されます。
 
発行可能なサービス・コール
機能概要
自タスクの終了(CPUロック状態は解除されます)
CPUロック状態への移行
CPUロック状態の解除
CPUロック状態の参照
ディスパッチ禁止状態の参照
コンテキスト種別の参照
ディスパッチ保留状態の参照
システム・ダウン

CPUロック状態は,以下のサービス・コールおよびext_tskによって解除されます。
- unl_cpuiunl_cpu
システムをCPUロック解除状態へ移行させます。
以下に,“CPUロック状態”を利用した際の処理の流れを示します。
図9-2  CPUロック状態
以下に,CPUロック状態への移行とその解除の記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void task ( VP_INT exinf )
 {
         ............
         ............
 
         loc_cpu ( );                    /*CPUロック状態への移行*/
 
         ............                    /*CPUロック状態*/
         ............
 
         unl_cpu ( );                    /*CPUロック状態の解除*/
 
         ............
         ............
 }

備考1 CPUロック状態の解除は,loc_cpuまたはiloc_cpuを発行した処理プログラムが終了する以前に行う必要があります。
備考2 loc_cpuiloc_cpuでは,ロック要求のキューイングが行われません。このため,すでにCPUロック状態の場合には,何も処理は行わず,エラーとしても扱いません。
備考3 unl_cpuiunl_cpuでは,解除要求のキューイングが行われません。このため,すでに非CPUロック状態の場合には,何も処理は行わず,エラーとしても扱いません。
備考4 unl_cpuiunl_cpuでは,dis_dspによるディスパッチ禁止状態は解除されません。
備考5 CPUロック状態の期間は基本クロック用タイマ割り込みはマスクされます。このため,CPUロック状態の期間が長くなると,時間管理機能で扱う時間が遅れる場合があります。
備考6 “カーネル管理割り込み”については,「10.1 割り込みの種類」を参照してください。
9.5 CPUロック状態の参照
複数のタスクやハンドラから呼ばれる関数では,現在のCPUロック状態を参照したい場合があります。このような場合には,sns_locを使用します。
- sns_loc
本サービス・コールは,CPUロック状態か否かを調べます。本サービス・コールは,戻り値として,CPUロック状態の場合はTRUE,CPUロック解除状態の場合はFALSEを返します。
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void CommonFunc ( void );
 void CommonFunc ( void )
 {
         BOOL ercd;                      /*変数の宣言*/
 
         ............
         ............
 
         ercd = sns_loc ( );             /*CPUロック状態の参照*/
 
         if ( ercd == TRUE ) {
                 ............            /*CPUロック状態*/
                 ............
         } else if ( ercd == FALSE ) {
                 ............            /*非CPUロック状態*/
                 ............
         }
 
         ............
         ............
 }

9.6 ディスパッチ禁止状態への移行と解除
ディスパッチ禁止状態では,タスクのスケジューリングが禁止されるため,他のタスクに対して排他的に処理を行うことができます。
以下のサービス・コールによって,ディスパッチ禁止状態へ移行します。また,chg_imsによって割り込みマスク(PSW.IPL)を0以外に変更したときにも,ディスパッチ禁止状態へ移行します。
- dis_dsp
システムをディスパッチ禁止状態へ移行させます。
ディスパッチ禁止状態は,以下のサービス・コール,ext_tsk,およびchg_imsによって割り込みマスク(PSW.IPL)を0に変更したときに解除されます。
- ena_dsp
システムをディスパッチ許可状態へ移行せます。
以下に,“ディスパッチ禁止状態”を利用した際の処理の流れを示します。
図9-3  ディスパッチ禁止状態
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void task ( VP_INT exinf )
 {
         ............
         ............
 
         dis_dsp ( );                    /*ディスパッチ禁止状態への移行*/
 
         ............                    /*ディスパッチ禁止状態*/
         ............
 
         ena_dsp ( );                    /*ディスパッチ禁止状態の解除*/
 
         ............
         ............
 }

備考1 ディスパッチ禁止状態の解除は,dis_dspを発行したタスクがDORMANT状態へ遷移する以前に行う必要があります。
備考2 dis_dspでは,禁止要求のキューイングが行われません。このため,すでにディスパッチ禁止状態の場合には,何も処理は行わず,エラーとしても扱いません。
備考3 ena_dspでは,許可要求のキューイングが行われません。このため,すでにディスパッチ許可状態の場合には,何も処理は行わず,エラーとしても扱いません。
備考4 ディスパッチ禁止状態の間に“自タスクを状態遷移させる可能性のあるサービス・コール(wai_semwai_flgなど)”を発行した場合には,要求条件の即時成立/不成立を問わず,戻り値としてE_CTXを返します。
9.7 ディスパッチ禁止状態の参照
複数のタスクやハンドラから呼ばれる関数では,現在のディスパッチ禁止状態を参照したい場合があります。このような場合には,sns_dspを使用します。
- sns_dsp
本サービス・コールは,ディスパッチ禁止状態か否かを調べます。本サービス・コールは,戻り値として,ディスパッチ禁止状態の場合はTRUE,ディスパッチ許可状態の場合はFALSEを返します。
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void CommonFunc ( void );
 void CommonFunc ( void )
 {
         BOOL ercd;                      /*変数の宣言*/
 
         ............
         ............
 
         ercd = sns_dsp ( );             /*ディスパッチ禁止状態の参照*/
 
         if ( ercd == TRUE ) {
                 ............            /*ディスパッチ禁止状態*/
                 ............
         } else if ( ercd == FALSE ) {
                 ............            /*ディスパッチ許可状態*/
                 ............
         }
 
         ............
         ............
 }

9.8 コンテキスト種別の参照
複数のタスクやハンドラから呼ばれる関数では,現在のコンテキスト種別を参照したい場合があります。このような場合には,sns_ctxを使用します。
- sns_ctx
本サービス・コールは,本サービス・コールを発行した処理プログラムのコンテキスト種別を調べます。本サービス・コールは,戻り値として,非タスク・コンテキストの場合はTRUE,タスク・コンテキストの場合はFALSEを返します。
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void CommonFunc ( void );
 void CommonFunc ( void )
 {
         BOOL ercd;                      /*変数の宣言*/
 
         ............
         ............
 
         ercd = sns_ctx ( );             /*コンテキスト種別の参照*/
 
         if ( ercd == TRUE ) {
                 ............            /*非タスク・コンテキスト処理*/
                 ............
         } else if ( ercd == FALSE ) {
                 ............            /*タスク・コンテキスト処理*/
                 ............
         }
 
         ............
         ............
 }

9.9 ディスパッチ保留状態の参照
以下のいずれかの条件を満たすときをディスパッチ保留状態と呼びます。
- ディスパッチ禁止状態
- CPUロック状態
- ハンドラなど,PSW.IPL>0の状態
複数のタスクやハンドラから呼ばれる関数では,現在のディスパッチ保留を参照したい場合があります。このような場合には,sns_dpnを使用します。
- sns_dpn
本サービス・コールは,ディスパッチ保留状態か否かを調べます。本サービス・コールは,戻り値として,ディスパッチ保留状態の場合はTRUE,ディスパッチ保留状態でない場合はFALSEを返します。
以下に,本サービス・コールの記述例を示します。
 #include        "kernel.h"              /*標準ヘッダ・ファイルの定義*/
 #include        "kernel_id.h"           /*cfg600が出力するヘッダ・ファイルの定義*/
 
 void CommonFunc ( void );
 void CommonFunc ( void )
 {
         BOOL ercd;                      /*変数の宣言*/
 
         ............
         ............
 
         ercd = sns_dpn ( );             /*ディスパッチ保留状態の参照*/
 
         if ( ercd == TRUE ) {
                 ............            /*ディスパッチ保留状態*/
                 ............
         } else if ( ercd == FALSE ) {
                 ............            /*非ディスパッチ保留状態*/
                 ............
         }
 
         ............
         ............
 }