TOPPERS/FDMPKernel ドキュメント
1.0 TOPPERS-FDMP(Function Distributed Multi Processor) カーネル
- はじめに
- 本カーネルは,JSP 1.4.1 をベースに機能分散マルチプロセッサに 拡張したものである. -
- TODO:
- 検討点(未解決もくは未決定)
- 方針
- FDMP動作アーキテクチャ
- FDMPを動作させるためには,以下のアーキテクチャを満たす必要がある
- 各プロセッサのデータ(rodataも含む)を置くローカルメモリが お互いにアクセス可能.ローカルメモリは全てのプロセッサから 見て同じアドレスでアクセスできる必要がある.
- 任意のプロセッサに割込み(プロセッサ間割込み)を発生可能
- プロセッサ間での排他制御のための機構及びその機構を用いて ロックをプロセッサ数x2個作成可能であること.ただし2個でも 動作は可能.
- 例 : test & set 命令, Mutex 回路
- カーネル構築方法
- シングルプロセッサと異なる点についてのみ説明する.
- CFGファイルを用意する.
- FDMP用のコンフィギュレータを実行する.実行により各プロセッサ毎に プロセッサ名でオブジェクト生成用のディレクトリ(プロセッサディレ クトリ)が生成されて以下のファイルが生成される. class_id.h, kernel_id.h, kernel_cfg.c
- class_id.h(クラスIDファイルファイル)には,クラスID付きのオブジェ クトIDが定義されている. 例えばPE1のTASK1というタスクをPE1以外からアクセスするには, class_id.h をインクルードし,PE1_TASK1というIDでAPIを実行すれば よい.
- 各プロセッサのプロセッサディレクトリで make depend を実行して 依存関係ファイルを生成した後,make を実行してカーネルオブジェ クトを生成する.
- カーネルモデル
- 基本モデル(ローカルクラスのみ) モデルの拡張性を保持するため,クラスコントロールブロックを用いる モデルは残しておく.
- タスク状態不整合問題
- ロック/ディスパッチ禁止状態で実行中のタスクに対してsus_tsk/ter_tsk が発行された場合の振る舞い(セマンティクス)を決定.
- 仕様
- sus_tsk(ID tskid)
- CPUロック/ディスパッチ禁止中のタスクに対してsus_tsk()を発行す ると,タスクは一時的に過渡的な状態(run-suspend)になる.
- ter_tsk(ID tskid)
- CPUロック/ディスパッチ禁止中のタスクに対してter_tsk()を発行 すると,タスクは一時的に過渡的な状態(run-terminated)になる.
- 実装方法
- ter_tskを発行したことを示すterflgをTCBに追加.
- ret_intではこのフラグをチェックして,TRUEだとコンテキストを 保存せずにディスパッチャーに飛ぶ. ret_intでチェックするのは以下の二つの理由からである. 1. CPUロック解除時に,ter_tsk()の処理の結果,発行されたプロ セッサ間割込みが有効になるためである. 2. 割込みハンドラ実行時(runtskより優先度が高い)に,ter_tsk() が発行される可能性がある.
- terflgのクリアはactivate_rで行う.
- activate_context()はスタックをつぶさないように変更
- sus_tsk対象タスクがruntskかつenadspがFALSEなら,割り込みを 発行しないようにすると無駄な割り込みを防げる.
- sus_tsk(ID tskid)の検討
- CPUロック状態の runtsk に発行
- 特に対策の必要はなし
- sus_tsk()の実行後,プロセッサ間割り込みを発生する
- CPUロック中はAPIが発行できない。
- CPUロックを解除した時点で割り込みを受け付ける
- タスクの状態はsuspendに移行しているため,rsm_tsk()は正しく 動作する.
- ディスパッチ禁止状態の runtsk に発行
- 特に対策の必要はなし
- sus_tsk()実行後,プロセッサ間割り込みを発生する
- 割り込みは許可されているので、割り込みルーチンに入りるが, ディスパッチ禁止中のため,何もせずにリターン.
- ena_dsp()が実行されると,ディスパッチを行う.ena_dsp()の 中でタスクロックをとるため,sus_tsk()とのレーシングは発生 しない.
- タスクの状態はsuspendに移行しているため,rsm_tsk()は正しく 動作する.
- APIの発行
- CPUロック状態では,自タスクを待ち状態にするAPIは発行できない. いいかえると,自分の状態は変更できない.そのため,API発行は 問題ない.また,ext_tsk()は原則エラーだが,TOPPERSではワー ニングにして処理.
- ter_tsk(ID tskid)の検討
- CPUロック状態の runtsk に発行
- 特に対策の必要はなし
- CPUロック解放時点でプロセッサ間割り込みが入りディスパッチが 発生する.
- 一般にタスクを初期化してしまい,スタックを壊す可能性がある. ただし、スタックを壊さないように修正することは可能.
- ディスパッチ禁止runtsk に発行
- APIの発行
- terflgセットはディスパッチ要求(プロセッサ間割込み)の発行前に行うこと
- 逆にすると,プロセッサ間割込みの出口のret_intで,terflgを見落とす 恐れがある.
- デットロック回避
- 対象API
- TCBへの追加エントリ
- タイムアウト(wait_tmout(TCB *tcb))
- 再ロック後に待ちでなければ何もしなくてもよい.タイムアウト処理は 対象タスクと同一プロセッサで動作しているので,対象タスクはこの間 に動作せず,他のオブジェクト待ちになることはない.
- rel_wai(ID tskid)
- 再ロック後に,対象タスクが別の待ちオブジェクトに対して待ち状態 になっていれば,何もせずにE_OBJを返す.同じ待ち状態なら待ちを 解除してE_OKを返す.
- chg_pri(ID tskid, PRI tskpri)
- 最初のロックでnewpriをTCBに登録してロックを開放.他のルーチンで の待ち状態解除時にはnewpriを見て優先度を変更.再ロック後にnewpri の値が有効なら同じ待ちのはずなので通常の優先度変更を行う.
- ter_tsk(ID tskid)
- 最初のロックでTCBのpend_tertskをTRUEにしてロック開放.待ち状態解 除時にはpend_tertskを見てTRUEならタスク終了処理.再ロック後に pend_tertskがTRUEなら同じオブジェクトに対する待ちのはずなので通 常のタスク終了処理を行う.
- pend_tertsk/pend_chgpri/pend_relwaiをチェックするタイミング
- ACUIRE_LOCKすり抜け問題
- 自分が待ちに入るAPIで割り込みを禁止してからタスクロックを取るまで に,自タスクがrunnableでなくなっている可能性がある.
- runnableかどうかをチェックし、一度ロックを放し割り込みを許可する 以下のマクロを用意.
- 対象API
- snd_dtq(ID dtqid, VP_INT data)
- tsnd_dtq(ID dtqid, VP_INT data, TMO tmout)
- rcv_dtq(ID dtqid, VP_INT *p_data)
- trcv_dtq(ID dtqid, VP_INT *p_data, TMO tmout)
- wai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)
- twai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn, TMO tmout)
- rcv_mbx(ID mbxid, T_MSG **ppk_msg)
- trcv_mbx(ID mbxid, T_MSG **ppk_msg, TMO tmout)
- get_mpf(ID mpfid, VP *p_blk)
- tget_mpf(ID mpfid, VP *p_blk, TMO tmout)
- wai_sem(ID semid)
- twai_sem(ID semid, TMO tmout)
- dis_dsp(void)
- slp_tsk()
- tslp_tsk(TMO tmout)
- sus_tsk(ID tskid)
- dly_tsk(RELTIM dlytim)
- コーディングの際の注意点
- NESTED_LOCK使用時の注意点
- XXX_NESTED_LOCK()は,T_ACQUIRE_LOCK()との間をリトライで 繰り返し実行するため,この間は非破壊コードでなければならない.
- プロセッサ間割込み
- 他のプロセッサに対してのディスパッチ要求はプロセッサ間割込みにより 実現する.
- 関連ファイル
- 関数
- ロック
- オブジェクトロック → タスクロックの順にロックを取得
- 関連ファイル
- 関数
- 初期化(タスクロックの例)
- init_tsk_lock()を呼び出し,その戻り値を自exccbのtsk_lock_prt に登録.
- 自ccbのtsk_lock.lock_opsにmy_local_acquire_lockと my_local_release_lockを登録
- 他ccbのtsk_lock.lock_opsにlocal_acquire_lockとlocal_release_lock を登録
- ロックマクロ(lock.h)
- ACQUIRE_LOCK(lockobj)
- RELEASE_LOCK(lockobj)
- RELEASE_LOCK_AND_DISPATCH(lockobj, dspreq)
- T_ACQUIRE_LOCK(lockobj) t_lock_cpu()によりCPUロックする
- T_ACQUIRE_LOCK_AND_CHECK_RUNNABLE() ロック後,自タスクの状態が変化していればリトライする.
- T_ACQUIRE_NESTED_LOCK(lockobj, lockobj1) lockobjのロックを取得.取得できない場合は,lockobj1のロックと CPUロックを解放してリトライ
- T_ACQUIRE_NESTED_LOCK_AND_CHECK_RUNNABLE(lockobj1) ロック後,自タスクの状態が変化していればリトライする.
- snd_dtq(ID dtqid, VP_INT data)
- tsnd_dtq(ID dtqid, VP_INT data TMO tmout)
- rcv_dtq(ID dtqid, VP_INT *p_data)
- trcv_dtq(ID dtqid, VP_INT *p_data, TMO tmout)
- wai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn)
- twai_flg(ID flgid, FLGPTN waiptn, MODE wfmode, FLGPTN *p_flgptn, TMO tmout)
- rcv_mbx(ID mbxid, T_MSG **ppk_msg)
- trcv_mbx(ID mbxid, T_MSG **ppk_msg, TMO tmout)
- get_mpf(ID mpfid, VP *p_blk)
- tget_mpf(ID mpfid, VP *p_blk, TMO tmout)
- wai_sem(ID semid)
- twai_sem(ID semid, TMO tmout)
- T_RELEASE_LOCK(lockobj)
- T_RELEASE_NESTED_LOCK(lockobj, lockobj1) lockobjのみ解放する
- T_RELEASE_LOCK_AND_DISPATCH(lockobj, dspreq)
- I_ACQUIRE_LOCK(lockobj)
- I_ACQUIRE_NESTED_LOCK(lockobj, lockobj1) lockobjのみロックする
- I_RELEASE_LOCK(lockobj)
- I_RELEASE_NESTED_LOCK(lockobj, lockobj1) lockobjのみ解放する
- CCB/EXCCB
- CCBの内容
- INIT prcid
- LOCKOBJ tsk_lock
- LOCKOBJ obj_lock
- QUEUE *p_ready_queue;
- UINT *p_ready_primap;
- TCB **p_runtsk;
- TCB **p_schedtsk;
- BOOL *p_enadsp;
- TMEVTN *p_tmevt_heap;
- UINT *p_last_index; タイムイベントヒープのインデックス
- CBTCB tsk;
- CBTCB sem;
- CBTCB flg;
- CBTCB dtq;
- CBTCB mbx;
- CBTCB mpf;
- CBTCB cyc;
- FP p_activate_r;
- FP p_call_cychdr;
CCBの登録内容の初期化 EXCCBは各モジュールの初期化ルーチン(xxx_initialize())で初期化される. その後,EXCCBからCCBにコピーが行われる.
- ターゲット依存部
- ターゲット依存部の多くはJSPカーネルと共通である.ここでは,JSPカー ネルのターゲット依存部をFDMPカーネルに流用するための情報として,Nios2 における,JSPカーネルとFDMPカーネルのターゲット依存部の相違点ついてま とめる.
- cpu_config.h : 変更
- cpu_context.h : 変更
- cpu_support.S : 変更 ret_int ret_exc TCBのterflgをチェックして,trueならばディスパッチャーに飛ぶ activate_r スタックからではなく,tinibからtaskやexinfを取得するように変更 タスク例外のチェックコード call_texrtn から dispatch_call_texrtn に変更
- makeoffset.c : 変更 terflg, tinib, task, exinf のオフセットを取得するように変更
- nios2.h Mutexの定義とドライバを追加
- mp_config.c : 新規追加
- mp_config.h : 新規追加
- ディレクトリファイル構成 各ファイルの前の記号 N : 新規作成 S : シングルと同じ D : マルチプロセッサ用に手を入れた
- ./include : インクルードディレクトリ
- ./kernel : カーネル共通部
- ./systask : システムタスク
- ./library : カーネルライブラリ
- ./config/nios2 : プロセッサ依存部 (Nios2)
- ./config/nios2/nios2_dev_board/ : システム依存部
- ./config/microblaze/ : プロセッサ依存部(Microbalze)
- D : Makefile.config : プロセッサ依存部用Makefile
- S : cpu_config.c : プロセッサ依存モジュール ソースファイル
- D : cpu_config.h : プロセッサ依存モジュール ヘッダーファイル
- D : cpu_context.h : タスクコンテキスト操作ルーチン
- S : cpu_defs.h : プロセッサに依存する定
- S : cpu_insn.h : プロセッサの特殊命令のインライン関数定義
- D : cpu_support.S : プロセッサ依存モジュール アセンブリ言語部
- S : hw_serial.cfg : SIOドライバ(Microblaze UART Lite用)のコンフィギュレーションファイル
- S : hw_serial.h : シリアルI/Oデバイス(SIO)ドライバ(MicroBlaze opb_uart用)
- S : hw_timer.h : プロセッサ依存タイマモジュール
- D : makeoffset.c : オフセット情報生成ファイル
- D : mbelf.l : リンカスクリプト
- D : mbelf_rom.l : ROM化対応リンカスクリプト
- S : microblaze.c : 標準ペリフェラル用ドライバ ソースファイル
- D : microblaze.h : 標準ペリフェラル用ドライバ ヘッダーファイル
- S : microblaze_asm.inc : Microblazeアセンブラ用定義ファイル
- N : mp_config.c : マルチプロセッササポートモジュール ソースファイル
- N : mp_config.h : マルチプロセッササポートモジュール ヘッダーファイル
- S : start.S : カーネル用のスタートアップモジュール
- ./config/microblaze/pe1/ : システム依存部(MireMulti)
Copyright © 2006 by TAKAGI Nobuhisa.
このページは Mon Apr 3 23:49:11 2006 に Doxygen によって生成されました。
|
|