複数周期を利用するために開発したものですが、もちろん単周期でも使用可能です。 そのときは、最低タイマ割り込み2周期分という制限がなくなって、1周期単位から設定できるようになり、起きるべき時間をカーネル内部でチェックしてくれるようになるので、制御処理に要する時間を測定する必要もなくなります。
制御などを実行すべき時刻が来たかどうかをプロセスに通知する機能として、
実際にこの方法をつかうにはモジュールをカーネルに登録し、アクセスのための特別ファイル(/dev/なんとか、の類い)をつくらなければなりません(詳細は後述)。
登録したら、実行するプログラムでは
デバイスにアクセスする場合には、メジャー番号・マイナー番号という数値が使用されます。
メジャー番号でドライバを識別し、マイナー番号で内部の機能を選択します。
アクセスする場合には直接この数値を指定するのではなく、予め、特殊なファイルをつくっておきます。
これが開かれたとき、デバイスへのアクセスを意図したものとLinuxが解釈し、適当に処理してくれます。
周期実行プログラムは、起動時に引数を10個まで指定できます。 それぞれを周期とした周期実行がなされます。周期の単位は「1タイマ割り込み周期」です(普通のLinuxは2で20ms, 1k-Linuxで20=20ms)。 このプログラムはエンターキーで停止します。 または、合計で10000周期しても止ります。 最後にデータファイルに実測した周期を出力します(cycle0.xy-cycle?.xy, 第1カラム:時刻, 第2カラム:周期)。
周期を20[ms]にしてしまうと、ほとんど直線しか見えませんので、ここでは2,4,6,8[ms]にした結果例を示します。
次に、
2つ目の形式でこのファイル記述子を使用した場合の周期を設定します。
時間単位はタイマ割り込み周期です。
3つ目の形式は周期をちらす役目を持ちます。上の実行例では、公約数2を持つ周期群を設定しましたが、周期の基準点がopenした時刻であるため、同時にopenすると各実行タイミングがそろいます(0,1,2,3が1行に表示)。
それぞれの周期に制御動作などを割り当てた場合、その処理順によって周期にばらつきが出かねません。
それに対して、同時に複数の周期のタイミングが揃わないようにすれば、それぞれの処理をタイマ割り込みの直後に実行できるはずです(2,4,6,8だと(理論的に)むりですが、3,6,9では可能)。
この場合に、3つ目の形式を実行すると、適当にちらしてくれます(ちゃんとずれるように探すので乱数よりまともです:-)。が、均等にはなりません)。
なお、これは単一プロセスではなく複数プロセスからそれぞれ周期を設定した場合にも効果があります。
それ以前に、各周期設定は完全に独立なので、同じプロセスでも、異なるプロセスでも動作はかわりません。
設定したら、周期実行のループをつくります。基本的に、whileループなどの中で、
ここまで準備した上で
返り値が負の場合、普通はエラーですが、シグナルのこともあります。
返り値が0の場合はタイムアウトしています。返り値が正の場合は渡したファイル記述子のいずれかの準備が完了しています。
どの記述子の準備が出来たかを知るには、
コンパイル時のオプションに -DUSE_RDTSC があります。
これをつけない場合、ドライバもプロセス側も時刻情報の取得には
(生データファイル:
cycle0.xy,
cycle1.xy,
cycle2.xy,
cycle3.xy
)
1つの時の例同様、ほぼ一定の周期が保たれつつ、ときどき大きく周期がはずれます。
これまでの例と異なるのは、遅れた分は次回に早くなることです。
これは、ドライバ内部での処理の実装によっています。
前者は実時間の数値がそのまま得られ、汎用性に優れるのですが、プロセス側からはシステムコールを呼ばなければならず、時間が必要です(わずかですが)。
それに対して、後者は1クロックの命令一つで済むので非常に高速ですが、変換係数を設定しなければならず、汎用性が低下します。
固定のシステムでは後者をつかうといいとはおもいます。
いずれにせよ、今回のように複数の部分で時刻情報を使いたい場合は統一しなければならないでしょう。