リアルタイムOSの内部構造を見てみよう!

第21回 ASPカーネル新機能の紹介<イベントフラグの複数タスク待ち>

今回は,ASPカーネルの新機能の紹介として,イベントフラグの複数タスク待ちについて解説します.イベントフラグの機能はTOPPERS/JSPカーネルでもサポートしていました.しかし,1つのイベントフラグに対して複数のタスクが待つという機能は,μITORN4.0のスタンダードプロファイル外の機能でしたので,TOPPERS/JSPカーネルではサポートしていませんでした.ASPカーネルではこの部分を拡張し,1つのイベントフラグに対して複数のタスクが待つことができるようになりました.つまり,イベントフラグを1回セットすると,場合によっては複数のタスクが待ち解除となる場合があります.

ここでは,イベントフラグ待ちサービスコールwai_flg,イベントフラグのセットサービスコールset_flgのソースコード解説を行い,その中で新機能を紹介していきます.

まず,サービスコールの仕様をμITRON4.0仕様書で確認します.

» Read More

まず,イベントフラグ待ちの時に構成される構造を図1に示します.詳細は19回を参照してください.

null

【図1 イベントフラグ待ち状態時のデータ構造】

では,まずwai_flgサービスコールのソースコードから見ていきます.
/kernel/eventflag.c

233 ER
234 wai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)
235 {
236 FLGCB *p_flgcb;
237 WINFO_FLG winfo_flg;
238 ER ercd;
239
240 LOG_WAI_FLG_ENTER(flgid, waiptn, wfmode, p_flgptn);
241 CHECK_DISPATCH();
242 CHECK_FLGID(flgid);
243 CHECK_PAR(waiptn != 0U);
244 CHECK_PAR(wfmode == TWF_ORW || wfmode == TWF_ANDW);
245 p_flgcb = get_flgcb(flgid);
246
247 t_lock_cpu();
248 if ((p_flgcb->p_flginib->flgatr & TA_WMUL) == 0U
249 && !queue_empty(&(p_flgcb->wait_queue))) {
250 ercd = E_ILUSE;
251 }
252 else if (check_flg_cond(p_flgcb, waiptn, wfmode, p_flgptn)) {
253 ercd = E_OK;
254 }
255 else {
256 winfo_flg.waiptn = waiptn;
257 winfo_flg.wfmode = wfmode;
258 p_runtsk->tstat = (TS_WAITING | TS_WAIT_FLG);
259 wobj_make_wait((WOBJCB *) p_flgcb, (WINFO_WOBJ *) &winfo_flg);
260 dispatch();
261 ercd = winfo_flg.winfo.wercd;
262 if (ercd == E_OK) {
263 *p_flgptn = winfo_flg.flgptn;
264 }
265 }
266 t_unlock_cpu();
267
268 error_exit:
269 LOG_WAI_FLG_LEAVE(ercd, *p_flgptn);
270 return(ercd);
271 }


237行目:STEP1
WINFO_FLG領域を確保します.実行中のタスクが使用しているスタック上に確保されます.
245行目:該当イベントフラグのイベントフラグ管理ブロックのアドレスを,p_flgcbに格納します.

248行目:STEP2
イベントフラグ属性が,TA_WMULでないのに,すでにイベントフラグ待ちキューにタスクが存在する場合には,エラーとします.
属性がTA_WMULであれば,すでにタスクが待っていてもさらに待つことができます.→ASP新機能

252行目:STEP3
check_flg_condで待ち解除条件のチェックを行います.

89 BOOL
90 check_flg_cond(FLGCB *p_flgcb, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)
91 {
92 if ((wfmode & TWF_ORW) != 0U ? (p_flgcb->flgptn & waiptn) != 0U
93 : (p_flgcb->flgptn & waiptn) == waiptn) {
94 *p_flgptn = p_flgcb->flgptn;
95 if ((p_flgcb->p_flginib->flgatr & TA_CLR) != 0U) {
96 p_flgcb->flgptn = 0U;
97 }
98 return(TRUE);
99 }
00 return(FALSE);
101 }


92〜94行目:該当イベントフラグの現在のフラグパターンが,待ち条件に合致していれば,現在のフラグパターンを呼び出し元に返します.
イベントフラグが待ち解除条件を満たしていれば,wai_flgを発行したタスクは待ち状態にならずに戻ります.
95〜97行目:イベントフラグ属性が,TA_CLRであれば,現在のイベントフラグパターンを0にクリアします.

255行目:STEP4
イベントフラグ待ち解除パターンと,現在のイベントフラグのパターンが合致せず,イベントフラグ待ち状態になる場合にここにきます.
256,257行目:INFO_FLGのwai_ptn,wfmodeに待ち解除条件を設定します.
258行目:TCBのタスク状態を,イベントフラグ待ちとします.
259行目:STEP5
同期・通信オブジェクト待ちにする共通関数wobj_make_wait()を呼び出します.
wobj_make_wait()では,レディキューから該当タスクを外し,p_schedtskを更新します.そして,図1の各構造体同士のリンク構造を形成します.(第19回で,セマフォの例で解説しています.)

