第3章  タスク管理機能


本章では,RI78V4が提供しているタスク管理機能について解説しています。

3.1 概  要

RI78V4におけるタスク管理機能では,タスクの状態を操作する機能のほかに,タスクの状態を参照する機能も提供しています。

3.2 タ ス ク

タスクは,他の処理プログラム(周期ハンドラ,割り込みハンドラなど)とは異なり,RI78V4が提供するサービス・コールを使用して明示的に操作しない限り実行されることのない処理プログラムであり,スケジューラから呼び出されます。

備考 タスクが処理を実行するうえで必要となる実行環境情報は,“タスク・コンテキスト”と呼ばれ,タスクの実行が切り替わる際には,RI78V4により現在実行中のタスクのタスク・コンテキストがセーブされ,次に実行されるタスクのタスク・コンテキストがロードされます。

3.2.1 タスクの状態

タスクは,処理を実行するうえで必要となるOS資源の獲得状況,および,事象発生の有無などにより,様々な状態へと遷移していきます。そこで,RI78V4では,各タスクが現在どのような状態にあるかを認識し,管理する必要があります。

なお,RI78V4では,タスクが取り得る状態を以下に示した6種類に分類し,管理しています。

図3−1  タスクの状態遷移



- DORMANT状態

タスクとして起動されていない状態,またはタスクとしての処理を終了した際に遷移する状態です。
なお,DORMANT状態のタスクは,RI78V4の管理下にありながらも,RI78V4のスケジューリング対象からは除外されています。


- READY状態

処理を実行するうえで必要となる準備は整っているが,より高い優先度,または同一優先度のタスクが処理を実行中のため,CPUの利用権が割り当てられるのを待っている状態です。

- RUNNING状態

CPUの利用権が割り当てられ,処理を実行中の状態です。
なお,RUNNING状態のタスクは,システム全体を通して同時に複数存在することはありません。


- WAITING状態

処理を実行するうえで必要となる条件が整わないため,処理の実行が中断した状態です。
なお,WAITING状態からの処理再開は,処理の実行が中断した箇所からとなります。したがって,処理を再開するうえで必要となる情報(タスク・コンテキストなど)は,中断直前の値が復元されます。
また,RI78V4では,要求条件の種類により,WAITING状態を以下に示す6種類に細分化し,管理しています。



表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を発行した際,対象メールボックスからメッセージを受信することができなかった場合に遷移する状態です。

メモリ・ブロック待ち状態

get_mpf,またはtget_mpfを発行した際,対象固定長メモリ・プールからメモリ・ブロックを獲得することができなかった場合に遷移する状態です。



- SUSPENDED状態

強制的に処理の実行を中断させられた状態です。
なお,SUSPENDED状態からの処理再開は,処理の実行が中断した箇所からの再開となります。したがって,処理を再開するうえで必要となる情報(タスク・コンテキストなど)は,中断直前の値が復元されます。


- WAITING-SUSPENDED状態

WAITING状態とSUSPENDED状態が複合した状態です。
なお,WAITING状態が解除された際にはSUSPENDED状態へ,SUSPENDED状態が解除された際にはWAITING状態へと遷移します。


3.2.2 タスクの優先度

タスクには,処理を実行するうえでの優先順位を決定する“優先度”が付与されています。

これにより,RI78V4では,実行可能な状態(RUNNING状態,および,READY状態)へと遷移している全タスクの中から“最も高い優先度(最高優先度)を持つタスク”を選び出し,CPUの利用権を与えます。

なお,RI78V4では,“優先度”を以下に示した2種類に分類し,管理しています。

- 初期優先度
タスクの生成時に設定される優先度です。


- 現在優先度
タスクがDORMANT状態からREADY状態へと遷移したのち,再びDORMANT状態へと遷移するまでの優先度の総称です。
したがって,タスクがDORMANT状態からREADY状態へと遷移した際の現在優先度は“初期優先度と同値”となり,chg_priichg_priの発行により優先度の変更が行われた際の現在優先度は“変更後優先度と同値”となります。



