沼津高専 電子制御工学科
RT-Linux及びsoftware調査報告書
MIRS0202-TECH-0005
改訂記録
版数 作成日 作成者 承認 改訂内容
A01 2003.02.12 小野田 山田 初版


1.目的
       MIRSに搭載する、RT-Linux、RT-タスクモジュールについて特に詳しく調査する。


2.調査報告


    1.RT-Linuxについて

      1.1 RT-Linuxとは

            Real-Time Linux は、Linux と共存可能なリアルタイムOSだが、厳密な意味ではリアルタイムOSではなく、RT-Linux が提供するのはスケジューラとプロセス間通信のみである。RTLinuxは、仮想マシンをLinuxに提供し、Linuxを優先順位の低い1つのリアルタイムプロセスとして実行することで、リアルタイム処理と従来のLinuxの処理の共存を実現している。このリアルタイム処理というのは ある幅で処理開始タイミングと処理終了までの時間制限を保証した処理 のことである。RT-LinuxはリアルタイムOSであり、リアルタイムOSは、リアルタイム処理を行うマルチタスクOSである。

  MS-DOS上で割り込み処理プログラムを走らせたのと、どう違うのかというと、タイマーカウンタのハードウェアを用意してDOSの割り込みを使えば、DOSでもリアルタイム処理は可能であるのだが、MS-DOSはシングルタスクである上、開発環境が UNIXの資産を受け継いでいるLinux に比べると遥かに貧弱である。 RTLinuxならば、リアルタイム処理を実行しながら、複数のプログラムを 実行できる上、開発環境も整っているので開発も楽にできるという強みがある。また、タイマーカウンタ等のハードウェアを用意しなくても、 (CPUにそこまでの処理能力があるかどうかは別として) OS自体が 1ns 程度の時間制約まで守れる設計になっている。 MS-DOSやMS-Windowsといった OS の設計では 1ms 以下のサンプリングは 保証されない。したがって、安価で開発環境の整っているRTLinuxの方が、リアルタイム制御を行うのに(開発行程も含めて)向いているといえる。


      1.2 RT-Linuxの処理の流れ

struct
fig.1 RT-Linuxの処理の流れ


     
RT-FIFO: Linuxプロセスとリアルタイムタスク間を結ぶ情報交換機能を持つ。Linuxプロセスからは、標準的なデバイス"/dev/rtfx"(x=0,1,2…)として利用できる。


      1.3 RT-Linuxで提供されるAPI関数

