Smalight OSを使おう 7タスク目 タスク管理を使う1 [Smalight OS]
※sus_tskは、引数にタスクID番号を取る事から、他タスクを強制的にSUSPENDさせるのが普通の使い方だと思いますが、ここでは引数に自タスクIDを使って、自分自身をSUSPENDに遷移させて見せています。
※この文章を読んで貰えれば判るかと思いますが、よくsmalight osの特徴として、小さく軽くて、更に簡単と言う文章を見受ける事ができますが、それはどうかと思います。つまり小さく軽く作る事の見返りとしてOS内部のチェックが甘くなり、と言うよりプログラマーのスキルに依存する事が前提となってしまっており、その辺をよく理解して使わないと、とんでもないバグを作り込む事になるかもしれません。
また、タスク間通信機能が一切無いのは、ちょっとやり難いなあ。イベントフラグで待ち解除時のパターンを戻り値として取得可能。
小さくて軽いと言うのは同意しますが。
この記事は、某SNSで書いているものを転載しています。
今回は最も基本的なサービスコールであるタスク管理機構を使ってみます。
前にsmalight osにおけるタスクの状態遷移を示しましたが、このタスク管理機構が提供する機能は、直接的に(自または他)タスクに対して状態の遷移を起させる物です。
サービスコールの動作を解説します。
まずはタスク部(タスクの中)から発行できるサービスコールです。
自タスクをWAITに遷移させるには「slp_tsk」
WAITのタスクをREADYに遷移させるには「wup_tsk」
READYのタスクをSUSPENDに遷移させるには「sus_tsk」
WAITのタスクをWAIT+SUSPENDに遷移させるには「sus_tsk」
自タスクをSUSPENDに遷移させるには「sus_tsk」
SUSPENDのタスクをREADYに遷移させるには「rsm_tsk」
WAIT+SUSPENDのタスクをWAITに遷移させるには「rsm_tsk」
WAIT+SUSPENDのタスクをSUSPENDに遷移させるには「wup_tsk」
ローテーションタスクの順番の入れ替えを行う「rot_rdq」
※「sus_tsk」を実行中のタスクから自タスクIDを引数に使用する時には注意が必要です。
もし実行中のタスクが一時的に割り込みを禁止した状態で「sus_tsk」を発行してしまった時、それ以降割り込み禁止状態が継続する事となり、必要なディスパッチが発生しなくなる可能性が有ります。
本来はSUSPENDに入らず、エラーコードを返すべきかと思いますが、smalight osでは、OS自身でこのチェックを行う事は無く、プログラマーの責任となっています。
次いでOS管理下の割り込みハンドラから発行できるサービスコールです。
WAITのタスクをREADYに遷移させるには「iwup_tsk」
READYのタスクをSUSPENDに遷移させるには「isus_tsk」
WAITのタスクをWAIT+SUSPENDに遷移させるには「isus_tsk」
SUSPENDのタスクをREADYに遷移させるには「irsm_tsk」
WAIT+SUSPENDのタスクをWAITに遷移させるには「irsm_tsk」
WAIT+SUSPENDのタスクをSUSPENDに遷移させるには「iwup_tsk」
ローテーションタスクの順番の入れ替えを行う「irot_rdq」
まずサービスコール名を見れば判る様に、同じ機能のサービスコールの先頭に"i"を付ける事で、割り込みハンドラで使用できるサービスコールである事を示しています。
タスク部から発行できるサービスコールとの違いは、割り込みの一番最後にディスパッチを行う為に、サービスコール内部ではディスパッチを行っていない点です。
※基本的に、割り込みハンドラの中から利用できるサービスコールには、自ら待ち状態に入るサービスコールを利用する事はできません。それは、割り込みの中で無限ループに入るのと同じだからです。
しかしsmalight osの場合はサービスコール内でチェックしませんので、この点もプログラマが注意する必要が有ります。
では、自タスクをWAITに遷移させる「slp_tsk」と、SUSPENDに遷移させる「sus_tsk」と、他タスクを起床させる「wup_tsk」と、SUSPENDを解除する「rsm_tsk」をやってみます。
今回のサンプルプログラムでは、tsk01とtsk02のみしか使用しませんし、システムタイマー、イベントフラグ、セマフォ等の時間管理機構やカーネルオブジェクトも使用しませんので、コンパイル時の定義や、config.cの要所、要所を適宜合わせて置いてください。
tsk01は優先度1、tsk02は優先度2として、またtsk02はWAITの状態で起動しますので、config.cを以下の様に編集します。
/*------ TCB Status Init -------------------------------------*/ /* * Task status Init : CTCB_ST_RDY | CTCB_ST_SLP | ... * ("slos.h" Refer to for details.) */ const UB knl_tcbStInit[KNL_TCB_NUM] = { CTCB_ST_RDY, /* TCB1 */ CTCB_ST_SLP, /* TCB2 */ };
タスクはそれぞれ以下の様に記述します。
#define TID_1 1 #define TID_2 2 void tsk01( void ) { int i; for( i = 0; i < 2; i++ ) { wup_tsk( TID_2 ); } sus_tsk( TID_1 ); /*ここにブレークポイントを設定*/ slp_tsk(); /*ここにブレークポイントを設定*/ } void tsk02( void ) { while( 1 ) { rsm_tsk( TID_1 ); /*ここにブレークポイントを設定*/ slp_tsk(); /*ここにブレークポイントを設定*/ p2_0 ^= 1; /*ここにブレークポイントを設定*/ } }
さて、今回のサンプルの確認には、オンチップデバッカーを使用します。
コメントで「ここにブレークポイントを設定」と書かれた位置にブレークポイントを設定します。
それでは、「リセット後実行」でプログラムスタートしますと、まず最初に優先度1で起動したtsk01が、2回の「wup_tsk」の発行を行って、「sus_tsk」の位置で停止します。この「sus_tsk」は自らに向けて発行しているので、tsk01はこれ以降SUSPENDに遷移します。
この状態から「実行」を行うと、次はtsk02の「rsm_tsk」の位置で停止します。これは、tsk02はWAITで起動したのですが、tsk01の「wup_tsk」の発行によってREADYに遷移し、またtsk01が自ら待ち状態に入った為に、tsk02がRUNに遷移し、ここまでやって来たのです。
この状態から「実行」を行うと、次はtsk01の「slp_tsk」の位置で停止します。これはtsk02の「rsm_tsk」の発行でtsk01がSUSPENDからREADYに遷移し、さらに優先度が比較された時にtsk01の方が優先度が高かった為に、実行中のタスクが切り替わるプリエンプトが行われた為です。
しかしこれ以降、tsk01は自らWAITに遷移します。
この状態から「実行」を行うと、次はtsk02の「slp_tsk」の位置で停止します。勿論これはtsk01がWAITに遷移した事による、tsk02のREADYからRUNへの遷移が行われた為です。
この状態から「実行」を行うと、tsk02は自らWAITに遷移します。そして次の処理の「p2_0 ^= 1;」には決して到達しません。
μITRONと異なり、smalight osの場合、起床要求はキューイングされません。wup_tskを発行した場合、現在WAIT状態のタスクに対してのみ有効で(rsm_tskの場合はSUSPEND)、READY状態になったタスクには適用されませんので、tsk01で2回「wup_tsk」を発行したとしても、最初の一回しか効かなかったのです。
やっぱりC言語の開発スキルをアップしたいと言う事で、どうぞ!。
コメント 0