初心者でもわかる RTOS開発入門 (2)

概要

本記事は、eForceの【開発者から学べる入門ウェビナー】RTOS基礎編-座学をテキスト化したものです。前回はRTOS(リアルタイムOS)の動作の仕組みや、RTOS上でのアプリケーション作成の流れ、μC3(マイクロシーキューブ)が採用しているμITRON(マイクロアイトロン)の概要について解説しました。今回はRTOSの代表的な機能である時間管理、スケジューラーの仕組みとマルチタスク機構について解説します。

本記事でわかること

  • 時間管理:システム時刻管理 / 周期処理の機能
    ・定周期処理
    ・タイミング制御
  • スケジューラの仕組み
    ・優先度の高いタスクから実行
    ・最初に実行待ち状態に入ったタスクから実行(FCFS方式)
  • マルチタスク機構
    ・タスク単位での機能分割
    ・各タスクの優先度設定

スケジューラーの仕組みとマルチタスク機構

1.時間管理

時間管理の代表的な機能

μITRONは、カーネルタイマを利用して時間を管理します。時間管理の代表的な機能を紹介します。RTOSが時間管理をしているため、次に示す機能が利用できます。

処理遅延(dly_xxx)
自タスクをシステムコールが呼び出された時刻から指定される時間の間、待ち状態に遷移させます。

周期起動  (cyc_xxx)
システムを構築する際に一定時間毎に何らかの処理をしたい時に利用します。
周期ハンドラは一定周期で起動されるタイムイベントハンドラです。

タイムアウト (txxx_xxx)
OSの機能を利用するためにシステムコールで呼び出しを実行後、指定時間が経過しても処理が実行されなかった場合にタイムアウトを行います。

アラーム (alm_xxx)
時間経過の監視に用います。タスクでアラームをセットし、指定時間内に次の呼び出しが行われない場合などに、RTOSが指定した関数を呼び出します。

システムコール(API)の名称

システムコールとは実行中のプログラムがOSの機能を呼び出すために使用する仕組みのことです。また、その命令や関数などのAPIをさします。

xxx_yyy XXXの部分が操作の種類を表す。YYYの部分が操作の対象(オブジェクト)を表す。
fxxx_yyy 強制を示す。
ixxx_yyy タスクコンテキスト以外から使用するシステムコール。μ3Cの場合は、iがつくシステムコールもつかない場合と同じ実装。
pxxx_yyy ポーリング。待つ可能性がある場合はタイムアウトエラーでリターン。
txxx_yyy 待ちに入る場合、指定された時間まで待つ。時間が経過しても処理が完了しなければタイムアウトエラーでリターン。
vxxx_yyy インプリメント依存を示す。

 

2.マルチタスク機構

マルチタスク機構とは

RTOSの中心部分であるカーネルが持つ主な機能の一つに、マルチタスク機構があります。マルチタスクとは、複数のタスクを並列に処理するために、CPUを仮想化、多重化するシステムのことですが、実際にはある時刻にCPUが実行できるのはひとつのタスクのみです。RTOSは、時分割で制御して複数のタスクの実行を疑似的に平行実行させる機構を持っています。

マルチタスク機構は、大きくわけて以下の2つで構成されています。

スケジューリング
コンテキスト切替

これよりスケジューリングを解説し、コンテスト切替は5章で解説します。

LEDの点滅処理で時間管理を考える

時間管理の実例としてLED点滅のサンプルを示します。Task Aは、実行状態、実行可能状態、待ち状態の三つの状態があり、LED点灯処理(実行状態)→dly_tsk(待ち状態)→イベント→実行可能状態→LED消灯(実行状態)→dly_tsk(待ち状態)→イベント…と繰り返すことによりLEDを点滅させています。

dly_tskは自タスクの遅延です。自タスクをシステムコールが呼び出された時刻からdlytimで指定される時間の間、待ち状態に遷移させます。
指定時刻が経過後タスクの待ちが解除され、再びタスクが実行可能状態を経て実行状態に遷移します。

タスクの状態遷移とディスパッチ

 

eForce社のRTOS μC3 / Compactにおいて、基本の状態遷移は4つの状態で表すことができます。

実行状態(RUNNING):現在タスクが実行中の状態
実行可能状態のタスクの中で最も優先順位の高いタスクの状態

実行可能状態(READY):実行可能になった状態
タスクを実行する条件は整っているが、当該タスクより優先度の高いタスク
または同一優先度で先に実行可能状態となったタスクが実行状態のため実行できない状態

待ち状態(WAITING):待ち解除の条件が満たされるのを待っている状態
条件が満たされると実行可能状態に遷移

休止状態(DORMANT):タスクが起動されるのを待っている状態
タスクの起動前、および タスク終了後の状態

LED点滅制御における具体的な遷移については、RTOSウェビナーの動画にて詳細を解説しております。(19:40 – 24:00)
状態遷移の解説は文章では表現しきれないため、是非ウェビナーの動画で参照してください。