備考1 RI78V4におけるタスクの優先度は,その値が小さいほど,高い優先度であることを意味します。

備考2 システム内で利用可能な優先度は,優先度情報で指定された優先度範囲となります。

3.2.3 タスクの生成

RI78V4では,タスクの生成方法を“カーネル初期化部において静的に生成する”に限定しています。

したがって,RI78V4では,タスクを処理プログラムからサービス・コールを発行するなどして動的に生成することはできません。

- 静的な生成
タスクの静的な生成は,システム・コンフィギュレーション・ファイルにタスク情報を定義することにより実現されます。
RI78V4では,カーネル初期化部において,情報ファイルに格納されているデータをもとにタスクの生成処理を実行し,管理対象とします。



3.2.4 タスクの削除

RI78V4では,カーネル初期化部において静的に生成されたタスクを処理プログラムからサービス・コールを発行するなどして動的に削除することはできません。

3.2.5 タスクの基本型

タスクを記述する場合,VP_INT型の引き数を1つ持ったvoid型の関数(関数名:任意)として記述します。

なお,引き数exinfには“タスク情報で指定した拡張情報,またはsta_tskista_tsk発行時に指定した起動コード”が設定されます。

以下に,タスクの基本型を示します。

【 C言語で記述する場合 】

 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ............                    /*タスクの本体処理*/
         ............
 
         ext_tsk ( );                    /*自タスクの終了*/
 }
 

備考 #pragma rtos_task指令は,kernel_id.h内に定義されています(CF78V4が自動的に出力します)。そのため,kernel_id.hは必ずインクルードしてください。

【 アセンブリ言語で記述する場合 】

 $INCLUDE        (kernel.inc)            ;標準ヘッダ・ファイルの定義
 $INCLUDE        (kernel_id.inc)         ;システム情報ヘッダ・ファイルの定義
 
         .PUBLIC  _func_task
         .section .text, TEXT
 _func_task:
         PUSH    BC                      ;引き数exinfの上位2バイトをスタックに保存
         PUSH    AX                      ;引き数exinfの下位2バイトをスタックに保存
 
         ............                    ;タスクの本体処理
         ............
 
         BR      !!_ext_tsk              ;自タスクの終了
 

3.2.6 タスク内での処理

RI78V4では,タスクを切り替える際に“独自のディスパッチ処理(タスクのスケジューリング処理)”を実行しています。

このため,タスクを記述する際には,以下に示す注意点があります。

- 記述方法
タスクは,「3.2.5 タスクの基本型」で示された関数形式でC言語,またはアセンブリ言語を用いて記述します。


- スタックの切り替え
RI78V4では,タスクを切り替える際に“切り替え先のタスク用スタック(タスク・スタック)への切り替え処理”を実行しています。
したがって,ユーザは,タスク内でスタックの切り替えに関する処理を記述する必要はありません。



- 割り込み状態
RI78V4では,タスクをREADY状態からRUNNING状態へと遷移した際,“タスク情報において指定した初期割り込み状態”としています。
したがって,タスク内で割り込み状態を変更(禁止/許可)する場合は,__DI,__EI関数の呼び出しが必要となります。



- サービス・コールの発行
タスク内で発行可能なサービス・コールは,“タスクから発行可能なサービス・コール”に限られます。


備考 各サービス・コールの発行有効範囲についての詳細は,表12−8表12−17を参照してください。

3.3 タスクの起動

RI78V4では,タスクの起動において,“起動要求をキューイングする”,“起動要求をキューイングしない”の2種類のインタフェースを用意しています。

3.3.1 起動要求をキューイングする

