Everything

第3章  タスク管理機能


本章では,RI850V4が提供しているタスク管理機能について解説しています。
3.1 概  要
RI850V4におけるタスク管理機能では,タスクの生成/起動/終了などといったタスクの状態を操作する機能のほかに,優先度の参照,タスク詳細情報の参照などといったタスクの状態を参照する機能も提供しています。
3.2 タ ス ク
タスクは,他の処理プログラム(周期ハンドラ,割り込みハンドラなど)とは異なり,RI850V4が提供するサービス・コールを使用して明示的に操作しない限り実行されることのない処理プログラムです。
なお,RI850V4では,タスクを管理するに当たり,タスクと一対一に対応した管理オブジェクト(タスク管理ブロック)を用いることにより,タスクが取り得る状態の管理,およびタスク自体の管理を行っています。
備考 タスクが処理を実行するうえで必要となるプログラム・カウンタ,汎用レジスタなどの実行環境情報は,“タスク・コンテキスト”と呼ばれ,タスクの実行が切り替わる際には,現在実行中のタスクのタスク・コンテキストがセーブされ,次に実行されるタスクのタスク・コンテキストがロードされます。
3.2.1 タスクの状態
タスクは,処理を実行するうえで必要となる資源の獲得状況,および事象発生の有無などにより,さまざまな状態へと遷移していきます。そこで,RI850V4では,各タスクが現在どのような状態にあるかを認識し,管理する必要があります。
なお,RI850V4では,タスクが取り得る状態を以下に示した6種類に分類し,管理しています。
図3-1 
タスクの状態遷移
1 ) DORMANT状態
タスクとして起動されていない状態,またはタスクとしての処理を終了した際に遷移する状態です。
なお,DORMANT状態のタスクは,RI850V4の管理下にありながらも,RI850V4のスケジューリング対象からは除外されています。
2 ) READY状態
処理を実行するうえで必要となる準備は整っているが,より高い優先度(同一優先度の場合もある)を持つタスクが処理を実行中のため,CPUの利用権が割り当てられるのを待っている状態です。
3 ) RUNNING状態
CPUの利用権が割り当てられ,処理を実行中の状態です。
なお,RUNNING状態のタスクは,システム全体を通して同時に複数存在することはありません。
4 ) WAITING状態
処理を実行するうえで必要となる条件が整わないため,処理の実行が中断した状態です。
なお,WAITING状態からの処理再開は,処理の実行が中断した箇所からとなります。したがって,処理を再開するうえで必要となる情報(タスク・コンテキスト:プログラム・カウンタ,汎用レジスタなど)は,中断直前の値が復元されます。
また,RI850V4では,要求条件の種類により,WAITING状態を以下に示す10状態に細分化し,管理しています。
表3-1  WAITING状態の種類
状態種別
意味
起床待ち状態
slp_tsk,またはtslp_tskを発行した際,自タスクの起床要求カウンタ(起床要求の発行回数を保持)が0x0の場合に遷移する状態です。
時間経過待ち状態
dly_tskを発行した際に遷移する状態です。
資源獲得待ち状態
wai_sem,またはtwai_semを発行した際,対象セマフォから資源を獲得することができなかった場合に遷移する状態です。
イベントフラグ待ち状態
wai_flg,またはtwai_flgを発行した際,対象イベントフラグのビット・パターンが要求条件を満足していなかった場合に遷移する状態です。
データ送信待ち状態
snd_dtq,またはtsnd_dtqを発行した際,対象データ・キューのデータ・キュー領域にデータを書き込むことができなかった場合に遷移する状態です。
データ受信待ち状態
rcv_dtq,またはtrcv_dtqを発行した際,対象データ・キューからデータを受信することができなかった場合に遷移する状態です。
メッセージ受信待ち状態
rcv_mbx,またはtrcv_mbxを発行した際,対象メールボックスからメッセージを受信することができなかった場合に遷移する状態です。
ミューテックス待ち状態
loc_mtx,またはtloc_mtxを発行した際,対象ミューテックスをロックすることができなかった場合に遷移する状態です。
固定長メモリ・ブロック待ち状態
get_mpf,またはtget_mpfを発行した際,対象固定長メモリ・プールから固定長メモリ・ブロックを獲得することができなかった場合に遷移する状態です。
可変長メモリ・ブロック待ち状態
get_mpl,またはtget_mplを発行した際,対象可変長メモリ・プールから可変長メモリ・ブロックを獲得することができなかった場合に遷移する状態です。

