プロが教えるわが家の防犯対策術!

μITRON4.0準拠のNORTi+ARMを使用し組み込み開発をしています。
質問は、スタックでオーバーフローの可能性があるため、スタックの見積もりを行いたいのですが、
(1)タスクのスタックの見積もり方法が、タスクごとにスタックを計算し足し算でよいのか(タスクごとにスタック容量を設定するので)、タスクの発生パターンを考えてそれの合計のスタックを見積もればよいのか分かりません。また計算してくれるコマンドやツールはあるのでしょうか?
(2)割り込みハンドラ等の非タスクコンテキストとタスクコンテキストのスタックの関係、両者を含めてオーバーフローを考えるべきなのでしょうか?
よろしくお願いいたします。

A 回答 (3件)

1.タスクスタックを個別にするには、cre_tskでのスタックアドレスを渡してあげること。


2.その他のスタック(カーネル、割り込みハンドラ)は、スタック用メモリ
  が使われ、そのサイズは、STKMSZ で定義したサイズが使われます。
3.タイムイベントハンドラは、スタックセクションから直接使われるようです。

使われるというのは、生成したときに固定サイズで割り当てされると考えたらよいと
思います。ですので、それぞれがオーバーしないサイズにしないといけません。

以下 蛇足かもしれませんが
1)スタック必要サイズを調べるのは設計上必要な作業
 オーバーしてから調べるのではなく、本来設計上いくら必要か算出しておく
 べき内容です。設計データとして算出し、ドキュメント化しておくことを
 お勧めします。 カーネルスタックはぜひ、ミスポさんに問い合わせください。
 もし、こんなことも回答できないようなら、有償OSとして選ぶ意味がないと私は思います。

2)稀に暴走する場合の対処
 いろんな原因があって、難しいケースもあります。設計に立ち返って
 たとえばスタックオーバーを仮定してそれを調査しなおすのもひとつかと思います。
 ICEが今使えないということですが、使えるようになったら、デバッガーのトレース
 機能で調べたらよいかと思います。(ARMのそれがトレースできないならできませんが)
    • good
    • 0
この回答へのお礼

ありがとうございました。
コメントにありますように
1)スタック必要サイズを調べるのは設計上必要な作業
大変身にしみるお言葉です。今回は他人が作成したプログラムの解析でしたがリアルタイムOSの組み込みの学習も兼ねてスタックについて勉強したいと思います。

お礼日時:2008/06/06 00:31

まずはどのタスクのスタックがオーバーフローしているかの解明が先決かと。



NORTiであれば、システム起動時に各タスクのスタック領域はタスクID番号で埋められています。

ICEで一通り実行した後にbreakして、スタック領域のメモリ内容を見渡すと各タスクのスタックがどれくらい使われているかが把握できます。

例えば、TASKAのIDが1なら、スタック領域は
01 01 01 01 01 01 01 01
     :
01 01 01 01 01 01 01 01
01 15 42 FF 38 25 8F A5
と言うように、01が並んだ後に実際に使われたスタックには値が入った領域が表われます。
01の個数が残りスタックサイズなので、タスクIDが無くなっている或いは、極端に少なくなっているタスクはスタックオーバーフローの可能性があります。

スタック領域は、CRE_XXX系のシステムコールでOSオブジェクトを生成する時のパラメータで、メモリ領域をNULLにしているのであれば、リンカで割り当てたデフォルトスタック領域が使われていますので、リンカの設定を見て下さい。

割り込みでオーバーフローしているのであれば、ISPというグローバル変数に割り込みハンドラのスタック領域末尾のアドレスが格納されていて、そのアドレスから上が0埋めされていますので、同様にオーバーフローしているか確認できます。

タイムイベントハンドラのスタック領域は、上記ISPの下なのですが、こちらは0クリアしてくれていないので、システム起動時にICE等で0埋めするなどの処置が必要になります。

いずれにしろNORTiでしたら、ソースがついていますので、一度sysini()関数とcre_tsk()関数の中身を解析することをお薦めします。
(一部アセンブラがありますが、それ程難しいことはしていないので)
システム起動時のスタック領域の割り付け方が分かりますので、上記に書かれていることが理解できるかと思います。

