第 3 章 初歩の RTLinux プログラミング 27
3.7 LinuxプロセスからRTLinuxモジュールを制御するプログラム
3.7.3 RTLinuxモジュールの動き
ここでは、RTLinuxモジュール(module3.o)の動きに注目して見てみます。
まず、RTLinuxモジュール内の各リソースとRTLinuxスレッド,ハンドラの生成関係を下図に示しま
す。
RT-FIFO
スレッド&ハンドラのコード init_module
ハンドラ(my_handler)
RTLinuxスレッド(my_task) FIFO1(GET_HANDLER_FIFO)
FIFO2(GET_TASK_FIFO)
FIFO3(SET_TASK_FIFO)
cleanup_module
生成 破棄
Linuxプロセスからの指令を受け取るハンドラ(my_handler)と、RTLinuxスレッド(my_task)が生成/
破棄されています。
次に、RTLinuxモジュール内での相互関係を示します。
ハンドラ(my_handler)
RTLinuxスレッド(my_task) Linuxプロセス
周期実行 ID_START ID_STOP
開始 停止
counter変数 ←インクリメント
FIFO1(GET_HANDLER_FIFO)
FIFO3(SET_TASK_FIFO)
FIFO2(GET_TASK_FIFO)
RTLinuxモジュール内で中心となるのは、周期実行を行うRTLinuxスレッド(my_task)です。この RTLinuxスレッドは、Linuxプロセスからの指令により、周期実行のスタート(ID_START),ストッ プ(ID_STOP)を行います。スタート後の周期実行中、RTLinuxスレッドは内部のcounter変数を周期 ごとにインクリメントします。(将来、カスタマイズするならば、例えば、ここにDIOやAD/DA等 の周期的な制御を入れると良いでしょう)
LinuxプロセスからRTLinuxスレッドへの指示は、ハンドラ(my_handler)を経由して行われます。こ のハンドラは、Linuxプロセスからの指示を、RTLinuxスレッドに、そのまま送っています。(将来、
RTLinuxスレッドを2つ以上に増やした時、このハンドラで、操作するスレッドを集中的に管理す ると良いでしょう)
ハンドラとRTLinuxスレッドは、RT-FIFOによって、情報の交換を行います。
RT-FIFOの生成と削除は、init_module関数とcleanup_module関数で行っています。
以降では、処理順にこれらの処理を解説します。
(89〜99行目:rtf_destroy、rtf_create関数)
RT-FIFOを生成するのは、rtf_create関数です。破棄はrtf_destroy関数です。
コードでは、rtf_destroy関数を呼び出した後、rtf_create関数を呼び出しています。
通常であれば、init_module関数を実行する時、RT-FIFOは生成済みということは考えにくいのです が、ここでは保険として、rtf_destroy関数で明示的に削除を行っています。
RT-FIFOのサイズは、各RT-FIFOごとに変えています。
特にRTLinuxスレッドからLinuxプロセスへ結果を返却するRT-FIFO(99行目の、SET_TASK_FIFO)
では、”sizeof(long:4バイト) * BUFF_SIZE(100個) = 400バイト”のバッファサイズを確保しています。
これは、RTLinuxスレッドに格納した情報を、即座にLinuxプロセス側で取り出せることは考えに くいため、ある程度RT-FIFOに情報が溜まっても、処理が続けられるよう(バッファをオーバーフ ローしないよう)に、大きめのバッファを確保しています。
実際のリアルタイムプログラミングでも、2つのプロセス間が非同期に動作する場合、バッファサ イズに、余裕を持たせることは重要です。
(91行目:rtf_create_handler関数)
rtf_create_handler関数は、ハンドラ(my_handler)を生成する関数です。
このハンドラでは、指定されたRT-FIFOにメッセージが溜まると呼び出される、明示的なイベン
(69〜73行目:my_handler関数のwhileループ)
ハンドラ(my_handler)関数では、このwhileループがメインとなります。
ここでは、Linuxプロセスと繋がるRT-FIFOから送られるデータを受け取るために、rtf_get関数で 待機します。
受け取ったデータは、ここでは、rtf_put関数にて、そのままRTLinuxスレッド(my_task)と繋がる RT-FIFOに送っています。
簡単なイメージを、下図に示します。
RT-FIFO RT-FIFO
my_handler
ハンドラ
rtf_get rtf_put
Linuxプロセス側 RTLinuxスレッド側
将来、RTLinuxスレッドを2つ3つと増やした場合、ここをLinuxプロセスから各RTLinuxスレッド へメッセージを分配するための、集配所として追加すれば良いでしょう。
RT-FIFO RT-FIFO
my_handler
ハンドラ
rtf_get rtf_put
Linuxプロセス側 RTLinuxスレッド側
RT-FIFO
RT-FIFO
(24〜56行目:my_task関数のwhileループ)
RTLinuxスレッド(my_task)では、このwhileループがメインとなります。
ここでは、ハンドラと繋がるRT-FIFOから送られるデータをrtf_get関数で受け取り、その指示に従 い、周期実行のスタートおよびストップを行います。
周期実行を動作させている時、内部のcounter変数がインクリメントされていきます。
このインクリメントされた値は、rtf_put関数を用いて、Linuxプロセスに繋がるRT-FIFOに送られ ます。
29行目のrtf_get関数は、周期実行が行われている/行われていないに関わらず、ここでRT-FIFOか らのデータ待ちになってしまうと思われるかも知れません。
しかし、実際には、rtf_get関数の呼び出しは、RT-FIFOからのデータがあれば、29〜47行の処理を 行い、無ければ50行以降の処理を続けます。
33〜46行のswitch文では、Linuxプロセスから送られてきた指示に対する処理が記述されています。
動きを以下に示します。
ID_START value変数の値をms単位の実行周期として、pthread_make_periodic_np関数を呼び出し、
自身の実行周期の間隔を指定する。
ID_STOP pthread_suspend_np関数を呼び出し、自スレッドをスリープ状態にする。
50〜55行の処理は、周期実行している時の、処理コードです。
内容は、内部counter変数をインクリメントし、counter変数の値を、rtf_put関数を使って、RT-FIFO に書き込み続けています。
ここでやっているのは、非常に単純な処理ですが、この処理をDIOやAD/DA等に置き換えて見る と、様々なやり方が想定できることでしょう。
例えば、周期実行の部分に、1件のAD入力関数を配置するだけで、サンプリング間隔を簡単に可 変することが実現できます。
■関数解説
★rtf_create
RT-FIFOを生成します。
第1引数でRT-FIFOのID値を、第2引数でサイズを指定します。
生成したRT-FIFOを破棄するには、rtf_destroy関数を用います。
★rtf_create_handler
この関数は、ユーザ空間からRT-FIFOにデータが書き込まれた際に、呼び出される関数を登録します。
第1引数には、RT-FIFO作成時に指定したID値を指定します。
第2引数には、RT-FIFOにデータが書き込まれた際に、呼び出される関数を指定します。
この関数は、ユーザ空間からRT-FIFOにデータが書き込まれた際に呼ばれる関数を登録しますが、カー ネル空間からアクセスされた(rtf_put、rtf_get関数を使用した)場合に呼ばれる関数を登録するには、
rtf_create_rt_handler関数を使用します。
★pthread_wakeup_np
この関数を呼ぶことで、指定したRTLinuxスレッドの実行を再開することができます。
★pthread_suspend_np
引数により指定したRTLinuxスレッドをpthread_wakeup_npが呼び出されるまで中断します。