5 ) SUSPENDED状態
強制的に処理の実行を中断させられた状態です。
なお,SUSPENDED状態からの処理再開は,処理の実行が中断した箇所からの再開となります。したがって,処理を再開するうえで必要となる情報(タスク・コンテキスト:プログラム・カウンタ,汎用レジスタなど)は,中断直前の値が復元されます。
6 ) WAITING-SUSPENDED状態
WAITING状態とSUSPENDED状態が複合した状態です。
なお,WAITING状態が解除された際にはSUSPENDED状態へ,SUSPENDED状態が解除された際にはWAITING状態へと遷移します。
3.2.2 タスクの優先度
タスクには,処理を実行するうえでの優先順位を決定する優先度が付けられています。そこで,RI850V4のスケジューラでは,実行可能な状態(RUNNING状態,およびREADY状態)にあるタスクの優先度を参照し,その中から最も高い優先度(最高優先度)を持つタスクを選び出し,CPUの利用権を与えています。
なお,RI850V4では,“タスクの優先度”を以下に示した2種類に分類し,管理しています。
- 初期優先度
タスクの生成時に設定される優先度です。したがって,タスクがDORMANT状態からREADY状態へと遷移した直後の優先度(スケジューラが参照する優先度)は,初期優先度となります。
- 現在優先度
タスクを起動後,RI850V4が各種操作(タスクのスケジューリング,優先度順の待ちキューへのキューイング,タスクの優先度継承)を行う際に参照する優先度です。
備考1 RI850V4におけるタスクの優先度は,その値が小さいほど,高い優先度であることを意味します。
備考2 システム内で利用可能な優先度の範囲については,システム・コンフィギュレーション・ファイル作成時に基本情報最大タスク優先度maxtpri)を定義することにより実現されます。
3.2.3 タスクの基本型
タスクを記述する場合,VP_INT型の引き数を1つ持ったvoid型の関数として記述します。
なお,引き数exinfには“タスクの拡張情報”が設定されます。
以下に,タスクをC言語で記述する場合の基本型を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ............
         ............
 
         ext_tsk ( );                    /*タスクの終了*/
 }

