理想のRTOSを自作する (2)

【タイマー管理】

タイマー粒度問題を解決するために待ち時間をマイクロ秒で指定する方法を考えてみた。

問題は複数の待ち時間をどう管理するかだ。それと使うタイマーは1個で済ませたい。となると方法は一つしかない。タイマーにはカウント値と比較し割り込みを発生させる比較割り込みがある。それを利用すれば実現可能だ。

要求された複数の待ち時間は通常同じはならない(同じであってもかまわない)ので待ち時間の長さで要求を並び替えることは可能である。と考えると複数の要求があったとしてもタイマーは最短の待ち時間にのみ専念するだけで良いことになる。最初の要求を処理したら次の要求のためにタイマーを再セットアップする。それを要求が無くなるまで繰り返すだけだ。

但し、待ち時間で管理すると割り込みの遅延やオーバーヘッドにより誤差が拡大しつづけるので注意してほしい。誤差が拡大しないようにするには待ち時間を時刻※に変換し管理する必要がある。時刻※はいつかオーバーフローしてしまい過去なのか未来なのかわからなくなってしまうときがくるが現在時刻※を起点(ゼロ)とするだけで解決できる。要求時刻※から現在時刻※を減算した結果を符号付きと見なし、マイナスなら過去、プラスなら未来と判断する。この方法による制約は待ち時間が時刻※の最大値の半分に制限されるということだけだ。
※時刻は32ビットのマイクロ秒値を想定。

実装上の問題としては割り込み処理のオーバーヘッド等によりタイマーセットアップ中に要求時刻を過ぎてしまう場合があることだ。過ぎ去ったものは仕方ない。後ろを振り返えらず前に進もう。ということでそういう場合は最短のタイミングで次の割り込みが発生するようほんの少し未来のカウンター値(カウンター値+2※)を比較値として設定すれば良いだろう。
※タイマーはいつカウントアップするかわからないため+1では失敗する可能性がある。

一番の問題だと言っていたタイマーだけでもうちょっと書けるかなと思っていたが、なんか無理っぽいので、違う話題に...

【汎用リスト管理】

RTOSの自作ではタスク管理のためのリスト構造があちこちで必要になる。都度コーディングするのもいいが面倒なので汎用的に使えるライブラリを作成してみた。stdテンプレート・ライブラリにリスト管理のためのクラスはあるがデータ構造自体を内部割り当てしてしまうため多重リンクには適さない。でも、複数のリンク・ポインターをどう管理するのか?という素朴な問題があったので暫し悩んでみて解決策をひらめいた。offsetof()を使う方法だ。リンク・ポインターの位置さえ分かればあとはキャストでどうにでもなる。試してみたところ構造体メンバは問題なかったがクラス・フィールドを指定すると警告が出るので構造体に限定すべき?なのだろう。

ライブラリは、headポインターのみの”single ended queue”と、head及びtailポインターを持つ”double ended queue”の2種類のテンプレート・クラス。最後に追加する頻度が高いのであれば”double ended queue”、そうでなければ”single ended queue”と目的に合わせて使い分けすれば良い。また、同一仕様なので同じ使い方ができる。

多重リンクに対応するために構造体名とそのリンク・ポインターとなるメンバー名を指定する仕様となっている。定義されたマクロを使うと少しだけシンプルに短く書ける。なお、リンクする構造体自体の領域は利用者側で割り当てすること。

【サンプル・コード】

【リスト管理ライブラリの概要】

リストを初期化する。

先頭ノードを取得する。リストが空の場合は、nullptrが返される。

最終ノードを取得する。リストが空の場合は、nullptrが返される。

リストが空ならtrueを返す。

リストの登録ノード数を返す。

リストの最後にノードを追加する。

リストの先頭ノードを削除し返す。リストが空の場合はnullptrを返す。

指定ノードを削除する。先頭ノードが削除されるとQUEUE_STATUS_FIRST、それ以降はQUEUE_STATUS_SECOND、削除されなかった場合はQUEUE_STATUS_NONEを返す。

指定されたmatch関数がtrueを返したノードだけを削除する。リストが空になるとtrueを返す。

指定されたmatch関数がtrueを返している間ノードを削除し続ける。リストが空になるとtrueを返す。

指定されたmatch関数がtrueを返したノードの直前に指定されたノードを挿入する。match関数がtrueを返さなかった場合は、最後に追加される。先頭に挿入されるとQUEUE_STATUS_FIRST、それ以降はQUEUE_STATUS_SECONDを返す。

指定されたmatch関数がtrueを返したノードを返す。

【リスト管理ライブラリ】

次回は、GPIO管理にしようかな。

【関連する投稿】
理想のRTOSを自作する (1)
理想のRTOSを自作する (2)
理想のRTOSを自作する (3)
理想のRTOSを自作する (4)
理想のRTOSを自作する (5)
理想のRTOSを自作する (6)
理想のRTOSを自作する (7)
理想のRTOSを自作する (8)
理想のRTOSを自作する (9)
理想のRTOSを自作する (10)
理想のRTOSを自作する (11)

カテゴリーrtos

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください