Zig版ASP3カーネルのslp_tsk
こんにちは、めのんです!
平日になりましたので、今回はいつものようにZig版TOPPERS/ASP3カーネルの話題です。 念のため前回のリンクも貼っておきますね。
今回見ていくのはタスク付属同期機能の代表的なサービスコールのひとつslp_tskです。 slp_tskの定義はkernel/task_sync.zigにあります。
/// /// 起床待ち[NGKI1252] /// pub fn slp_tsk() ItronError!void { var winfo: WINFO = undefined; traceLog("slpTskEnter", .{}); errdefer |err| traceLog("slpTskLeave", .{ err }); try checkDispatch(); //[NGKI1254] { target_impl.lockCpuDsp(); defer target_impl.unlockCpuDsp(); var p_selftsk = p_runtsk.?; if (p_selftsk.flags.raster) { //[NGKI3455] return ItronError.TerminationRequestRaised; } else if (p_selftsk.flags.wupque > 0) { p_selftsk.flags.wupque -= 1; //[NGKI1259] } else { make_wait(TS_WAITING_SLP, &winfo); //[NGKI1260] traceLog("taskStateChange", .{ p_selftsk }); target_impl.dispatch(); if (winfo.werror) |werror| { return werror; } } } traceLog("slpTskLeave", .{ null }); }
実質二十数行しかない関数ですなんですが、本質的な処理はmake_wait関数にあるはずです。 確かC版のASP3カーネルでもそうなっていましたから。
Zigの文法的な見所はとくにないのですが、C版ではlock_cpu_dspやunlock_cpu_dspというマクロが使われていたので、どこで定義されているのか分かりにくかったのですが、Zig版ではtarget_impl.lockCpuDspのようになっているのでターゲット依存部で定義されていることがすぐにわかります。 こういうのはZigの利点かもしれませんね。
それでは、slp_tskの肝になるmake_wait関数の定義を見ていきましょう。 kernel/wait.zigに定義があるようです。
/// /// 待ち状態への遷移 /// /// 実行中のタスクを待ち状態に遷移させる.具体的には,実行中のタスク /// のタスク状態をtstatにしてレディキューから削除し,TCBのp_winfoフィー /// ルド,WINFOのp_tmevtbフィールドを設定する. /// pub fn make_wait(tstat: u8, p_winfo: *WINFO) void { p_runtsk.?.tstat = tstat; make_non_runnable(p_runtsk.?); p_runtsk.?.p_winfo = p_winfo; p_winfo.* = WINFO{ .p_tmevtb = null }; }
拍子抜けするほど短い関数でした。
内容を見ていくと、p_runtskが参照しているTCBに情報を設定しているほかはmake_non_runnable関数の呼び出しのようです。 make_non_runnable関数も見ていきましょう。 定義はkernel/task.zigにあります。
/// /// 実行できる状態から他の状態への遷移 /// /// p_tcbで指定されるタスクをレディキューに挿入する.また,必要な場合 /// には,実行すべきタスクを更新する. /// pub fn make_non_runnable(p_tcb: *TCB) void { const prio = p_tcb.prio; const p_queue = &ready_queue[prio]; p_tcb.task_queue.delete(); if (p_queue.isEmpty()) { ready_primap.clear(prio); if (p_schedtsk == p_tcb) { assert(dspflg); p_schedtsk = if (ready_primap.isEmpty()) null else searchSchedtsk(); } } else { if (p_schedtsk == p_tcb) { assert(dspflg); p_schedtsk = getTCBFromQueue(p_queue.p_next); } } }
見た感じだと、レディキューから指定したタスクを取り除いて、次に実行するタスクをp_schedtskに設定しているだけのようです。
slp_tskはセマフォやイベントフラグのようなタスク間同期・通信オブジェクトの状態変化を待ているわけではないですし、タイマーイベントを待っているわけでもありません。 wup_tskで起こされるまで待つだけなので、別のキューにつなぐわけでもなく単純なんだろうなと思いました。
次回はwup_tskかtslp_tskを見ていきたいのですが、タイマーイベントを先に見るならdly_tskが先の方がいいかもしれませんね。 今夜までに考えておくことにします。
それでは!!