備考1 sta_tsk,またはista_tskの発行によりDORMANT状態からREADY状態へと遷移した場合,引き数exinfには“sta_tsk,またはista_tsk発行時に指定した拡張情報”が設定されます。
備考2 タスク内でreturn命令が発行された場合,ext_tskと同等の処理が実行されます。
備考3 タスクの拡張情報についての詳細は,「3.4 タスクの起動」を参照してください。
3.2.4 タスク内での処理
RI850V4では,タスクを切り替える際,独自のスケジューリング処理を行っています。このため,タスクを記述する際には,以下に示す注意点があります。
- 記述方法
C言語,またはアセンブリ言語で記述します。
C言語で記述するときは通常の関数と同様に記述することができます。
アセンブリ言語で記述するときは使用するコンパイラの呼び出し規約にのっとって作成してください。
- スタックの切り替え
RI850V4では,タスクを切り替える際,タスク情報において指定されたタスク・スタックへの切り替え処理を行っています。したがって,タスク内でスタックの切り替えに関する記述を行う必要がありません。
- サービス・コールの発行
タスクでは,“タスク内から発行可能なサービス・コール”のみが発行可能となります。
備考 各サービス・コールの発行有効範囲についての詳細は,表16-1表16-12を参照してください。
- EIレベル・マスカブル割り込みの受け付け状態
RI850V4では,タスクを起動する際,プライオリティ・マスク・レジスタPMRのPMnビットに対する操作,およびプログラム・ステータス・ワードPSWのIDビットに対する操作を行い,システム・コンフィギュレーション作成時に属性(記述言語,初期起動状態など)tskatrで指定された割り込み状態としています。
3.3 タスクの生成
RI850V4では,タスクの静的な生成のみサポートしています。処理プログラムからサービス・コールを発行して動的に生成することはできません。
タスクの静的生成とは,システム・コンフィギュレーション・ファイルで静的API“CRE_TSK”を使用してタスクを定義することをいいます。
静的API“CRE_TSK”の詳細は,「17.5.1 タスク情報」を参照してください。
3.4 タスクの起動
RI850V4では,タスクの起動において,“起動要求をキューイングする”,“起動要求をキューイングしない”の2種類のインタフェースを用意しています。
なお,RI850V4では,コンフィギュレーション時にタスク情報で指定した拡張情報,およびサービス・コールsta_tskista_tsk発行時に第2パラメータstacdで指定した値を“タスクの拡張情報”と呼んでいます。
3.4.1 起動要求をキューイングする起動
タスクの起動(起動要求をキューイングする)は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- act_tskiact_tsk
パラメータtskidで指定されたタスクをDORMANT状態からREADY状態へと遷移させたのち,初期優先度itskpriに応じたレディ・キューの最後尾にキューイングします。これにより,対象タスクは,RI850V4のスケジューリング対象となります。
ただし,本サービス・コールを発行した際,対象タスクがDORMANT状態以外の場合には,対象タスクのキューイング処理,および状態操作処理は行わず,対象タスクに起動要求をキューイング(起動要求カウンタに0x1を加算)しています。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         act_tsk ( tskid );              /*タスクの起動(起動要求をキューイングする)*/
 
         ............
         ............
 }

備考1 RI850V4が管理する起動要求カウンタは,7ビット幅で構成されています。このため,本サービス・コールでは,起動要求数が127回を越えるような場合には,起動要求の発行起動要求のキューイング(起動要求カウンタの加算処理)は行わず,戻り値としてE_QOVRを返します。
備考2 本サービス・コールの発行により起動されたタスクには,拡張情報として“タスク情報で指定した拡張情報”が渡されます。
3.4.2 起動要求をキューイングしない起動
タスクの起動(起動要求をキューイングしない)は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- sta_tskista_tsk
パラメータtskidで指定されたタスクをDORMANT状態からREADY状態へと遷移させたのち,初期優先度itskpriに応じたレディ・キューの最後尾にキューイングします。これにより,対象タスクは,RI850V4のスケジューリング対象となります。
ただし,本サービス・コールでは,起動要求のキューイングが行われません。このため,対象タスクがDORMANT状態以外の場合には,対象タスクの状態操作処理は行わず,戻り値としてE_OBJを返します。
なお,パラメータstacdには,対象タスクに引き渡す拡張情報を指定します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
         VP_INT  stacd = 123;            /*変数の宣言,初期化*/
 
         ............
         ............
 
         sta_tsk ( tskid, stacd );       /*タスクの起動(起動要求をキューイングしない)*/
 
         ............
         ............
 }

3.5 起動要求のキューイング解除
起動要求のキューイング解除は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- can_actican_act
パラメータtskidで指定されたタスクにキューイングされている起動要求をすべて解除(起動要求カウンタに0x0を設定)します。
なお,正常終了時は戻り値として本サービス・コールの発行により解除した起動要求数を返します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ER_UINT ercd;                   /*変数の宣言*/
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         ercd = can_act ( tskid );       /*起動要求のキューイング解除*/
 
         if ( ercd >= 0x0 ) {
                 ............            /*正常終了処理*/
                 ............
         }
 
         ............
         ............
 }

