マルチプロセッサ用リアルタイムOSの解説

第13回 mact_tskサービスコールの解説

今回は,FMPカーネルで新たに提供するmact_tskサービスコールについて解説します.このサービスコールは,プロセッサを指定してタスクを起動します.つまり起動時にタスクのマイグレーションが可能となります.
mig_tsk()の仕様は,対象タスクを自タスクと同一のプロセッサに割りつけられているタスクに限定しました.そこで,他プロセッサに割りつけられているタスクのマイグレーション方法として,休止状態のタスクに対して,起動とタスクマイグレーションを行うmact_tsk()を提供しています.また,mig_tsk()とは異なり,対象タスクの制限はなく,また非タスクコンテキストからの発行も可能です.(imact_tsk())

mact_tsk(ID tskid, ID prcid)
プロセッサを指定してタスクを起動する.
(TPRC_INI(=0)を指定すると,初期割付けプロセッサで起動する)

キューイングした場合には,タスク終了後,指定したプロセッサでタスクを起動します.
このため,TCBへ次回の起動先のプロセッサを記憶するactprcメンバをFMPでは追加しています.

act_tskとの違い
(1)マイグレーション元と先のプロセッサのタスクロックを取得する.
※act_tskでは,対象タスクが割り付けられているプロセッサのタスクロックのみの取得.
(2)TCBのp_pcbをマイグレーション先のプロセッサに変更し,割り付けられているプロセッサを付け替えてから実行できる状態にする.
(3)キューイングする場合は,actprcに次回起動時のプロセッサIDを指定する.

図1にmact_tskの全体の流れを示します.act_tskとの違いは色で示します.



[図1 mact_tsk全体の流れ]
ソースコードを見ていきます.
[kernel/task_manage.c]
368 ER 
369 mact_tsk(ID tskid, ID prcid)
370 {
371 TCB *p_tcb;
372 ER ercd;
373 PCB *t_p_pcb;
374 PCB *f_p_pcb;
375 bool_t dspreq = false;
376
377 LOG_MACT_TSK_ENTER(tskid, prcid);
378 CHECK_TSKCTX_UNL();
379 CHECK_TSKID_SELF(tskid);
380 CHECK_PRCID_INI(prcid);
381
382 t_lock_cpu();
383 p_tcb = get_tcb_self(tskid, get_my_p_pcb());
384 prcid = (prcid == TPRC_INI)? p_tcb->p_tinib->iaffinity : prcid;
385 T_CHECK_MIG(p_tcb->p_tinib->affinity_mask, prcid);
386
387 /* 現在割り付けられているプロセッサと移動先のプロセッサのタスクロックを取得 */
388 t_acquire_dual_tsk_lock(p_tcb, prcid, &f_p_pcb, &t_p_pcb);
389 if (TSTAT_DORMANT(p_tcb->tstat)) {
390 LOG_TSKMIG(p_tcb, f_p_pcb->prcid, prcid);
391 p_tcb->p_pcb = t_p_pcb;
392 if (make_active(p_tcb)) {
393 dspreq = dispatch_request(t_p_pcb);
394 }
395 ercd = E_OK;
396 }
397 else if (!(p_tcb->actque)) {
398 p_tcb->actque = true;
399 p_tcb->actprc = prcid;
400 ercd = E_OK;
401 }
402 else {
403 ercd = E_QOVR;
404 }
405 release_dual_tsk_lock_and_dispatch(f_p_pcb, t_p_pcb, dspreq);
406 t_unlock_cpu();
407
408 error_exit:
409 LOG_MACT_TSK_LEAVE(ercd);
410 return(ercd);
411 }


それでは,ソースコードの詳細を見ていきます.

383行目:対象タスクのTCBアドレスを,p_tcbに格納します.
#define get_tcb_self(tskid, my_p_pcb)
((tskid) == TSK_SELF ? (my_p_pcb)->p_runtsk : get_tcb(tskid))

384行目:prcidにTPRC_INI(=0)が指定された場合,初期割り付けプロセッサで起動するため,タスク初期化ブロックに登録されている初期割り付けプロセッサIDをprcidとする.
※タスク初期化ブロックへのアクセスポインタは,TCBに登録されている.

385行目:prcidに指定した起動先プロセッサへ,マイグレーション可能かチェックする.