タスクの起動(起動要求をキューイングする)は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- act_tskiact_tsk
パラメータtskidで指定されたタスクをDORMANT状態からREADY状態へと遷移させます。
これにより,対象タスクは,初期優先度に対応したレディ・キューの最後尾にキューイングされ,RI78V4のスケジューリング対象となります。
ただし,本サービス・コールを発行した際,対象タスクがDORMANT状態以外の状態へと遷移していた場合には,状態操作処理は実行されず,起動要求カウンタの加算処理(起動要求カウンタに0x1を加算)が実行されます。
以下に,本サービス・コールの記述例を示します。




 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         act_tsk ( tskid );              /*タスクの起動(起動要求をキューイングする)*/
 
         ............
         ............
 }
 

備考1 RI78V4が管理する起動要求カウンタは,7ビット幅で構成されています。このため,本サービス・コールの発行により,起動要求数が最大カウント値127を越える場合には,カウンタ操作処理は実行されず,戻り値として“E_QOVR”が返されます。

備考2 本サービス・コールの発行により起動されたタスクには,起動コードとして“拡張情報exinf”が引き渡されます。

3.3.2 起動要求をキューイングしない

タスクの起動(起動要求をキューイングしない)は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- sta_tskista_tsk
パラメータtskidで指定されたタスクをDORMANT状態からREADY状態へと遷移させます。
これにより,対象タスクは,初期優先度に対応したレディ・キューの最後尾にキューイングされ,RI78V4のスケジューリング対象となります。
以下に,本サービス・コールの記述例を示します。



 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
         VP_INT  stacd = 1048575;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         sta_tsk ( tskid, stacd );       /*タスクの起動(起動要求をキューイングしない)*/
 
         ............
         ............
 }
 

備考1 本サービス・コールでは,起動要求のキューイングが行われません。このため,対象タスクがDORMANT状態以外の場合には,状態操作処理は実行されず,戻り値として“E_OBJ”が返されます。

備考2 本サービス・コールの発行により起動されたタスクには,起動コードとして“stacd”が引き渡されます。

3.4 起動要求の解除

起動要求の解除は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- can_act
パラメータtskidで指定されたタスクにキューイングされている起動要求をすべて解除(起動要求カウンタに0x0を設定)します。
なお,本サービス・コールが正常終了した際には,戻り値として“解除した起動要求数”が返されます。
以下に,本サービス・コールの記述例を示します。



 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ER_UINT ercd;                   /*変数の宣言*/
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         ercd = can_act ( tskid );       /*起動要求の解除*/
 
         if ( ercd >= 0x0 ) {
                 ............            /*正常終了処理*/
                 ............
         }
 
         ............
         ............
 }
 

3.5 タスクの終了

RI78V4では,タスクの終了において,“自タスクの終了”,“他タスクの強制終了”の2種類のインタフェースを用意しています。

3.5.1 自タスクの終了

自タスクの終了は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- ext_tsk
自タスクをRUNNING状態からDORMANT状態へと遷移させます。
これにより,自タスクは,レディ・キューから外れ,RI78V4のスケジューリング対象から除外されます。
ただし,本サービス・コールを発行した際,自タスクに起動要求がキューイングされていた(起動要求カウンタが0x0以外であった)場合には,RUNNING状態からDORMANT状態への状態操作処理,および,起床要求カウンタの減算処理(起床要求カウンタから0x1を減算)を行ったのち,DORMANT状態からREADY状態への状態操作処理もあわせて実行されます。
以下に,本サービス・コールの記述例を示します。




 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ............
         ............
 
         ext_tsk ( );                    /*自タスクの終了*/
 }
 

備考1 本サービス・コールでは,自タスクがsig_semget_mpfなどの発行により獲得したOS資源の返却は行いません。したがって,獲得中のOS資源については,本サービス・コールを発行する以前に返却する必要があります。

備考2 本サービス・コールでは,RUNNING状態からDORMANT状態への状態操作処理を実行する際に,

- 優先度(現在優先度)

- 起床要求数

- サスペンド要求数

- 割り込み状態

といった情報をタスクの生成時に設定される値で初期化しています。

備考3 タスク内でreturn命令を記述した場合,本サービス・コールと同様の動作が実行されます。

