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

第10回 mig_tskサービスコールの解説(前編)

 

FMPカーネルに採用された,タスクマイグレーションサービスコール(mig_tsk)について解説します.

タスクマイグレーション
タスクマイグレーションとは,タスクの割付けプロセッサを変更することをいいます.
第7回で解説したように,FMPカーネルでは,負荷変動への対応が可能なように,タスクを移動させるサービスコール(mig_tsk)を追加しました.
汎用OS等では,カーネル自身が自動的かつ動的に負荷分散を行いますが,この方法では,リアルタイム性の保証が困難になってしまいます.
そこで,FMPカーネルでは,カーネル自身が負荷分散を行うことはしませんが,タスクを移動するサービスコールを用意することで,ユーザがミドルウェアとして負荷分散を実現することができる仕組みを提供しています.

このFMPカーネルで提供しているタスクマイグレーション機能は,サービスコールを発行したプロセッサに割付けられたタスクに対してのみ可能としています.また,非タスクコンテキストからこのサービスコールを発行できません.
この制約は,システムコールの最悪実行時間,平均実行時間を抑えるために定めています.

mig_tsk(ID tskid, ID prcid)
tskidで指定したタスクをprcidで指定したプロセッサに移動させる.

マイグレーション可能な条件
・タスクから自プロセッサに割り付けられている他のタスクに対して
・自タスクに対して 

制約1:非タスクコンテキストからは発行できない
制約2:他プロセッサに割り付けられているタスクには発行できない


図1に全体の流れを示します.



[図1 mig_tsk 全体の流れ]
mig_tskでは,大きく分けて次の3つの処理が行われます.

・対象タスクのTCBのp_pcb(割付けられているプロセッサのPCBアドレス)に移動先のプロセッサのPCBを指定する.
・対象タスクが実行できる状態であれば,移動元のプロセッサのレディキューからTCBを外す.その後,移動先のプロセッサのレディキューにTCBを接続する.
・マイグレーションによって,移動元,および,移動先プロセッサで必要であればディスパッチを行う.
mig_tsk()の処理結果は,対象タスクの状態,移動先プロセッサの種別などによって異なります.処理の分類とその結果を以下に示します.


対象タスクの状態 詳細 結果
(1)実行状態 ディスパッチ禁止中の場合 (1-a)
  同一プロセッサを指定した場合 (1-b)
  他プロセッサを指定した場合 (1-c)
(2)実行可能状態 同一プロセッサを指定した場合 (2-a)
  他プロセッサを指定した場合 (2-b)
(3)休止状態   (3)
(4)待ち状態 時間待ちでない場合 (4-a)
  時間待ちの場合 (4-b)


(1)対象タスクが実行状態(自タスクに対して,mig_tskを発行)
(1-a)ディスパッチ禁止中の場合
       エラー
(1-b)自プロセッサを指定した場合
       自タスクを同一優先度で最低優先順位とする.他のタスクが最高優先順位となれば,自プロセッサでディスパッチ発生.
(1-c)他プロセッサを指定した場合
       対象タスクのTCBのp_pcbを移動先プロセッサへ付け替える.
       移動先プロセッサで,自分自身が最高優先順位なら,ディスパッチ発生.
       移動元プロセッサは,今まで実行状態だったタスクがマイグレーションすることになるので,ディスパッチャ呼び出しが発生.他に実行状態のタスクが存在すれば,最高優先順位のタスクへのディスパッチが発生.
(実行状態タスクが存在しなければアイドルループへ)

(2)対象タスクが実行可能状態
(2-a)自プロセッサを指定した場合
       対象タスクを,同一優先度で最低優先順位とする.ディスパッチは発生しない.
(2-b)他プロセッサを指定した場合
       対象タスクのTCBのp_pcbを移動先プロセッサへ付け替える.

       移動先プロセッサで対象タスクが最高優先順位なら,移動先のプロセッサで,ディスパッチ発生.
       自プロセッサではディスパッチは発生しない.


