自作OSに挑戦する日記 16日目
「30日でできる!OS自作入門」を読んで分かったことや、とりあえず書いておきたいことなどを書いていきます。
この本はChapterが1から30まであるので、各チャプター毎に1記事書いていきます。
Chapter 15 「マルチタスク - 2」
今回やった内容
- マルチタスク完成
- タスクに優先順位をつける
環境
- メインPC
- MacBook Pro (13-inch, 2017, Four Thunderbolt 3 Ports)
- macOS Mojave 10.14
- 自作OSを動作させる環境
作業記録
15日目までで簡単なマルチタスクは実装できました。ただまだ2つしかタスクを扱えないので、16日目でもっと強化していきます。
まず、シートの時と同じように1つのタスク情報をもつ構造体と、複数のタスクをまとめて管理するような構造体をそれぞれ作ってあっげます。
#define MAX_TASKS 1000 struct TASK{ int sel, flags; struct TSS32 tss; }; struct TASK_CTL{ int now, running; struct TASK task_addr[MAX_TASKS]; struct TASK tasks[MAX_TASKS]; };
TASK_CTL内のnowで現在実行しているタスクの task_addr 内での添字を、runningでTASK_CTLで管理しているタスクの数を持ちます。このnowとrunningを変更することでタスクスイッチを行います。
また構造体だけでなく、TASK_CTLの初期化関数やタスクスイッチ関数も作ってあげます。
これで、複数タスクの管理ができるようになったのでウィンドウを増やしてみます。ウィンドウ毎にシートとタスクを作って実行します。それぞれのタスクではひたすら数を数えるような処理を行わせます。
ウィンドウがたくさん pic.twitter.com/gtHpKIRV83
— ゆん (@yn0014) March 11, 2019
OSっぽい…!静止画なので動きが分からないですが、タスクそれぞれでちゃんと高速カウントが行われています。
ここまでで、複数のタスクが管理できるようになりました。しかし今のままだと全てのタスクに平等にCPUが割り当てるようになっているので、マウスの描画処理など他よりも優先させたいものがあった時に不便です。
ということでタスクそれぞれに優先度をつけて、優先度が高いタスクはCPUの割り当て時間を長くするようにしてあげます。
struct TASK{ int sel, flags; int priority; struct TSS32 tss; }; void task_switch(void){ ~(略)~ // タスク切り替え struct TASK *task = task_ctl->task_addr[task_ctl->now]; timer_set(task_timer, task->priority); // ←ココ if(task->flags >= 2){ far_jmp(0, new_task->sel); } }
タスクの優先度がそのまま切り替え時間になります。分かりやすい。
OSを使っていると優先度が同じ他のタスクより優先してタスクを実行させたいという時があるかもしれません…(あるかもではなく確実にある)。ということでレベルという概念を導入します。
ちなみにここまで実装したものを実行するとマウスやキーボードの反応が非常に遅く優先度の恩恵をあまり得ることができません…。レベル導入後は軽快に動いてくれるようになります。
レベルまで実装するとこうなります。
/* multitask.c */ #define MAX_TASKS 1000 #define MAX_TASKS_LV 100 #define MAX_LEVELS 10 struct TASK{ int sel, flags; int level, priority; struct TSS32 tss; }; struct TASK_LEVEL{ int running, now; struct TASK *task_addr[MAX_TASKS_LV]; }; struct TASK_CTL{ int now_level; char do_level_change; struct TASK_LEVEL level[MAX_LEVELS]; struct TASK tasks[MAX_TASKS]; };
TASK_LEVELという構造体が新しく仲間入りしました。TASK_CTLではレベルの数だけTASK_LEVELをもち、TASK_LEVELではそのレベルに登録されているタスクを持ちます。タスクスイッチ時には、それぞれのレベルを上から見ていって1つでもタスクが登録されていたらそのレベル内でスイッチし続けます。
つまり、登録されている中で一番高いレベルのタスクのみが実行され続け、それより下のレベルのタスクは実行されません。下のレベルが実行されるには上のレベルのタスクが終了するのを待つしかないということになります。
1番上のレベルにメインループを、それより1つ下のレベルにカウンタを配置してみました。これで実行してみると…
16日目完成〜! pic.twitter.com/fPPUrM8dKh
— ゆん (@yn0014) March 12, 2019
マウスやキーボードの反応が素早くなりました。カウンタの部分をじっとみてみると、マウスなどの割り込みが発生しているときは少しカウント速度が遅くなっています。ちゃんとレベルの処理が実装できているみたいです〜!
まとめ
マルチタスク完成です〜!16日目初めて最初の方はマウスやキーボードの反応がとても遅くなっていたのでどうなるものかと思ってましたが、レベルの実装で元の動きを取り戻してくれました(良かった…)。
本に書かれている内容だと優先度の実装部分で軽快に動くみたいですが、自分の環境ではそうはなりませんでした…不思議です。コードは間違えていないのでエミュレータのバージョンなどが原因だと予想しています。
16日目まででOSとしての基本機能はほぼ完成したのでは…と思っていますがどうなんですかね(๑╹ω╹๑ )