備考4 RI78V4では,“自タスクの終了”としてreturn命令を記述した方がコード効率が良くなります。

3.5.2 他タスクの強制終了

他タスクの強制終了は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- ter_tsk
パラメータtskidで指定されたタスクを強制的にDORMANT状態へと遷移させます。
これにより,対象タスクは,RI78V4のスケジューリング対象から除外されます。
ただし,本サービス・コールを発行した際,対象タスクに起動要求がキューイングされていた(起動要求カウンタが0x0以外であった)場合には,DORMANT状態への状態操作処理,および,起床要求カウンタの減算処理(起床要求カウンタから0x1を減算)を行ったのち,DORMANT状態からREADY状態への状態操作処理もあわせて実行されます。
以下に,本サービス・コールの記述例を示します。




 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
 
         ............
         ............
 
         ter_tsk ( tskid );              /*他タスクの強制終了*/
 
         ............
         ............
 }
 

備考1 本サービス・コールでは,対象タスクがsig_semget_mpfなどの発行により獲得したOS資源の返却は行いません。したがって,獲得中のOS資源については,本サービス・コールを発行する以前に返却する必要があります。

備考2 本サービス・コールでは,DORMANT状態への状態操作処理を実行する際に,

- 優先度(現在優先度)

- 起床要求数

- サスペンド要求数

- 割り込み状態

といった情報をタスクの生成時に設定される値で初期化しています。

3.6 優先度の変更

優先度の変更は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- chg_priichg_pri
パラメータtskidで指定されたタスクの優先度(現在優先度)をパラメータtskpriで指定された値に変更します。
以下に,本サービス・コールの記述例を示します。


 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
         PRI     tskpri = 15;            /*変数の宣言,初期化*/
 
         ............
         ............
 
         chg_pri ( tskid, tskpri );      /*優先度の変更*/
 
         ............
         ............
 }
 

備考 本サービス・コールを発行した際,対象タスクがRUNNING状態,またはREADY状態であった場合には,優先度の変更処理を実行したのち,パラメータtskpriで指定された優先度に対応したレディ・キューの最後尾にキューイングし直す処理もあわせて実行されます。

3.7 タスクの状態参照

タスクの状態参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。

- ref_tsk
パラメータtskidで指定されたタスクのタスク状態情報(現在状態など)をパラメータpk_rtskで指定された領域に格納します。
以下に,本サービス・コールの記述例を示します。


 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 func_task ( VP_INT exinf )
 {
         ID      tskid = ID_tskA;        /*変数の宣言,初期化*/
         T_RTSK  pk_rtsk;                /*データ構造体の宣言*/
         STAT    tskstat;                /*変数の宣言*/
         PRI     tskpri;                 /*変数の宣言*/
         STAT    tskwait;                /*変数の宣言*/
         ID      wobjid;                 /*変数の宣言*/
         UINT    actcnt;                 /*変数の宣言*/
         UINT    wupcnt;                 /*変数の宣言*/
         UINT    suscnt;                 /*変数の宣言*/
 
         ............
         ............
 
         ref_tsk ( tskid, &pk_rtsk );    /*タスクの状態参照*/
 
         tskstat = pk_rtsk.tskstat;      /*現在状態の獲得*/
         tskpri = pk_rtsk.tskpri;        /*現在優先度の獲得*/
         tskwait = pk_rtsk.tskwait;      /*待ち要因の獲得*/
         wobjid = pk_rtsk.wobjid;        /*管理オブジェクトのIDの獲得*/
         actcnt = pk_rtsk.actcnt;        /*起動要求数の獲得*/
         wupcnt = pk_rtsk.wupcnt;        /*起床要求数の獲得*/
         suscnt = pk_rtsk.suscnt;        /*サスペンド要求数の獲得*/
 
         ............
         ............
 }
 

備考 タスク状態情報T_RTSKについての詳細は,「12.5.1 タスク状態情報」を参照してください。