(3)対象タスクが休止状態
       対象タスクのTCBのp_pcbを移動先プロセッサへ付け替える.ディスパッチは発生しない.

(4)対象タスクが待ち状態
(4-a)時間待ちでない場合
       対象タスクのTCBのp_pcbを移動先プロセッサへ付け替える.ディスパッチは発生しない.
(4-b)時間待ちの場合
       上記処理以外に,タイムイベントを移動先プロセッサへ移動する.

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

[kernel task_manage.c]
150 ER 
151 mig_tsk(ID tskid, ID prcid)
152 {
153 TCB *p_tcb;
154 ER ercd = E_OK;
155 PCB *t_p_pcb;
156 PCB *f_p_pcb;
157 bool_t dspreq = false;
158 PCB *my_p_pcb;
159 #ifdef TOPPERS_SYSTIM_LOCAL
160 EVTTIM left_time;
161 #endif /* TOPPERS_SYSTIM_LOCAL */
162
163 LOG_MIG_TSK_ENTER(tskid, prcid);
164 CHECK_TSKCTX_UNL();
165 CHECK_TSKID_SELF(tskid);
166 CHECK_PRCID_INI(prcid);
167
168 t_lock_cpu();
169 p_tcb = get_tcb_self(tskid, get_my_p_pcb());
170 prcid = (prcid == TPRC_INI)? p_tcb->p_tinib->iaffinity : prcid;
171 T_CHECK_MIG(p_tcb->p_tinib->affinity_mask, prcid);
172
173 /* 現在割り付けられているプロセッサと移動先のプロセッサのタスクロックを取得 */
174 t_acquire_dual_tsk_lock(p_tcb, prcid, &f_p_pcb, &t_p_pcb);
175 my_p_pcb = get_my_p_pcb();
176 if (f_p_pcb != my_p_pcb) {
177 /*
178 * 自タスクと同じプロセッサに割り付けられているタスクでなけれ
179 * ばエラー. mig_tsk を呼び出したタスクがシステムコール呼出し後,
180 * マイグレートされた場合にも,ここでエラーとなる
181 */
182   ercd = E_OBJ;
183 }


制約1のチェック
164行目:非タスクコンテキストからの呼び出しなら,エラーとする.
サービスコールの呼び出し元が,タスクコンテキスト以外であればエラーを返します.

ロックの取得
174行目:移動元と,移動先のプロセッサのタスクロックを取得.

この,t_acquire_dual_tsk_lock()処理中に,f_p_pcbに対象タスクの割り付けられているプロセッサ(移動元プロセッサ)のPCBアドレス,t_p_pcbにprcidで示す移動先プロセッサのPCBアドレスが設定されます.

※ロックの詳細については,後日解説します.

制約2のチェック
175〜183行目:対象タスクが他のタスクに割り付けられている場合はエラーとする.
175行目:現在処理が行われているプロセッサ(自プロセッサ)のPCBアドレスをmy_p_pcbに格納する.

[kernel pcb.h]
Inline PCB*
get_my_p_pcb(void)
{
return p_pcb_table[x_prc_index()];
}


※PCBアクセステーブル
[ユーザディレクトリ/kernel_cfg.c]
PCB* const _kernel_p_pcb_table[TNUM_PRCID] = {
&_kernel_prc1_pcb,
&_kernel_prc2_pcb
};


get_my_p_pcb()では,コンフィギュレーションによってkernel_cfg.cに生成された,PCBアクセステーブル(p_pcb_table[])から,割り付けられているプロセッサのPCBアドレスを取得します.
※x_prc_index():プロセッサINDEX(0オリジン)を取得する関数

176〜183行目:対象タスクの割り付けられているPCB(f_p_pcb)と,現在処理が行われているPCB(my_p_pcb)とが同じかどうかを判別し,違っていればエラーとする.


次回は,タスクマイグ―ション処理の続きを解説します.