Zig版ASP3カーネルのCRE_TSKの中
こんにちは、めのんです!
前回予告したとおり、今回は静的APIのひとつCRE_TSKの中を覗いていくことにします。 まずはkernel/static_api.zigにあるCRE_TSKの定義をおさらいしましょう。
// タスクの生成 pub fn CRE_TSK(comptime p_self: *CfgData, comptime tsk_name: []const u8, comptime ctsk: T_CTSK) void { comptime var p_tsk = addItem(T_TSK, &p_self.tsk_list); p_tsk.name = tsk_name; p_tsk.inib = comptime task.cre_tsk(ctsk) catch |err| reportError("CRE_TSK", err); }
引数に関しては前回までに一通り見ましたので、今回は関数の内部に踏み込んでいきます。
まずはaddItem関数ですね。 この関数はCRE_TSK関数の定義の少し上で定義されています。
// コンフィギュレーションデータの追加 fn addItem(comptime T: type, comptime p_list: *LIST(T)) *T { comptime var item: T = undefined; item.p_next = null; if (p_list.tail) |tail| { tail.p_next = &item; } else { p_list.head = &item; } p_list.tail = &item; p_list.length += 1; return &item; }
addItem関数の最初の引数comptime T: typeは型そのものを引数として渡しているようです。 C++のテンプレートやC#のジェネリクスは<>で囲んで型を渡しますが、Zigではどうやら普通の引数と同じように扱うようですね。 CRE_TSK関数からはT_TSKを第1引数としてaddItem関数に渡しています。
T_TSKの定義も同じくstatic_api.zigにあります。
/// /// タスクのコンフィギュレーションデータ /// const T_TSK = struct { name: []const u8, inib: task.TINIB, p_next: ?*T_TSK, };
どうやら名前とTINIB、あとは線形リストにするための次ノードへのポインタのようですね。 TINIBというのはタスク初期化ブロックで、これはC版にもあったのでわかります。
どうやら、addItem関数ではタスクなどのカーネルオブジェクトの初期化ブロックを線形リストに追加しているようです。 コンパイル時に線形リストを組み立てられるというのはすごく強力な言語機能だと思いました。
次はtask.cre_tsk関数なんですが、関数の内容は別の機会に回すとして、今回は関数の呼び出し方に注目したいと思います。 念のため、該当部分をもう一度引用しますね。
p_tsk.inib = comptime task.cre_tsk(ctsk) catch |err| reportError("CRE_TSK", err);
おそらくtask.cre_task関数はエラー共用体を返すのだと思います。 Zigではエラー共用体といって、値とエラーのどちらかといった返却値型を指定することができるんです。
で、普通はエラー共用体を返す関数は
p_tsk.inib = try task.cre_tsk(ctsk);
のように前にtryを付けて呼び出します(簡単にするためにcomptimeは省略しました)。 こうすることで、もしtask.cre_tsk関数がエラーを返せば、ただちにそのエラーを呼び出し元に返します。
そうしたくない場合は、今回のようにcatchを使います。 catchに続く|err|で発生したエラーがerrに格納されます。 それに続けてエラー発生時の処理を書くことができます。
といった感じで、CRE_TSK関数は定義されていました。
この辺りからだんだんとZigらしくなってきましたね。 とくにコンパイル時に線形リストを構築するのにはビックリしました。
次回はどうするか未定ですが、同じくZig版ASP3カーネルを扱うことになると思います。 task.cre_tsk関数の中を見ていってもいいんですけど長いんですよね。 夜までにどうするか考えておきます。
それでは!!