260行目:STEP6
実行中のタスクがイベントフラグ待ちになるので,無条件にディスパッチします.

261行目:
260行目でディスパッチして,待ち状態になっていたタスクが,実行状態になってこの行を実行します.イベントフラグ待ちから実行可能状態になるためには,該当イベントフラグに対して,set_flg()が発行される.もしくは,待ち状態の強制解除のためのサービスコールrel_wai()が発行されるという2とおりの可能性があります.そこで,set_flg()の中では,イベントフラグ待ち情報管理ブロックの待ち解除時のエラーコード(wercd)に,E_OKを,rel_wai()の処理の中では,E_RLWAIを設定します.そうすることで,イベントフラグ待ち状態から解除した理由を知ることができます.

※クリティカルセクション
247行目:CPUロック状態へ移行
266行目:CPUロック状態の解除
247行目から266行目までを,クリティカルセクションとして,排他的に処理を行うように制御しています.他のタスクや割込み処理によって,状態が変わってしまっては問題である区間をクリティカルセクションとして,t_lock_cpu()とt_unlock_cpu()で囲みます.

図2に,wai_flgの処理フローを示します.



【図2 wai_flgの処理フロー】

次に,イベントフラグセットのサービスコールset_flgのソースコードを見ていきます.

/kernel/eventflag.c

110 ER
111 set_flg(ID flgid, FLGPTN setptn)
112 {
113 FLGCB *p_flgcb;
114 QUEUE *p_queue;
115 TCB *p_tcb;
116 WINFO_FLG *p_winfo_flg;
117 ER ercd;
118
119 LOG_SET_FLG_ENTER(flgid, setptn);
120 CHECK_TSKCTX_UNL();
121 CHECK_FLGID(flgid);
122 p_flgcb = get_flgcb(flgid);
123
124 t_lock_cpu();
125 p_flgcb->flgptn |= setptn;
126 p_queue = p_flgcb->wait_queue.p_next;
127 while (p_queue != &(p_flgcb->wait_queue)) {
128 p_tcb = (TCB *) p_queue;
129 p_queue = p_queue->p_next;
130 p_winfo_flg = (WINFO_FLG *)(p_tcb->p_winfo);
131 if (check_flg_cond(p_flgcb, p_winfo_flg->waiptn,
132 p_winfo_flg->wfmode, &(p_winfo_flg->flgptn))) {
133 queue_delete(&(p_tcb->task_queue));
134 wait_complete(p_tcb);
135 if ((p_flgcb->p_flginib->flgatr & TA_CLR) != 0U) {
136 break;
137 }
138 }
139 }
140 if (p_runtsk != p_schedtsk && dspflg) {
141 dispatch();
142 }
143 ercd = E_OK;
144 t_unlock_cpu();
145
146 error_exit:
147 LOG_SET_FLG_LEAVE(ercd);
148 return(ercd);
149 }



125行目:STEP1
set_flg発行によってセットするフラグパターン(setptn)を,FLGCBにセットします.

127行目〜:イベントフラグ待ちキュー内を,待ち解除条件を満たしているタスクがいないか検索します.
131行目:check_flg_cond()(前述)
待ち解除条件を満たしているタスクがあれば,イベントフラグパターンを返します.さらに,イベントフラグ属性が,TA_CLRであれば,現在のイベントフラグパターンを0にクリアします.
133行目:STEP2
該当タスクをイベントフラグ待ちキューから外します.
134行目::STEP3 wait_complete()
該当タスクを待ち解除します.この結果実行状態となるタスクが,レディキューの中で最高優先順となる場合には,p_schedtskが該当タスクに更新されます.(後ほどディスパッチします.)wait_complete()の処理の中で,該当タスクのイベントフラグ待ち情報管理ブロックのwercdにE_OKを設定します.
135行目:
イベントフラグ属性がTA_CLRの場合は,検索を終了します.TA_CLRでない場合は,検索を続け,待ち解除条件に合致するタスクがあれば,同様に待ち解除の処理を行います.
◎1回のset_flg発行で,複数のタスクが待ち解除となる.→ASP新機能
140行目:STEP4
ここまでの処理で,待ち解除条件に合致したタスクを実行可能状態としたことで,p_schedtskが更新され,ディスパッチする必要があり,かつディスパッチできる状態であれば,ディスパッチします.

※クリティカルセクション
124行目:CPUロック状態へ移行
144行目:CPUロック状態の解除
124行目から144行目までを,クリティカルセクションとして,排他的に処理を行うように制御しています.

図3にset_flgの処理フローを示します.

null

【図3 set_flgの処理フロー】