めのん@ひとりプログラミング同好会

このブログはすべてフィクションであり、実在の人物、団体とは一切関係ありません

Zig版ASP3カーネルのact_tsk

こんにちは、めのんです!

昨夜は久々に違う話題にしましたけど、ここのところずっとZig版TOPPERS/ASP3カーネルの話題を取り上げています。

今回はact_tskというサービスコールを見ていきたいと思います。 念のためact_tskについて少しだけ解説しておきますね。

act_tskはμITRONからあるサービスコールでタスクを起動するためのものです。 正確にいうとタスクを休止状態から実行可能状態に遷移させます。

静的APIのCRE_TSKでTA_ACTを指定したタスクはact_tskを呼ばなくても起動しますが、それ以外のタスクや一度ter_tskで休止状態にしたタスクはact_tskを呼ぶまで起動しません。 act_tskの呼び出しはキューイングできるので、キューイングされている状態でcan_tskやter_tskを呼べばキューが1つずつ減っていくんだったと思います(ちょっとうろ覚えです)。 といっても、ASP3カーネルではキューイングできるのは1つまでなので、あまりキューイングという感じはしません。

では、早速act_tskの定義を見てみましょう。 kernel/task_manage.zigに定義があります。

///
///  タスクの起動[NGKI3529]
///
pub fn act_tsk(tskid: ID) ItronError!void {
    var p_tcb: *TCB = undefined;

    traceLog("actTskEnter", .{ tskid });
    errdefer |err| traceLog("actTskLeave", .{ err });
    try checkContextUnlock();                   //[NGKI1114]
    if (tskid == TSK_SELF and !target_impl.senseContext()) {
        p_tcb = p_runtsk.?;                     //[NGKI1121]
    }
    else {
        p_tcb = try checkAndGetTCB(tskid);      //[NGKI1115]
    }
    {
        target_impl.lockCpu();
        defer target_impl.unlockCpu();

        if (isDormant(p_tcb.tstat)) {
            make_active(p_tcb);                 //[NGKI1118]
            requestTaskDispatch();
        }
        else if ((p_tcb.p_tinib.tskatr & TA_NOACTQUE) != 0
                     or p_tcb.flags.actque == TMAX_ACTCNT) {
            return ItronError.QueueingOverflow; //[NGKI3528]
        }
        else {
            p_tcb.flags.actque += 1;            //[NGKI3527]
        }
    }
    traceLog("actTskLeave", .{ null });
}

今回は見所がたくさんありますね。

まずはerrdeferです。 関数の中でtry演算子を使うと、エラーが発生したときにただちに関数からリターンするんですけど、そのときに呼び出される処理を登録するためのものです。 今回はtraceLogを呼び出すようになっています。

次に、

        p_tcb = p_runtsk.?;                     //[NGKI1121]

この部分ですが、うしろに .? を付けることでp_runtskがnullだったときには何もしないことを意味しています。

先ほどはerrdeferが登場しましたが、今度はdeferが登場しています。 これはエラーが発生したかどうかに関係なく、現在のスコープから抜ける際に呼び出す処理を登録しています。 tryブロックにfinallyを使える言語は多いですが、そんな感じでしょうね。

μITRONやC版ASP3カーネルのact_tskの返却値型はERですけど、このact_tsk関数はItronErrorとvoidのエラー共用体になっています。 Zig版ASP3カーネルのサービスコールは、エラーが発生せず真偽値を返すものをのぞけば、全部エラー共用体を返すようになっています。

C版と同じシグニチャを持つ関数も用意されているようで、kernel/c_api.zigに定義があります。

// act_tskのC言語API
export fn act_tsk(tskid: ID) ER {
    return callService(task_manage.act_tsk(tskid));
}

callService関数は、エラーが発生しなければE_OKにするなどの変換を行うためのものなので、サラッと流してもいいと思います。

というわけで今回はact_tskを見てみました。 関連するサービスコールということで、次回はcan_actを見ていきたいと思います。 余力があればter_tskも見ていきたいですね。

それでは!!