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が表示されない」と表記しましたが、他のものより非常に遅いだけで表示自体はできていたようです。
マルチタスクの詳細設定
ある程度汎用化されているものの現段階でマルチタスクは 全てのタスクを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命令やっとるだけかな(待機中)。 超高速で移動して待機ってなんか勿体無い。 各移動先から手裏剣投げれると面白いかな。 でもマルチタスクの本質として各移動先で別の処理ができる、というのが重要だから、 移動先からいろいろ(手裏剣以外にも鎌とかマキビシとか)ぶん投げれれば楽しいかな。
- 作者: 川合秀実
- 出版社/メーカー: 毎日コミュニケーションズ
- 発売日: 2006/03/01
- メディア: 単行本
- 購入: 36人 クリック: 735回
- この商品を含むブログ (299件) を見る
*1:お店の行列の割り込みとかにイメージが近いけど、割り込みという概念はすでに使っているので紛らわしい