3.スケジューラーの仕組み

タスクの優先度とレディーキュー

実行可能状態における優先順位と優先度の関係図を示します。

タスクは休止状態から起動を経て実行可能状態に遷移します。タスクの状態は常にOSによって監視され、スケジューリングに従ってプロセッサが実行しているタスクを切り替えるディスパッチが実行されます。ただし、ディスパッチが起こらない状態では、ディスパッチが起こる状態になるまでディスパッチは保留され、この間に実行可能状態に遷移したタスクが複数ある場合を考えます。実行可能状態に遷移したタスクはレディーキューに登録されます。レディキューとは、実行可能状態にあるタスクのつながる行列をさします。全てのタスクには優先度が与えられており、実行可能状態のタスクが複数ある場合は、そのなかで最も優先度の高いタスクからディスパッチにより実行状態に遷移します。

同一優先度のタスクが複数存在する場合は、先にレディーキューに並んだ順でタスクを実行します(FCFS方式)。また、スケジューラーの機能ではプリエンプト・ディスパッチにより、タスク切替が行われることがあります。プリエンプトとは、実行中のタスク処理を中断して他の優先度の高いタスクに差し替えることをさします。例えば、現在のタスクFよりも優先順位の高いタスクCが実行可能状態になった場合は、タスクFから実行する権利を取り上げ、タスクCに実行権を与えることができます。

タスクの優先度とレディーキューについては、RTOSウェビナー動画にて詳細を解説しています。(24:00-27:10)

RTOSの動作開始

RTOSなしの場合はCPUを起動させるブート処理や初期化を行った後に各処理を実行させますが、RTOSを動作させる際にはブート処理・初期化とタスク実行の間に中間の処理が必要となります。


具体的には上図のように、ユーザがメイン関数内にタスク処理からタスク起動までの一連の処理を作らなければなりません。ITRONでは、タスク生成情報など事前に生成できる情報をコンフィグレーションと呼ぶ処理で実際のコードや変数として生成することが可能です。eForceの一部のパッケージ製品では、WindowsのGUIアプリケーションであるコンフィグレータが付属しており、GUIの画面上でOSの設定が可能です。コンフィグレータを用いてこれらの処理の構築・生成が可能となることで、RTOS導入へのストレス低減に繋がります。

同期処理:優先度の設定も併用

同期処理とは、タスクの状態を直接的に操作することによってタスク間の同期を行う処理です。一例として、ゲームのコントローラのボタンが押されたときにパンチをするという動作を考えます。通常、パンチをする動作のTask Bはwai_flgで待ち状態に設定されています。ボタンが押された際に割り込みサービスルーチンが起動し、イベントフラグ (i)set_flgで待ち状態が解除されます。Task Bは優先度が高いため即時実行状態になり、パンチをくりだします。
ここでは、RTOSの機能であるイベントフラグを利用しています。簡単な解説を次章で示します。

4.イベントフラグの動作紹介

条件待ち合わせ

せっかくなので複数タスクがある場合も考えてみましょう。マルチタスク処理では、各タスクに対して必要なイベントが発生するまで待ち状態となります。そのため、各タスクに対するイベントが発生した時に待ち状態が解除される動作が必要となりますイベントフラグとは、イベント(事象)をフラグの有無(ビットのON/OFF)という組み合わせで表現し、タスク間やタスクと割込みサービスルーチン間で通知することができる機能です。

TaskSを十字ボタンの左右、TaskFを十字ボタンの上下、TaskBを黄色いボタン、TaskKを赤いボタンにそれぞれ対応した機能を実装したとします。コントローラ側の処理は、割込みサービスルーチンで作成されています。コントローラを操作することで割込み処理が呼び出され、操作されたボタンに応じてイベントフラグによってタスクに通知します。赤いボタンが1ビットめ、黄色のボタンが2ビットめと予め定めておき、受け取り側でイベントフラグが対応するビットがONになるのを待つと、複数のボタンに応じた処理の構築が可能になります。上図だと最大で32種類のイベントが割り付け可能ということになります。

優先度ベースのRTOSならではのメリット

上図は、タスクの状態遷移を時系列で示したものです。dly_tskなど待ち状態に遷移するシステムコールを呼び出した場合にも、タスクの切り替わりが発生します。タスク優先度は1が最高で、数が多いほど低くなります。図のように、低優先度のTaskCは、TaskAとTaskBが待ち状態となることで初めて実行状態になります。また、先ほどのイベントフラグのパンチをTaskBとすると、コントローラが押されたことで iset_flgを呼び出し、TaskBが実行状態になりパンチをすることが示されています。

同期処理と優先度べースのRTOSならではのメリットについて、RTOSウェビナー動画にて詳細を解説しております。(28:45-34:20)

タスクスケジューリングの詳細例

イベント発生時にシステムコールを呼び出した場合にタスクの切り替わりが発生します。図の赤い部分のタスクの遷移について解説します。

