RTLinuxは、 Linuxオペレーティングシステム全体を完全なプリエンプティブプロセスとして実行するハードリアルタイムオペレーティングシステム(RTOS)マイクロカーネルです。ハードリアルタイム特性により、RTLinuxアプリケーションからロボット、データ収集システム、製造プラント、その他の時間制約のある機器や機械を制御することが可能になります。名前は似ていますが、 Linux FoundationのReal-Time Linuxプロジェクトとは関係ありません。[ 1 ]
RTLinuxは、ニューメキシコ鉱業技術研究所のビクター・ヨダイケン、マイケル・バラバノフ、コート・ドーガンらが開発し、その後FSMLabsで商用製品として販売されました。 2007年2月、 Wind River SystemsがFSMLabsの組み込み技術を買収し、 Wind River Linux向けのWind River Real-Time Coreとして提供を開始しました。2011年8月現在、Wind RiverはWind River Real-Time Core製品ラインの販売を終了しており、事実上RTLinux製品の商用サポートも終了しています。
RTLinux の主要な設計目標[ 2 ]は、汎用オペレーティングシステムにハードリアルタイム機能を追加して、両方の機能を備えた複雑な制御プログラムの開発を容易にすることでした。[ 3 ] [ 4 ]例えば、汎用データベースを使用して Web オペレータ インターフェイスをエクスポートするリアルタイム モータ コントローラを開発したい場合があります。 リアルタイム機能と非リアルタイム機能の両方をサポートできる単一のオペレーティングシステムを構築しようとするのではなく、RTLinux は、(1) リアルタイム オペレーティングシステムが非リアルタイム オペレーティングシステムによって実行をブロックされることがないように、また (2) 2 つの異なる環境で実行されているコンポーネントがデータを簡単に共有できるように、リアルタイム オペレーティングシステムと非リアルタイム オペレーティングシステムの間でコンピューティング デバイスを共有するように設計されました。 名前が示すように、RTLinux は当初、非リアルタイム システムとして Linux を使用するように設計されました[ 5 ]が、最終的には、RTCore リアルタイム カーネルが Linux またはBerkeley Software Distribution (BSD) Unix のどちらでも実行できるように進化しました。
マルチ環境リアルタイム(MERT)は、Unixシステムと共存するリアルタイムオペレーティングシステムの最初の例でした。MERTは従来の仮想化技術に依存しており、リアルタイムカーネルがホストオペレーティングシステム(またはハイパーバイザ)であり、ベルシステムズUnixがゲストでした。RTLinuxは、MERTの概念をPC時代と汎用ハードウェアに合わせて更新しようとする試みでした。また、仮想化によって生じるオーバーヘッドなど、MERTのパフォーマンス上の限界を克服しようとする試みでもありました。
RTLinuxは、ゲストOSを仮想マシンにカプセル化する代わりに、ゲストの割り込み制御のみを仮想化しました。この方法により、リアルタイムカーネルはゲストオペレーティングシステムを完全にプリエンプティブなシステムに変換しつつ、例えばストレージデバイスを直接制御することができました。特に、ゲスト用の標準ドライバはソースコードを変更することなく動作しましたが、仮想化の「フック」を使用するために再コンパイルする必要がありました。準仮想化も参照してください。リアルタイムプログラムと非リアルタイムプログラムが通信できるようにUnixパイプが改良されましたが、共有メモリなどの他の方法も追加されました。
プログラマの視点から見ると、RTLinux は当初、リアルタイム タスク用の小さなスレッド環境と、それ以外のすべてに使用できる標準の Linux 環境のように見えました。リアルタイム オペレーティングシステムは、ロード可能なカーネル モジュールとして実装され、まずゲスト割り込み制御を仮想化し、次にリアルタイム スケジューラを起動しました。タスクには静的な優先度が割り当てられ、スケジューリングは当初は完全に優先度駆動型でした。ゲスト オペレーティングシステムは最も優先度の低いタスクとして組み込まれ、実質的にリアルタイム システムのアイドル タスクとして機能しました。リアルタイム タスクはカーネル モードで実行されました。RTLinux の後の開発では、 POSIXスレッドアプリケーション プログラミング インターフェイス ( API )が採用され、ゲスト プロセス内でリアルタイム スレッドを実行するユーザー モードでのスレッドの作成が可能になりました。マルチ プロセッサ環境では、スレッドはプロセッサ コアにロックされ、ゲスト スレッドが指定されたコアで実行されないようにすることが可能でした (事実上、コアをリアルタイム処理専用に予約)。
RTLinux は、標準 Linux と同じマシン上で特別なリアルタイム タスクと割り込みハンドラを実行する機能を提供します。これらのタスクとハンドラは、Linux が何をしているかに関係なく、実行する必要があるときに実行されます。プロセッサがハードウェア割り込みを検出してから割り込みハンドラが実行を開始するまでの最悪時間は、汎用x86 (2000 年頃) 上で動作する RTLinux では 15マイクロ秒未満です。RTLinux の定期タスクは、同じハードウェア上でスケジュールされた時刻から 35 マイクロ秒以内に実行されます。これらの時間はハードウェアによって制限されており、ハードウェアが改善するにつれて RTLinux も改善されます。標準 Linux は優れた平均パフォーマンスを持ち、 POSIX ソフトリアルタイム機能を使用するタスクに対してミリ秒レベルのスケジューリング精度を提供することさえ可能です。ただし、標準 Linux は、ミリ秒未満の精度と信頼性の高いタイミング保証を提供するようには設計されていません。RTLinux は軽量の仮想マシンに基づいており、Linux 「ゲスト」には仮想化された割り込みコントローラとタイマーが提供され、その他のすべてのハードウェア アクセスは直接行われます。リアルタイム「ホスト」の観点から見ると、Linux カーネルはスレッドです。決定論的処理に必要な割り込みはリアルタイムコアによって処理され、その他の割り込みはLinuxに転送されます。Linuxはリアルタイムスレッドよりも低い優先度で実行されます。ほぼすべてのI/OはLinuxドライバによって処理されます。オペレーティングシステムとRTLinux間でデータを共有するには、 FIFO(先入れ先出し)パイプまたは共有メモリを使用できます。
RTLinux の設計における重要な目標は、システムが透過的で、モジュール化され、拡張可能であることです。透過性とは、内部構造が不明瞭なブラックボックスが存在しないこと、およびあらゆる操作のコストが決定可能であることを意味します。モジュール化とは、必要のない機能とそのコストを省略できることを意味します。そして拡張性とは、プログラマがモジュールを追加し、システムを要件に合わせてカスタマイズできることを意味します。RTLinux の基本システムは高速割り込み処理のみをサポートしています。シンプルな優先度スケジューラを備えており、特定のアプリケーションのニーズにより適したスケジューラに簡単に置き換えることができます。RTLinux の開発にあたっては、Linux とその強力な機能を活用することで得られるメリットを最大限に引き出すように設計されました。
RTLinuxは、小さなコアコンポーネントとオプションコンポーネントのセットで構成されています。コアコンポーネントは、Linux自体によって遅延またはプリエンプトされない超低遅延の割り込みハンドラと、いくつかの低レベルの同期および割り込み制御ルーチンをインストールできます。このコアコンポーネントはSMPをサポートするように拡張され、同時にコア外部で提供できる一部の機能を削除することで簡素化されています。
RTLinuxの機能のほとんどは、オプションのサービスと抽象化レベルを提供するロード可能なカーネルモジュール群に含まれています。これらのモジュールには以下が含まれます。
RTLinuxのリアルタイムタスクは、Linuxがドライバやファイルシステムなどに使用するモジュールと同様のカーネルモジュールとして実装されます。リアルタイムタスクはハードウェアに直接アクセスし、仮想メモリは使用しません。初期化時に、リアルタイムタスク(モジュール)は、RTLinuxカーネルにデッドライン、期間、およびリリース時間の制約を通知します。
RT-Linuxは、スレッド操作のためのPOSIX APIを実装しています。スレッドは、pthread_create関数を呼び出すことで作成されます。の3番目のパラメータpthread_createは、スレッドによって実行されるコードを含む関数です。
RTLinuxではスレッドの優先順位を設定する必要があります。優先順位の高いスレッドは、優先順位の低いスレッドをプリエンプトできます。たとえば、ステッピングモーターを制御するスレッドがあるとします。モーターをスムーズに動かすには、このスレッドを厳密に一定の間隔で起動する必要があります。これは、このスレッドに高い優先順位を割り当てることで保証できます。サンプルファイルthreads2.cでは、さまざまなスレッドの優先順位を設定しています。スレッドの優先順位の設定は、以下のコードで行います。
int init_module ( void ) { pthread_attr_t attr ; struct sched_param param ; pthread_attr_init ( & attr ); param.sched_priority = 1 ; pthread_attr_setschedparam ( & attr , & param ) ; pthread_create ( & t1 , & attr , & thread_code , " this is thread 1" ); rtl_printf ( "Thread 1 started \n " ); /* ... */ }プログラムの出力は以下のとおりです。
スレッド1が開始されました スレッド2が開始されました スレッド3が開始されました メッセージ:これはスレッド1です メッセージ:これはスレッド2です メッセージ:これはスレッド2です メッセージ:これはスレッド2です メッセージ:これはスレッド1です メッセージ:これはスレッド1です メッセージ:これはスレッド3です メッセージ:これはスレッド3です メッセージ:これはスレッド3です
スレッド2は最も優先度が高く、スレッド3は最も優先度が低い。最初のメッセージは、スレッド2よりも少し前に開始された中程度の優先度のスレッド1によって出力される。