備考 本サービス・コールでは,状態操作処理は行わず,起動要求カウンタの設定処理のみを行います。
したがって,READY状態などからDORMANT状態に遷移することはありません。
3.6 タスクの終了
3.6.1 自タスクの終了
自タスクの終了,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- ext_tsk
自タスクをRUNNING状態からDORMANT状態へと遷移させ,レディ・キューから外します。これにより,自タスクは,RI850V4のスケジューリング対象から除外されます。
ただし,本サービス・コールを発行した際,自タスクの起動要求がキューイングされていた(起動要求カウンタが0x0以外の値であった)場合には,自タスクの状態操作(DORMANT状態への状態遷移処理)を行ったのち,自タスクの起動(DORMANT状態からREADY状態への状態遷移処理)もあわせて行われます。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ............
         ............
 
         ext_tsk ( );                    /*タスクの終了*/
 }

備考1 本サービス・コールでは,自タスクの状態操作(DORMANT状態への状態遷移処理)を行う際に,
- 優先度(現在優先度)
- 起床要求数
- サスペンド要求数
- 割り込み状態
といった情報をタスク生成時に設定される値で初期化しています。
また,自タスクがミューテックスをロックしていた場合には,ロック状態の解除(unl_mtxと同等の処理)もあわせて行われます。
備考2 タスク内でreturn命令が発行された場合,本サービス・コールと同等の処理が実行されます。
3.6.2 タスクの強制終了
タスクの強制終了,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- ter_tsk
パラメータtskidで指定されたタスクを強制的にDORMANT状態へと遷移させます。これにより,対象タスクは,RI850V4のスケジューリング対象から除外されます。
ただし,本サービス・コールを発行した際,対象タスクの起動要求がキューイングされていた(起動要求カウンタが0x0以外の値であった)場合には,対象タスクの状態操作(DORMANT状態への状態遷移処理)を行ったのち,対象タスクの起動(DORMANT状態からREADY状態への状態遷移処理)もあわせて行われます。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         ter_tsk ( tskid );              /*タスクの強制終了*/
 
         ............
         ............
 }

備考 本サービス・コールでは,対象タスクの状態操作(DORMANT状態への状態遷移処理)を行う際に,
- 優先度(現在優先度)
- 起床要求数
- サスペンド要求数
- 割り込み状態
といった情報をタスク生成時に設定される値で初期化しています。
また,対象タスクがミューテックスをロックしていた場合には,ロック状態の解除(unl_mtxと同等の処理)もあわせて行われます。
3.7 タスク優先度の変更
タスク優先度の変更は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- chg_priichg_pri
パラメータtskidで指定されたタスクの優先度(現在優先度)をパラメータtskpriで指定された値に変更します。
対象タスクがRUNNING状態,またはREADY状態であった場合には,優先度を変更したのち,対象タスクをパラメータtskpriで指定された優先度に応じたレディ・キューの最後尾につなぎかえます。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
         PRI     tskpri = 9;             /*変数の宣言,初期化*/
 
         ............
         ............
 
         chg_pri ( tskid, tskpri );      /*タスク優先度の変更*/
 
         ............
         ............
 }

備考 対象タスクが何らかの待ちキューに優先度順でキューイングされていた場合,本サービス・コールの発行により,待ち順序が変わることがあります。
例 セマフォの待ちキューに3つのタスク(タスクA:優先度10,タスクB:優先度11,タスクC:優先度12)が優先度順でキューイングされているとき,タスクBの優先度を11から9に変更した場合,待ちキューの待ち順序は,以下のように変更されます。
 
3.8 タスク優先度の参照
タスク優先度の参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- get_priiget_pri
パラメータtskidで指定されたタスクの現在優先度をパラメータp_tskpriで指定された領域に格納します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
         PRI     p_tskpri;               /*変数の宣言*/
 
         ............
         ............
 
         get_pri ( tskid, &p_tskpri );   /*タスク優先度の参照*/
 
         ............
         ............
 }