POSIXスタイルインターフェース関数
API関数機能
Pthread_createスレッドの生成
Pthread_exitスレッドの終了
Pthread_killスレッドへのシグナル送信
Pthread_selfスレッドIDの取得
Pthread_attr_initスレッドアトリビュートオブジェクトの初期化
Pthread_attr_getstacksizeスタックサイズ属性の取得
Pthread_attr_setstacksizeスタックサイズ属性の設定
Pthread_yieldスレッドのCPU明け渡し指示
Pthread_setschedparamスケジューリング属性の変更
Pthread_attr_getschedparamスケジューリングプライオリティ性の取得
Pthread_getschedparamスケジューリング属性の取得
Pthread_attr_setschedparamスケジューリングプライオリティ属性の設定
Clock_gettimeタイマー値の取得
clock_settimeタイマー値の設定
clock_getresタイマー分解能の取得
sched_get_priority_maxスケジューリングポリシー毎のプライオリティの最大値の取得
sched_get_priority_minスケジューリングポリシー毎のプライオリティの最小値の取得
pthread_mutexattr_getpshared(3)Mutex属性オブジェクトのプロセス間共有設定の取得
pthread_mutexattr_setpshared(3)Mutex属性オブジェクトのプロセス間共有設定の設定
pthread_mutexattr_init(3)Mutex属性オブジェクトの生成、初期化
pthread_mutexattr_destroy(3)Mutex属性オブジェクトの破棄
pthread_mutexattr_settype(3)Mutexタイプ属性の設定
pthread_mutexattr_gettype(3)Mutexタイプ属性の取得
pthread_mutex_init(3)Mutexの初期化
pthread_mutex_destroy(3)Mutex破棄
pthread_mutex_lock(3)Mutexのロック
pthread_mutex_trylock(3)Mutexのロック
pthread_mutex_unlock(3)Mutexのアンロック
非POSIXスタイル関数
API関数機能
pthread_attr_setcpu_npCPU IDのスレッド属性オブジェクトの設定
pthread_attr_getcpu_npCPU IDのスレッド属性オブジェクトの取得
pthread_wait_npスレッドの周期実行の抑制(wait)
pthread_delete_npスレッドの削除
pthread_setfp_npスレッドの浮動小数・演算の使用許可
pthread_make_periodic_npスレッドのリアルタイム実行条件を指示
pthread_suspend_npスレッドをサスペンド
pthread_wakeup_npサスペンド中のスレッドを再開


    2.リアルタイムタスクのプログラミング

        RT-Linux のリアルタイムタスクにおける動作の基本は、IRQ0のタイマー割込を用いた周期的起動である。起動の開始時刻と周期は任意に指定できる。タスクからはシステムコールは使用できないが、I/Oポートへの入出力を行うことはできるので、一定時間ごとにI/Oをポーリングして必要な処理を行うと行ったタイプの処理が、最も基本的なものとなる。

  リアルタイムタスクは、Linuxプロセスとの間でFIFOを用いてデータをやりとりすることができる。FIFOはLinux側ではデバイスドライバとしてあらかじめ登録され、プロセス内ではファイルとしてopen/closeし、read/writeにより入出力を行う。またプロセスではselectにより状態遷移を待つことによりプロセスとの同期を取ることができる。FIFOにはリアルタイムカーネルで動作するハンドラーをアタッチすることもできる。ハンドラーはread/writeが完了した時点でコールされるので、これもプロセスとタスクの同期に使用することができる。プロセスからwriteされるFIFOにハンドラーをアタッチすることにより、プロセスからタスクに容易にコマンドを送って処理させることができる。

  リアルタイムタスクはモジュールとして実現され、insmodコマンドにより登録、rmmodコマンドにより削除される。登録後タスクにに割周期等を指定して実際に起動するためには、Linuxプロセスから指令を送らねばならない。このためには、上記のようにプロセスからFIFOにコマンドデータを出力し、それにアタッチされたハンドラーで起動処理を行えばよい。

  タイマー以外のハードウェア割込も利用できるが、リアルタイムカーネル内部では、システムコールが使えないので、既存のデバイスドライバは使えない。このためバスボードなどに関わる割込処理プログラムはリアルタイムカーネル専用として新たに作成しなければならない。

  コンソールやディスクの入出力などLinuxカーネルで使用する割込は、リアルタイムカーネルが要求する割込の処理が割込許可をした時点か処理が終了した時点で、Linuxカーネルに渡される。このため通常のように使用することができるが、いったんRT-Linux用に書き換えねばならないので、バイナリコードのみで供給されているデバイスドライバは使用できなくなる。


    3.モジュール作成上の注意点

      ・メモリに関して

  モジュールはカーネル空間で動作する。カーネル空間でもポインタを用いてvmallocやkmallocという関数により、 メモリを確保することが可能である。しかし、callocのように中身を初期化してくれるわけではないので、プログラマ自身の手で確実に初期化を行うこと。
  また、外部変数はstaticと宣言しておかないと、メモリを待避させたり戻したりしているうちに、 変数の中身が書き変わってしまう危険性がある。外部変数を使わないに越したことはないが、使う場合はstaticを使用すること。


・FIFOに関して

  FIFOは構造体を渡すことができるが、ポインタを渡すことができない。 したがって、配列は構造体のメンバになることができない。 配列は、原理的にはポインタと同じだからである。 こういうときは多少冗長でも、配列の数だけメンバ変数を用意することになる。
  また、送るデータが少ないときは、DATA_FIFOのバッファを少なくする必要がある。 バッファが大きくあいていると、 スレッドから送られてくるデータに一定の遅れが出てしまうからである。


・その他

  一般に、割り込み処理やカーネル空間では浮動小数点演算は使用しないことになっている。 これは浮動小数点演算コプロセッサ(FPU)のレジスタが明示的に指定してやらない限り待避されないからである。
  RT-moduleプログラムを書くときは、 関数pthread_setfp_npを用いて明示的に浮動小数点演算を使用すること宣言しなければならない。