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

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

Zig版ASP3カーネルのT_CTSK

こんばんは、めのんです!

お昼の投稿ではCRE_TSKの各引数について見ていきました。 その中の最後の引数ctskの型T_CTSKは結構複雑だったので後回しにしました。 今回はT_CTSKの各フィールドについて、さらに深堀していくことにします。

まずはT_CTSK型の定義を再掲することにしましょう。

///
///  パケット形式の定義
///
pub const T_CTSK = struct {
    tskatr: ATR = TA_NULL,          // タスク属性
    exinf: EXINF = castToExinf(0),  // タスクの拡張情報
    task: TASK,                     // タスクのメインルーチンの先頭番地
    itskpri: PRI,                   // タスクの起動時優先度
    stksz: usize,                   // タスクのスタック領域のサイズ
    stk: ?[*]u8 = null,             // タスクのスタック領域
};

簡単な整数値はいいと思いますので、難しいものに絞って見ていきますね。

ますはexinfです。 型EXINFはinclude/t_stddef.zigで次のように定義されています。

pub const EXINF = ?*c_void;         // 拡張情報(★Zigの制限に対応)

わかりにくい型定義ですけど、c_voidというのはCのvoid型ですのでc_voidというのはCのvoidに相当します。 Zigではポインタであってもnullableにするには?がいるようですので?*c_voidになっているんだと思います。

で、この型の値を作るための関数がcastToExinfです。 定義は同じくinclude/t_stddef.zigにありました。

///
///  EXINF型への強制変換
///
pub fn castToExinf(exinf: var) EXINF {
    return switch (@typeInfo(@TypeOf(exinf))) {
        .Null => null,
        .Bool => @intToPtr(EXINF, @boolToInt(exinf)),
        .Int, .ComptimeInt => @intToPtr(EXINF, exinf),
        .Enum => @intToPtr(EXINF, @enumToInt(arg)),
        .Pointer => |pointer|
            @ptrCast(EXINF, if (pointer.size == .Slice) exinf.ptr else exinf),
        .Array => @ptrCast(EXINF, &exinf),
        .Optional =>
            if (exinf) |_exinf| castToExinf(_exinf) else @intToPtr(EXINF, 0),
        else => @compileLog(@typeInfo(@TypeOf(exinf))),
    };
}

なんか大変ですね。 たったこれだけのことに型スイッチが必要なんですねー

もとがCなのを強引にZigに移植しようとするからこうなるんだと思います。 最初からZig向けに設計していればもう少し簡単になったと思います。

ところで、.Nullや.Boolや.Intというのは見れば何のことなのか想像はつくんですけど、ドキュメントにはそのものずばりの記述がなかなか見つかりませんでした。 結局ライブラリのソースを読まないといけないので、このあたりがZigはまだまだ敷居が高いなあと思います。

次はTASKです。 定義はinclude/kernel.zigにありました。

pub const TASK   = fn(exinf: EXINF) callconv(.C) void;

思ったより普通でした。 パッと見て納得できる関数へのポインタ型でしたね。 これはCがわかっていれば簡単に理解できると思います。

stkもやや複雑ですが、これについてはお昼の投稿で読み解きました。 あとはそんなに難しくないので大丈夫だと思います。

これでCRE_TSKの引数については一通り読み解くことができました。 次回はCRE_TSK関数の内容を読み解いていくことにします。 実質的にはaddItem関数とtsk.cre_tsk関数ですね。 一度に終わるかどうかわかりませんけど。

それでは!!