技術日誌

DB,Java,セキュリティ,機械学習など。興味のあることを雑多に学ぶ

30日OS自作本16日目

16日目の内容です。 タスク管理の機構を強化するような内容です。

タスク管理

15日目でハードコードされた部分を無くします。タスクも構造体の配列で管理するようにします。

#define MAX_TASKS       1000   /* 最大タスク数 */

//前回から引き続き登場task state segment
struct TSS32 {
    int backlink, esp0, ss0, esp1, ss1, esp2, ss2, cr3;
    int eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
    int es, cs, ss, ds, fs, gs;
    int ldtr, iomap;
};

//タスク
struct TASK {
    int sel; /* selはGDTの番号のこと */
  int flags; //0:未使用 1:使用中 2:動作中
    struct TSS32 tss; //task state segmentへの参照
};

//タスク制御
struct TASKCTL {
    int running; /* 動作しているタスクの数 */
    int now; /* 現在動作しているタスクがどれだか分かるようにするための変数 */
    struct TASK *tasks[MAX_TASKS];//タスクの参照の配列
    struct TASK tasks0[MAX_TASKS];//タスクの配列
};

細かいですが、flagsは何で複数形なんだろう?変数の型が配列とかならわかるけど、気になる

スリープ

  • 実行する必要のないタスクはマルチタスクの対象としたくない
  • 例:マウス描画処理はマウス割り込み発生時以外は動かす必要がない。
  • マルチタスクの対象から外す -> スリープさせる
  • マルチタスク制御用の構造体(taskctl)のマルチタスク対象一覧(tasks[])から一時的に外す
    • これをスリープという
    • task_sleep()関数で指定したタスクのflgを1にする

動きが不安定なソース

自分の環境だとやはり13日目以降、安定しないソースがいくつかあるようです。 本章は全てのソースが何らかの動作不良を抱えていました。

ソース 不具合内容
harib13a 動きがガタガタ
harib13b 動きがガタガタ
harib13c 表示が非常に遅い
harib13d 表示が非常に遅い
harib13e 動きがガタガタ

追記:harib13c,dは「画面の3/4が表示されない」と表記しましたが、他のものより非常に遅いだけで表示自体はできていたようです。

www.youtube.com

マルチタスクの詳細設定

ある程度汎用化されているものの現段階でマルチタスクは 全てのタスクを0.002秒ごとに実行しているだけになります。

priority、levelという概念を導入し、マルチタスクを更に高機能化します

一つのタスクにかかる時間を調整する

一律に0.001秒ごとに切り替え、ではなく、taskAは0.1秒実行、taskBは0.01秒実行というふうな タスクごとの割り当て時間を可変的に設定できると便利です。こちらをTASKにpriorityという変数を導入し、 タスクきりかえのタイマーを常に0.002秒ではなく、任意の時間を設定します。

struct TASK {
    int sel, flags; /* selはGDTの番号のこと */
    int level, priority;
    struct TSS32 tss;
};

導入まえ

timer_settime(task_timer, 2);

導入後

timer_settime(task_timer, task->priority);

タスクの優先度をLEVELで制御する

スリープ機能の導入により、マウスの描画(taskA)はマウス割り込み発生時にのみ実行するようになっています。

まちタスクがこんな感じになっている時,

  • task1(実行ずみ)
  • task2(実行中)←runnning
  • task3(未実行)

task2が実行中、task3が未実行の周期でマウス割り込みが発生すると

  • task1(実行ずみ)
  • task2(実行中)←runnning
  • task3(未実行)
  • taskA(未実行スリープから復帰)

のようになり、マウス描画(taskA)はtask2のマルチタスク終了後、task3の実行時間を更に待つことになります。 task3が一瞬で終わるようにpriorityが設定されていればいいのですが、こちらに長い実行時間が割り当てられている場合、マウス描画がもたつくことになります。

そこでLEVELという概念を導入し、task3の実行前にtaskAを先に実行させるような仕組みを作ります。*1

  • task1(実行ずみ)
  • task2(実行中)←runnning
  • taskA(未実行スリープから復帰) !!!!ここに並ばせる
  • task3(未実行)
struct TSS32 {//変更なしなので略。
};
struct TASK {
    int sel, flags; /* selはGDTの番号のこと */
    int level, priority;
    struct TSS32 tss;
};
struct TASKLEVEL {
    int running; /* 動作しているタスクの数 */
    int now; /* 現在動作しているタスクがどれだか分かるようにするための変数 */
    struct TASK *tasks[MAX_TASKS_LV];
};
struct TASKCTL {
    int now_lv; /* 現在動作中のレベル */
    char lv_change; /* 次回タスクスイッチのときに、レベルも変えたほうがいいかどうか */
    struct TASKLEVEL level[MAX_TASKLEVELS];
    struct TASK tasks0[MAX_TASKS];
};

命名の文句ばっかりで申し訳ないですが、個人的にLEVELの構造体の名前にpriority(優先度)という単語を採用する方がしっくりきますね。。。

感想

15日目に書かれている内容ですが、マルチタスクを影分身と例えているところは言い得て妙。 影分身の移動先がマルチタスク対象の実行命令(far JMP)。 まぁ影分身ってたくさんいるって誤魔化してるだけだから全員HLT命令やっとるだけかな(待機中)。 超高速で移動して待機ってなんか勿体無い。 各移動先から手裏剣投げれると面白いかな。 でもマルチタスクの本質として各移動先で別の処理ができる、というのが重要だから、 移動先からいろいろ(手裏剣以外にも鎌とかマキビシとか)ぶん投げれれば楽しいかな。

30日でできる! OS自作入門

30日でできる! OS自作入門

*1:お店の行列の割り込みとかにイメージが近いけど、割り込みという概念はすでに使っているので紛らわしい