また、スタックオーバーフローは、経験上、不注意による巨大なローカル変数の宣言が原因となっていることが多々あります。

基本データ型であれば、大きな配列を取っていればすぐに気付くのですが、特に構造体の配列などは要注意です。
例えば、100バイトくらいある様な構造体の10個の配列を作っただけで1KB近くのスタックを消費してしまいます。
そう言った箇所がないか確認し、どうしてもローカル変数にするのでしたらstatic宣言して静的領域に追い出して下さい。
    • good
    • 0
この回答へのお礼

大変分かりやすい説明ありがとうございました。
sysini()関数とcre_tsk()関数を解析してみます。
オーバーフロー思われる現象が稀にしか発生しないということと、現状ICEでの解析ができないので、オーバーフローの可能性を調査しているところです。
これまではOSのない組み込みしかやったことがなかったので、タスクのスタックと割り込みのスタックの実際のメモリ配置がどうなっているのかもわかりませんでした。
ローカル変数で巨大なやつがいないか探してみます。

お礼日時:2008/06/04 02:44

NORTiのユーザーズマニュアルを見てみました。


スタックについてはちょっとわかりにくいという感じがします。
難しくしているのは、Nortiが、共有スタックというか、スタックエリアの
使いまわしができる仕様であるからです。

また、カーネルの使用スタックサイズも書いてないようです。
これについては、ミスポにキッチリ問い合わせることがよいかと思います。
「カーネルの使用スタックサイズの計算方法、サービスコール別にどんだけ
使うのか」
と聞いてみればいいと思います。


1)タスクの合計か、それとも発生パターンの合計
  後者の意味が少しわかりませんが、通常は前者で、全タスクの利用サイズを使用すると考えます。
  ただ、使いまわしができるので、たとえばタスク1とタスク2が同時に登録して
  いる状況がないなら、タスク1と2の大きいほうでその他のタスクのスタック
  サイズを足せばいいことになります。ところが、動的メモリ管理のためフラグメンテーション
  があるので、保証できないようです。ですので結局すべての合計になります。要するに前者です。
  ツール等は無いと思います。

2)非タスクコンテキストとコンテキストのスタックの関係
  関係といいますか別ものです。Nortiでは同じメモリ領域を使うことが可能になっているだけです。

  基本的には、タスク処理中(タスクコンテキスト)はタスクスタックが使われます。
  割り込みなど非コンテキスト時は、タスクスタックとは別のスタックに切り替えます。
  タスクスタックはタスク毎の最大サイズを、
  システムスタックはそれぞれの割り込み等の処理の最大サイズを割り当てる必要があります。
  カーネルそのもののスタックサイズは設定方法が記載されていないというか、システム全体を
  スタックセクションメモリを動的に利用し、タスクスタックなど割り当ての残ったものすべてを
  カーネルで利用するスタックとしているようです。そのための算出方法がでていないようです。

結局やることは
タスクすべての最大スタックサイズの合計(これはできてますね)
割り込みハンドラ用最大スタックサイズ(マニュアルに明記されています)
タイムイベント用最大スタックのサイズ(マニュアルに明記されています)
カーネルのスタックサイズ(これの説明がないようです)

を算出し、まとめてエリアをとるのか、個別にメモリに分けるかは、自由に設定できる
と思います。



参考にサービスコール毎のスタックサイズや
スタックサイズの算出方法の書かれたuITRONのマニュアルのURLを書いておきます。

参考URL:http://documentation.renesas.com/jpn/products/to …
    • good
    • 0
この回答へのお礼

ご回答ありがとうございました。
ユーザズマニュアルまで見ていただいて大変ありがとうございます。
CPUの暴走らしき現象は稀にしか発生しておらず、タスクのスタックサイズは大丈夫だと思っているのですが、最悪の割り込み発生とタイムイベントが重なったときににオーバーフローになっているかと推測していました。ですので、割り込みハンドラ+イベントでオーバーフローとなってもタスクのスタックがあまっているときは大丈夫なのか、そうではないかと判断したかったので質問させていただきました。
R32Cさんのご回答にあるように、まとめてエリアをとるのか、個別にメモリに分けるのかは設定があるとのことですので、そこを確認したいと思います。

お礼日時:2008/06/04 02:29

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!