最後に、タスクの起動部分を見てみましょう。リスト8は、OSの起動時に最初に起動される「初期タスク」です。内部では「kz_run()」というシステムコールにより、コンソールドライバタスク(consdrv)とコマンド処理タスク(command)を起動します。さらにその後は、アセンブラの“sleep命令”を実行する無限ループに入ります。このようなタスクは「アイドルタスク」などと呼ばれます。初期タスクがそのままアイドルタスクとして動作しているわけです。
static int start_threads(int argc, char *argv[]) { kz_run(consdrv_main, "consdrv", 1, 0x200, 0, NULL); kz_run(command_main, "command", 8, 0x200, 0, NULL); kz_chpri(15); /* 優先順位を下げて、アイドルスレッドに移行する */ INTR_ENABLE; /* 割り込み有効にする */ while (1) { asm volatile ("sleep"); /* 省電力モードに移行 */ } ……(後略)……
さて、これはどのように動作するのでしょうか? 実はこのアイドルタスクは、無限ループに入る前に「kz_chpri()」というシステムコールを用いて、優先度を最下位に下げています。このため、他に動作可能なタスクが存在する場合には、アイドルタスクは動作しません。
しかし、他に動作可能なタスクがいなくなると、アイドルタスクが動作を開始します。リスト8の通り、アイドルタスクは無限ループでsleep命令を実行するだけです。これはCPUの命令実行を止め、割り込み待ちになる命令です。これにより、割り込みが入るまで消費電力を節約できます。
シリアル送信処理を例に考えてみると、先述したようにシリアル送信を行う場合、送信が完了するまで後続の文字は送信できません。今回のプログラム構成では、この場合、“シリアル送信完了割り込み待ち”の状態に入ります。ここでコンソールドライバタスクやコマンド処理タスクはすることがないため、動作を停止しています(kz_recv()システムコールによりメッセージ待ちの状態になっています)。これにより、アイドルタスクが動作し、sleep命令を実行して省電力モードに移行させます。
シリアル送信割り込みが入ると、CPUが動作を再開します。そして、割り込みハンドラにより後続の文字が送信され、送信完了待ちになるとまたアイドルタスクが動作して省電力モードに入ります。このようにして、CPUがすることがなくなる(処理すべきタスクがない)とアイドルタスクが自動的に動作して、割り込みが入るまで省電力モードに移行してくれます。
このような細かなCPU制御はOSを使わなくともできるのですが、OSを利用することで、“やりたいこと”を独立させて簡便に記述できます。例えば、リスト8のアイドルタスクの処理は、無限ループでsleep命令を実行しているだけです。つまり「暇なときには省電力モードに入る」という“やりたいこと”をタスクとして独立させ、シンプルに記述できているわけです。シリアル受信や送信の処理も同様です。
これが組み込み機器でマルチタスクOSを利用する際の大きなメリットです。単一のCPUで複数の制御(例えば、今回はシリアル受信、シリアル送信、コマンド解析、省電力管理)を効率良く行うために、組み込み向けのマルチタスクOSは利用されます。
OSを利用するメリットというと、どうしても「多彩なデバイスを利用できるようにする」といったことが最初にいわれがちですが、それだけでは単なるライブラリ利用と変わりません。複数のデバイスを並列で制御したい場合に、マルチタスクにすることで制御内容を独立させ、プログラムの粒度を上げ、理解しやすいシンプルなプログラム構成でCPUを効率良く動作させることこそが、組み込み向けのマルチタスクOSを利用するメリットです。
今回までの内容で、組み込み向けマルチタスクOSとしての機能が一通りそろいました。次回からは、いよいよ“Webサーバの動作に向けて、ネットワーク機能を実装”していきます。ご期待ください! (次回に続く)
坂井弘亮(さかいひろあき)
某企業でネットワーク系の開発を行いながら、個人で組み込みOS「KOZOS」の開発や書籍/雑誌記事執筆、各種セミナーでの発表やイベント出展、勉強会の開催など多方面で活動中。IPAセキュリティ&プログラミングキャンプ講師(2010〜)。著書は「12ステップで作る組込みOS自作入門」など多数。
Copyright © ITmedia, Inc. All Rights Reserved.