Task Aが待ち状態になったあとのTask BとTaskCの動きを時系列で見てみましょう。この遷移の発生については、TaskBがイベントフラグにより待ち状態が解除された場合のタスク遷移状態を5つのステップで表現しています。

(1) (2) (3) (4) (5)
TaskB
優先度1
B1
待ち状態
B2
待ち解除
B3
実行可能状態
B4
ディスパッチ
B5
実行状態
TaskC
優先度2
C1
実行状態
C2
実行状態
C3
実行状態
C4
プリエンプト
C5
実行可能状態

(1)  Task Bが待ち状態、Task Cが実行状態です。
(2)  イベントフラグの待ち解除がされたことで Task Cが実行可能状態に遷移します。
(3)  Task Bが実行可能状態となります。ここでは Task B3(実行可能状態)> Task C3(実行状態)と優先度の不均衡がおこります。
(4)  (3)で優先度の不均衡が発生したことから、スケジューラーによってTask Bを実行可能状態から実行状態にディスパッチし、
Task Cを実行状態から実行可能状態にプリエンプトします。
(5)    Task C5(実行可能状態)< Task B5(実行状態)となり優先度が均衡となります。これでTask BとTask Cの状態遷移が行われています。

詳細な動きについてはRTOSウェビナーの動画にて解説しております。(35:20-38:05)

 

RTOS動作(タスクスケジューリング)のまとめ

ポイント
  • タスク優先度は1が最高で、数が大きいほど低くなる
     参考例(μC3/Compact:1~16)(μC3/Standard:1~31)
        ※ eForce製品での設定範囲
  • システムコールを呼ばなければ低優先度のタスクに状態が遷移しなくなる可能性がある
  • プリエンプト・ディスパッチにより、RTOSがタスク切替を実施
  • タスク間協調:複数のタスクが連携してシステムを構築

5.コンテキスト切替

 

コンテキストの切替・概要

RTOSでは発生したイベントによってはタスクの切り替え(ディスパッチ)を実施することがあります。実際に、タスク内に記述されたアプリケーションについてはタスク切り替えは意識せずに作成しています。タスク切替は任意のタイミングに実行されます。図はOSがタスクを切り替えるときの例を示したものです。現在実行中のTask A ではその時の状態を保存し、待ち状態などに遷移します。かわりに実行状態になるTask Bでは前回待ち状態となった時の状態に復帰後、ディスパッチなどが実施されます。

RTOSで動作しているプログラムが実行される環境をコンテキストと呼び、タスク、タイムイベントハンドラ、割り込みハンドラでそれぞれコンテキストを持っていると考えます。コンテキストを切り替える場合には、CPUのプログラムカウンタ(PC)、スタックポインタ(SP)、汎用レジスタ(REG)など必要なレジスタ情報などを一度スタック空間に退避させる必要があります。そして再開時に前回のセーブデータを展開し復元します。

スタック領域を準備する


先述のとおり、コンテキストの切り替えには、実行中のタスクの状態(変数・レジスタの値)をすべてメモリ等に保存する必要があり、退避させるための専用のメモリ領域を確保しないといけません。このメモリ領域のことをRTOSでは
スタック領域と呼んでいます。この領域はアプリ作成時に定義する必要があります。このスタック作成のサイズはタスクで使用する変数とレジスタを保管するために十分な容量を持っていなければなりません。

仮にスタック領域定義が不足していて、実際の使用量が多くなることをスタックオーバーフローと呼びます。通常スタックオーバーフローが発生すると、書き換えてはいけないメモリを書き換えてしまったりすることで、プログラムが暴走するリスクがあります。システム全体にとっては致命的なエラーとなり、原因究明も難しいです。そのため、ユーザ側で必要になるスタック領域を算段して領域のサイズを指定する必要があります。

タスク間協調

RTOSでは機器に要求される機能ごとに独立した処理を実行するタスクを実装し、各タスクは、要求される時間内に処理が完了するよう優先度を割り当てます。複数タスクを並行処理する場合、タスク間でタイミングを合わせて連携動作させたりタスク間での情報交換、すなわちタスク間の協調が必要となります。タスク間協調のなかで、本記事ではイベントフラグについて例をあげて解説しましたが、μITRONで定義されいる機能を下図に示します。排他制御を実施するセマフォ、タスク間の通信を担うデータキュー、メールボックス等があげられます。

種類 特徴 μITRONによる手段(例)
排他 資源待ち合わせ セマフォ、(ミューテックス)など
同期 条件待ち合わせ イベントフラグ
通信 タスク間でのデータ交換 データキュー、メールボックス(メッセージバッファ)

【開発者から学べる入門ウェビナー】RTOS基礎編-座学の動画は、下記URLからダウンロードいただけます。

【開発者から学べる入門ウェビナー】RTOS基礎編-座学
~0.RTOSの動作の仕組みや、RTOS上でのアプリケーションの作成について解説~