3.9 タスク状態の参照
3.9.1 タスク詳細情報の参照
タスク詳細情報の参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- ref_tskiref_tsk
パラメータtskidで指定されたタスクのタスク詳細情報(現在状態,現在優先度など)をパラメータpk_rtskで指定された領域に格納します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
         T_RTSK  pk_rtsk;                /*データ構造体の宣言*/
         STAT    tskstat;                /*変数の宣言*/
         PRI     tskpri;                 /*変数の宣言*/
         STAT    tskwait;                /*変数の宣言*/
         ID      wobjid;                 /*変数の宣言*/
         TMO     lefttmo;                /*変数の宣言*/
         UINT    actcnt;                 /*変数の宣言*/
         UINT    wupcnt;                 /*変数の宣言*/
         UINT    suscnt;                 /*変数の宣言*/
         ATR     tskatr;                 /*変数の宣言*/
         PRI     itskpri;                /*変数の宣言*/
 
         ............
         ............
 
         ref_tsk ( tskid, &pk_rtsk );    /*タスク詳細情報の参照*/
 
         tskstat = pk_rtsk.tskstat;      /*現在状態の獲得*/
         tskpri = pk_rtsk.tskpri;        /*現在優先度の獲得*/
         tskwait = pk_rtsk.tskwait;      /*待ち要因の獲得*/
         wobjid = pk_rtsk.wobjid;        /*管理オブジェクトのIDの獲得*/
         lefttmo = pk_rtsk.lefttmo;      /*残り時間の獲得*/
         actcnt = pk_rtsk.actcnt;        /*起動要求数の獲得*/
         wupcnt = pk_rtsk.wupcnt;        /*起床要求数の獲得*/
         suscnt = pk_rtsk.suscnt;        /*サスペンド要求数の獲得*/
         tskatr = pk_rtsk.tskatr;        /*属性の獲得*/
         itskpri = pk_rtsk.itskpri;      /*初期優先度の獲得*/
 
         ............
         ............
 }

備考 タスク詳細情報T_RTSKについての詳細は,「15.2.1 タスク詳細情報」を参照してください。
3.9.2 タスク基本情報の参照
タスク基本情報の参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
- ref_tstiref_tst
パラメータtskidで指定されたタスクのタスク基本情報(現在状態,待ち要因)をパラメータpk_rtstで指定された領域に格納します。
タスク情報のうち,現在状態,待ち要因のみを参照したい場合に使用します。
取得する情報が少ないのでref_tskiref_tskより高速に応答します。
以下に,本サービス・コールの記述例を示します。
 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 task ( VP_INT exinf )
 {
         ID      tskid = ID_TSK1;        /*変数の宣言,初期化*/
         T_RTST  pk_rtst;                /*データ構造体の宣言*/
         STAT    tskstat;                /*変数の宣言*/
         STAT    tskwait;                /*変数の宣言*/
 
         ............
         ............
 
         ref_tst ( tskid, &pk_rtst );    /*タスク基本情報の参照*/
 
         tskstat = pk_rtst.tskstat;      /*現在状態の獲得*/
         tskwait = pk_rtst.tskwait;      /*待ち要因の獲得*/
 
         ............
         ............
 }

備考 タスク基本情報T_RTSTについての詳細は,「15.2.2 タスク基本情報」を参照してください。
3.10 省メモリ化
RI850V4では,タスクが処理を実行する際に必要となるタスク・スタックのサイズを削減する方法として,プリエンプト禁止の手段を提供しています。
3.10.1 プリエンプト禁止
RI850V4では,システム・コンフィギュレーション・ファイル作成時にタスク情報として「属性:プリエンプトの受け付け状態TA_DISPREEMPT」を定義することができます。
この属性が定義されたタスクでは,「非タスクから発行されたスケジューリング要求を無視して処理を続行する」といった動作を行うため,1タスク当たり44バイトの管理領域を削減することが可能となります。