◎タスクの割付け可能プロセッサについて
タスクが指定したプロセッサへマイグレーション可能かどうかは,そのタスクが割り付けられているクラスに定義されている“マイグレーション可能なプロセッサのマスク指定”に依存します.
クラスの定義については,第8回を参照してください.
クラスの定義は,アプリケーションプログラム内で定義するものではありませんので,基本的にはアプリケーションエンジニアが毎回定義する必要はありません.基本的には,カーネルのソースコード内にある,OS実装者が用意したクラスの定義を使用することになります.

[\fmp\target\ターゲット名¥target.tf]
$ クラス TCL_1(クラスID 1)に関する指定
$
$ 初期割付けプロセッサ(ID指定)
$CLASS_AFFINITY_INI[1] = 1$
$ マイグレーション可能なプロセッサのマスク指定
$CLASS_AFFINITY_MASK[1] = 0x0000000f$
$ オブジェクトロック
& P_LOCKの場合に使用するオブジェクトロックを持つプロセッサのIDを指定
$CLASS_OBJ_LOCK[1] = 1$
$ タスクスタックのセクション指定
$CLASS_SECTION_TSKSTK[1]= "__attribute__((section(\"._kernel_prc1s_tstack\"),nocommon))"$
$ タスクコントロールブロックのセクション指定
$CLASS_SECTION_TSKCB[1]= "__attribute__((section(\"._kernel_prc1s_tskcb\"),nocommon))"$
$ オブジェクトコントロールブロックのセクション指定
$CLASS_SECTION_OBJCB[1]= "__attribute__((section(\"._kernel_prc1s_objcb\"),nocommon))"$


上記の場合,クラス1のマイグレーション可能なプロセッサのマスク指定は,0x0fとなっていますので,いずれのプロセッサへもマイグレーション可能です.

※ロックの取得 act_tsk()との違い(1)
388行目:移動元と,移動先のプロセッサのタスクロックを取得.
この,t_acquire_dual_tsk_lock()処理中に,f_p_pcbに対象タスクの割り付けられているプロセッサ(移動元プロセッサ)のPCBアドレス,t_p_pcbにprcidで示す移動先プロセッサのPCBアドレスが設定されます.
※ロックの詳細については,後日解説します.

(1)休止状態の場合(389〜396行目)

※割り付けられているプロセッサを付け替える act_tsk()との違い(2)
391行目:対象タスクのTCBのp_pcbに,移動先プロセッサを登録し,割り付けられているプロセッサを付け替える.

392行目:make_active()を発行する.
391行目で割り付けられているプロセッサを書き換えているので,指定したプロセッサで実行できる状態になります.

他の処理は,act_tskと同じですので,第12回を参照してください.

(2)休止状態以外(397〜404行目)

起動要求がキューイングされていない場合
397行目:休止状態でなく,起動要求されていなければ

TCBの起動要求キューイング(actque)メンバは,起動要求されているかどうか返すbool型変数です.FMPカーネルはキューイング回数を1回としていますので,キューイングされているかどうかを,bool型変数で表現します.

398行目:起動要求キューイングをtrueにします.

※次回起動時のプロセッサを登録 act_tsk()との違い(3)
399行目:TCBの次回の起動先のプロセッサを記憶するactprcメンバにprcidを登録する.

◎タスクの次回起動時の処理
actprcによるプロセッサの指定は,タスクの起動がキューイングしている場合に有効になります.タスクが終了する際に,タスクの起動がキューイングしていると,続けてそのタスクの起動処理が行われます.キューイングしているタスクがext_tsk()を発行した,もしくはter_tsk()が発行された際に,actprcに登録されているプロセッサで,起動処理が行われます.

起動要求がキューイングされている場合
403行目:すでに,起動要求キューイングされている場合は,エラーコードにE_QOVERを設定します.

※ロックの解放 act_tsk()との違い(1)
405行目:release_dual_tsk_lock_and_dispatch(f_p_pcb, t_p_pcb, dspreq);
388行目で取得した,移動元と,移動先のプロセッサのタスクロックを解放し,dspreqがtrueの場合は自プロセッサでディスパッチします.
375行目で,dspreqはfalseに初期化されています.この値がtrueになるのは,対象タスクが休止状態かつ自プロセッサを指定し,起動により最高優先順位となる場合で,ディスパッチが保留状態でない場合です.