第4章 タスク管理機能
本章では,RI600PXが提供しているタスク管理機能について解説しています。
RI600PXにおけるタスク管理機能では,タスクの生成/起動/終了などといったタスクの状態を操作する機能のほかに,優先度の参照,タスク詳細情報の参照などといったタスクの状態を参照する機能も提供しています。
タスクは,他処理プログラム(割り込みハンドラ,周期ハンドラ,およびアラーム・ハンドラ)とは異なり,RI600PXが提供するサービス・コールを使用して明示的に操作しないかぎり実行されることのない処理プログラムです。
備考 タスクが処理を実行するうえで必要となるプログラム・カウンタ,汎用レジスタなどの実行環境情報は,“タスク・コンテキスト”と呼ばれ,タスクの実行が切り替わる際には,現在実行中のタスクのタスク・コンテキストがセーブされ,次に実行されるタスクのタスク・コンテキストがロードされます。
タスクは,処理を実行するうえで必要となる資源の獲得状況,および,事象発生の有無などにより,さまざまな状態へと遷移していきます。そこで,RI600PXでは,各タスクが現在どのような状態にあるかを認識し,管理する必要があります。
なお,RI600PXでは,タスクが取り得る状態を以下に示した7種類に分類し,管理しています。
RI600PXに登録されていない仮想的な状態です。
タスクとして起動されていない状態,またはタスクとしての処理を終了した際に遷移する状態です。
なお,DORMANT状態のタスクは,RI600PXの管理下にありながらも,RI600PXのスケジューリング対象からは除外されています。
処理を実行するうえで必要となる準備は整っているが,より高い優先度(同一優先度の場合もある)を持つタスクが処理を実行中のため,CPUの利用権が割り当てられるのを待っている状態です。
CPUの利用権が割り当てられ,処理を実行中の状態です。
なお,RUNNING状態のタスクは,システム全体を通して同時に複数存在することはありません。
処理を実行するうえで必要となる条件が整わないため,処理の実行が中断した状態です。
なお,WAITING状態からの処理再開は,処理の実行が中断した箇所からとなります。したがって,処理を再開するうえで必要となる情報(タスク・コンテキスト:プログラム・カウンタ,汎用レジスタなど)は,中断直前の値が復元されます。
また,RI600PXでは,要求条件の種類により,WAITING状態を以下に示す12状態に細分化し,管理しています。
強制的に処理の実行を中断させられた状態です。
なお,SUSPENDED状態からの処理再開は,処理の実行が中断した箇所からの再開となります。したがって,処理を再開するうえで必要となる情報(タスク・コンテキスト:プログラム・カウンタ,汎用レジスタなど)は,中断直前の値が復元されます。
WAITING状態とSUSPENDED状態が複合した状態です。
なお,WAITING状態が解除された際にはSUSPENDED状態へ,SUSPENDED状態が解除された際にはWAITING状態へと遷移します。
タスクには,処理を実行するうえでの優先順位を決定する優先度が付けられています。そこで,RI600PXのスケジューラでは,実行可能な状態(RUNNING状態およびREADY状態)にあるタスクの優先度を参照し,その中から最も高い優先度(最高優先度)を持つタスクを選び出し,CPUの利用権を与えています。
なお,RI600PXでは,“タスクの優先度”を以下に示した2種類に分類し,管理しています。
- 現在優先度
RI600PXは,以下の処理を現在優先度にしたがって実施します。
備考 タスクがDORMANT状態からREADY状態へと遷移した直後の現在優先度(初期優先度)は,タスク生成時に指定します。
備考1 RI600PXにおけるタスクの優先度は,その値が小さいほど,高い優先度であることを意味します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考4参照*/
void Task1 ( VP_INT exinf ); /*備考4参照*/
void Task1 ( VP_INT exinf )
{
............
............
ext_tsk ( ); /*タスクの終了*/
}
|
備考2 タスク内でreturn命令が発行された場合,
ext_tskと同等の処理が実行されます。
備考4 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
RI600PXでは,タスクを切り替える際,独自のスケジューリング処理を行っています。このため,タスクを記述する際には,以下に示す注意点があります。
- サービス・コールの発行
タスクでは,“発行有効範囲”が“タスク”のサービスコールを発行可能です。
|
|
|
|
|
|
|
|
|
|
|
0x00000101(DNビットとRMビットのみ1)
|
|
|
タスクは,常にユーザ・モードで実行されます。タスクををスーパバイザ・モードで実行させることはできません。
スーパバイザ・モードで実行させたい処理は,INT命令の割り込みハンドラとして実装してください。
例えば,CPUを低消費電力モードに遷移させるWAIT命令は特権命令なので,スーパバイザ・モードで実行する必要があります。
なお,INT #1〜8は,RI600PXで予約されているので,使用しないでください。
1 ) システム・コンフィギュレーション・ファイルによる生成
システム・コンフィギュレーション・ファイルで静的API“task[]”を使用してタスクを生成します。
静的API“task[]”の詳細は,「
20.10 タスク情報(task[])」を参照してください。
2 )
cre_tskまたは
acre_tskサービスコールによる生成
cre_tskは,パラメータ
pk_ctskが指す領域に設定されたタスク生成情報にしたがって,パラメータ
tskidで指定されたタスクIDのタスクを生成します。
acre_tskは,パラメータ
pk_ctskが指す領域に設定されたタスク生成情報にしたがってタスクを生成し,生成されたタスクIDを返します。
指定するタスク生成情報は,以下の通りです。
- 生成後に起動する指定(TA_ACT属性)
生成されたタスクの状態は,TA_ACT属性を指定した場合はREADY状態,TA_ACT属性を指定しなかった場合はDORMANT状態となります。
- ユーザ・スタック・サイズ(
stksz),ユーザ・スタック領域の先頭アドレス(
stk)
ユーザ・スタック領域は,以下の条件を満たさなければなりません。
- メモリ・オブジェクトおよび他のタスクのユーザ・スタック領域と重ならないこと
以下に,代表としてacre_tskの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
extern void Task2 ( VP_INT exinf );
#pragma section B SU_STACK2 /* ユーザ・スタック領域のセクション*/
/* リンク時に16バイト境界アドレスに配置必要*/
#define STKSZ2 256 /*ユーザ・スタック・サイズは16の倍数*/
static UW Stack2[STKSZ2/sizeof(UW)]; /* ユーザ・スタック領域*/
#pragma section
#pragma task Task1 /*備考参照*/
void Task1 ( VP_INT exinf ); /*備考参照*/
void Task1 ( VP_INT exinf )
{
ER_ID tskid; /*変数の宣言*/
T_CTSK pk_ctsk = { /*変数の宣言,初期化*/
TA_DOM(1)|TA_ACT, /*タスク属性(tskatr)*/
0, /*拡張情報(exinf)*/
(FP)Task2, /*タスクの実行開始アドレス(task)*/
1, /*起動時優先度(itskpri)*/
STKSZ2, /*ユーザ・スタック・サイズ(stksz)*/
(VP)Stack2 /*ユーザ・スタック領域の先頭アドレス(stk)*/
};
............
............
tskid = acre_tsk ( &pk_ctsk ); /*タスクの生成*/
............
............
}
|
備考 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
-
exd_tskサービス・コールによる自タスクの削除
exd_tskは,自タスクを正常終了し,さらに削除します。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
............
............
exd_tsk( ); /*自タスクの正常終了と削除*/
}
|
備考1 本サービス・コールでは,自タスクがミューテックスをロックしていた場合には,ロック状態の解除(
unl_mtxと同等の処理)もあわせて行われます。
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
-
del_tskサービス・コールによる他タスクの削除
del_tskは,パラメータ
tskidで指定されたDORMANT状態の他のタスクを削除します。
本サービス・コールは,
信頼されたドメインに所属するタスクだけが呼び出せます。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考参照*/
void Task1 ( VP_INT exinf ); /*備考参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
............
............
del_tsk( tskid ); /*他タスクの削除*/
}
|
備考 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
RI600PXでは,タスクの起動において,“起動要求をキューイングする”,“起動要求をキューイングしない”の2種類のインタフェースを用意しています。
タスクの起動(起動要求をキューイングする)は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
act_tsk,
iact_tsk
パラメータ
tskidで指定されたタスクをDORMANT状態からREADY状態へと遷移させたのち,初期優先度のレディ・キューの最後尾にキューイングします。これにより,対象タスクは,RI600PXのスケジューリング対象となります。
ただし,本サービス・コールを発行した際,対象タスクがDORMANT状態以外の場合には,対象タスクのキューイング処理,および,状態操作処理は行わず,対象タスクに起動要求をキューイング(起動要求カウンタに1を加算)しています。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考3参照*/
void Task1 ( VP_INT exinf ); /*備考3参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
............
............
act_tsk ( tskid ); /*タスクの起動(起動要求をキューイングする)*/
............
............
}
|
備考1 RI600PXが管理する起動要求カウンタは,8ビット幅で構成されています。このため,本サービス・コールでは,起動要求数が255回を超える場合には,起動要求の発行起動要求の発行(起動要求カウンタの加算処理)は行わず,戻り値としてE_QOVRを返します。
備考2 本サービス・コールの発行により起動されたタスクには,
タスクの生成時に指定した拡張情報が渡されます。
備考3 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
タスクの起動(起動要求をキューイングしない)は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
sta_tsk,
ista_tsk
パラメータ
tskidで指定されたタスクをDORMANT状態からREADY状態へと遷移させたのち,初期優先度のレディ・キューの最後尾にキューイングします。これにより,対象タスクは,RI600PXのスケジューリング対象となります。
ただし,本サービス・コールでは,起動要求のキューイングが行われません。このため,対象タスクがDORMANT状態以外の場合には,対象タスクの状態操作処理は行わず,戻り値としてE_OBJを返します。
なお,パラメータ
stacdには,対象タスクに引き渡す拡張情報を指定します。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考参照*/
void Task1 ( VP_INT exinf ); /*備考参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
VP_INT stacd = 123; /*変数の宣言,初期化*/
............
............
sta_tsk ( tskid, stacd ); /*タスクの起動(起動要求をキューイングしない)*/
............
............
}
|
備考 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
起動要求のキューイング解除は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
can_act,
ican_act
パラメータ
tskidで指定されたタスクにキューイングされている起動要求をすべて解除(起動要求カウンタに0を設定)します。
なお,正常終了時は戻り値として本サービス・コールの発行により解除した起動要求数を返します。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
ER_UINT ercd; /*変数の宣言*/
ID tskid = 8; /*変数の宣言,初期化*/
............
............
ercd = can_act ( tskid ); /*起動要求のキューイング解除*/
if ( ercd >= 0 ) {
............ /*正常終了処理*/
............
}
............
............
}
|
備考1 本サービス・コールでは,状態操作処理は行わず,起動要求カウンタの設定処理のみを行います。したがって,READY状態などからDORMANT状態に遷移することはありません。
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
自タスクの終了は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
ext_tsk
自タスクをRUNNING状態からDORMANT状態へと遷移させ,レディ・キューから外します。これにより,自タスクは,RI600PXのスケジューリング対象から除外されます。
ただし,本サービス・コールを発行した際,自タスクの起動要求がキューイングされていた(起動要求カウンタ > 0)場合には,自タスクの状態操作(DORMANT状態への状態遷移処理)を行ったのち,自タスクの起動(DORMANT状態からREADY状態への状態遷移処理)もあわせて行われます。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考3参照*/
void Task1 ( VP_INT exinf ); /*備考3参照*/
void Task1 ( VP_INT exinf )
{
............
............
ext_tsk ( ); /*タスクの終了*/
}
|
備考1 本サービス・コールでは,自タスクがミューテックスをロックしていた場合には,ロック状態の解除(
unl_mtxと同等の処理)もあわせて行われます。
備考2 タスク内でreturn命令が発行された場合,本サービス・コールと同等の処理が実行されます。
備考3 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
タスクの強制終了は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
ter_tsk
パラメータ
tskidで指定されたタスクを強制的にDORMANT状態へと遷移させます。これにより,対象タスクは,RI600PXのスケジューリング対象から除外されます。
ただし,本サービス・コールを発行した際,対象タスクの起動要求がキューイングされていた(起動要求カウンタ > 0)場合には,対象タスクの状態操作(DORMANT状態への状態遷移処理)を行ったのち,対象タスクの起動(DORMANT状態からREADY状態への状態遷移処理)もあわせて行われます。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
............
............
ter_tsk ( tskid ); /*タスクの強制終了*/
............
............
}
|
備考1 本サービス・コールでは,対象タスクがミューテックスをロックしていた場合には,ロック状態の解除(
unl_mtxと同等の処理)もあわせて行われます。
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
タスク優先度の変更は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
chg_pri,
ichg_pri
tskidで指定されたタスクのベース優先度を
tskpriで指定された値に変更します。
変更されたタスクのベース優先度は,タスクが終了,または本サービス・コールを呼び出すまで有効です。次回のタスク起動時,タスクのベース優先度はタスク生成時に指定した初期タスク優先度になります。
本サービス・コールは,対象タスクの現在優先度も,
tskpriで示された値に変更します。ただし,対象タスクがミューテックスをロックしている場合は,現在優先度は変更しません。
対象タスクがミューテックスをロックしているかロックを待っている場合で,
tskpriがそれらのミューテックスのいずれかの上限優先度よりも高い場合には,戻り値としてE_ILUSEを返します。
現在優先度が変更された場合,以下の状態変化が生じます。
1 ) 対象タスクがRUNNING状態またはREADY状態の場合
本サービス・コールは,対象タスクを
tskpriで指定された優先度に応じたレディ・キューの最後尾につなぎかえます。
2 ) 対象タスクがTA_TPRI属性またはTA_CEILING属性のオブジェクトの待ちキューにキューイングされている場合
本サービス・コールは,
tskpriで指定された優先度にしたがって対象タスクを待ちキューにつなぎかえます。待ちキューに
tskpriで指定された現在優先度のタスクが複数ある場合は,対象タスクをそれらの中の最後尾につなぎかえます。
例 セマフォの待ちキューに3つのタスク(タスクA:優先度10,タスクB:優先度11,タスクC:優先度12)が優先度順でキューイングされているとき,タスクBの優先度を11から9に変更した場合,待ちキューの順序は,以下のように変更されます。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
PRI tskpri = 9; /*変数の宣言,初期化*/
............
............
chg_pri ( tskid, tskpri ); /*タスク優先度の変更*/
............
............
}
|
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
タスク優先度の参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
get_pri,
iget_pri
パラメータ
tskidで指定されたタスクの現在優先度をパラメータ
p_tskpriで指定された領域に格納します。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
PRI p_tskpri; /*変数の宣言*/
............
............
get_pri ( tskid, &p_tskpri ); /*タスク優先度の参照*/
............
............
}
|
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
タスク詳細情報の参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
ref_tsk,
iref_tsk
パラメータ
tskidで指定されたタスクのタスク詳細情報(現在状態,現在優先度など)をパラメータ
pk_rtskで指定された領域に格納します。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
T_RTSK pk_rtsk; /*データ構造体の宣言*/
STAT tskstat; /*変数の宣言*/
PRI tskpri; /*変数の宣言*/
PRI tskbpri; /*変数の宣言*/
STAT tskwait; /*変数の宣言*/
ID wobjid; /*変数の宣言*/
TMO lefttmo; /*変数の宣言*/
UINT actcnt; /*変数の宣言*/
UINT wupcnt; /*変数の宣言*/
UINT suscnt; /*変数の宣言*/
............
............
ref_tsk ( tskid, &pk_rtsk ); /*タスク詳細情報の参照*/
tskstat = pk_rtsk.tskstat; /*現在状態の獲得*/
tskpri = pk_rtsk.tskpri; /*現在優先度の獲得*/
tskbpri = pk_rtsk.tskbpri; /*ベース優先度の獲得*/
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; /*サスペンド要求数の獲得*/
............
............
}
|
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。
タスク基本情報の参照は,以下に示したサービス・コールを処理プログラムから発行することにより実現されます。
-
ref_tst,
iref_tst
パラメータ
tskidで指定されたタスクのタスク基本情報(現在状態,待ち要因)をパラメータ
pk_rtstで指定された領域に格納します。
タスク情報のうち,現在状態,待ち要因のみを参照したい場合に使用します。
取得する情報が少ないので
ref_tsk,
iref_tskより高速に応答します。
以下に,本サービス・コールの記述例を示します。
#include "kernel.h" /*標準ヘッダ・ファイルの定義*/
#include "kernel_id.h" /*cfg600pxが出力するヘッダ・ファイルの定義*/
#pragma task Task1 /*備考2参照*/
void Task1 ( VP_INT exinf ); /*備考2参照*/
void Task1 ( VP_INT exinf )
{
ID tskid = 8; /*変数の宣言,初期化*/
T_RTST pk_rtst; /*データ構造体の宣言*/
STAT tskstat; /*変数の宣言*/
STAT tskwait; /*変数の宣言*/
............
............
ref_tst ( tskid, &pk_rtst ); /*タスク基本情報の参照*/
tskstat = pk_rtst.tskstat; /*現在状態の獲得*/
tskwait = pk_rtst.tskwait; /*待ち要因の獲得*/
............
............
}
|
備考2 システム・コンフィギュレーション・ファイルで生成したタスクについては,これらのステートメントはcfg600pxがkernel_id.hに出力するため,記述不要です。