Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

【学習メモ#11th】12ステップで作る組込みOS自作入門

1,507 views

Published on

12ステップで作る組込みOS自作入門
http://www.amazon.co.jp/dp/4877832394/
坂井 弘亮(著)
カットシステム

Published in: Technology
  • Be the first to comment

【学習メモ#11th】12ステップで作る組込みOS自作入門

  1. 1. 12ステップで作る組込みOS自作入門 11thステップ @sandai
  2. 2. 【参考書籍】12ステップで作る組込みOS自作入門【内容】1ステップずつ、実際に動かしながらプログラムを発展させていく方式で無理なく学べる。OSやハードウェアに詳しくない方にも理解できるように十分な説明を提供坂井 弘亮(著)カットシステム(2010/5)【税込価格】4,410円【サポートページ】http://kozos.jp/books/makeos/
  3. 3. もくじ1.タスク間通信2.関数の再入と排他3.KOZOSでのタスク間通信4.メッセージ通信の実装5.プログラムの実行6.まとめ
  4. 4. 1.タスク間通信
  5. 5. タスク間通信● 組込みOSのカーネルはできるだけコンパクトに しておきたい – 高機能やリアルタイム性を求められるため● だから、デバイス・ドライバや、ファイル・シ ステムなどといったリアルタイム性を保証でき ないサービスは、カーネルの外でスレッドとし て実装する● とはいえ、そういったアプリは一般に単体で動 作できるものは少ない – 機能別にスレッドに分けることが多い – そこでスレッド同士でデータのやり取りができるタ スク間通信をできるようにする
  6. 6. システム・タスク● 基本サービスを行うスレッドのことを一般にシ ステム・タスクと呼ぶ – 任意サイズのメモリ管理を実装するとして、OSの機 能として実装すると空きメモリの検索時間が保証で きない – そこでメモリ管理を行うようなスレッドを作成し、 任意サイズ必要な場合はそのスレッドにタスク間通 信で依頼して領域を割り当ててもらう、などといっ た実装ができる● こういったOSのカーネルとセットで利用するス レッドがシステム・タスク
  7. 7. ユーザ・タスク● OSのユーザ側で作成するアプリケーション・プ ログラムは、ユーザ・タスクと呼ぶ – ユーザが使う目的のスレッドと考えれば良いかな● OSからみればシステム・タスクもユーザ・タス クもOSで動作しているスレッドにすぎない – 両者の違いは使われ方の違いなだけ
  8. 8. 2.関数の再入と排他
  9. 9. 関数の再入● タスク間通信が必要な理由はもうひとつ関数の 再入を避けるというものがある● 関数の再入とは、あるスレッドが特定の関数を 実行している最中に割込みによって別スレッド が動作し、その別スレッドがその関数を実行し てしまうこと – 別々のスレッドで同じタイミングで同じ関数を実行 してしまうようなことかな● 関数内でstaticなデータをやり取りしている場 合、内容を上書きし合うといった問題が起きる
  10. 10. 再入問題の回避● 回避する手段はいくつかの方法がある – 仮想メモリを実装し、タスクをスレッドでなくプロ セス化する – サービスをOS内部に実装し、システム・コールを利 用して呼び出すようにする – 関数をリエントラントな構造にする – 関数内の排他が必要な部分に履いた処理を入れる (割込み禁止など) – 再入が発生しない設計にする – サービスをスレッド化する
  11. 11. 仮想メモリを実装● 関数の再入はメモリを共通資源として複数のス レッドが扱っていることに問題がある● そこでタスクごとに独立した仮想的なメモリ空 間を割り当てれば良い● この仮想的なメモリを仮想メモリ、そのメモリ のアドレスを仮想メモリと呼ぶ● 仮想メモリにより動作するアドレス空間が独立 しているタスクをプロセスと呼ぶ – スレッドはアドレス空間は共通なので、他のスレッ ドの変数などにアクセスできるが、プロセスではそ ういったことはできない● スレッド・モデル、プロセス・モデルなどとし て区別される
  12. 12. MMU● 仮想メモリではMMUと呼ばれる専用ハードウェ アが仮想アドレスから実際のメモリアドレスに アドレス変換をした上で行われる – 実際のメモリを物理アドレスと呼ぶ● タスクごとにメモリ空間は独立するので、結果 的にメモリ保護を行うこともできる● メリットはいろいろあるが組込みOSには向かな い – H8にはMMUが無い – リアルタイム性や高速性に向いていない – そもそも組込みOSではメモリ保護は必要ない
  13. 13. サービスをOS内部に実装● OSの機能としてカーネル内部に実装する方法が ある● システム・コールによってOSに依頼する形● とはいえ、OSの肥大化に繋がるし、再入を防止 したいサービスを全てカーネルに含ませるとい うポリシーの無い設計になってしまうので、あ まり良い手段とはいえない
  14. 14. 関数をリエントラントな構造にする● 関数が再入されても問題が発生しない構造に なっていることをリエントラント(再入可能)と 言う – リエントラントにするには、たとえば静的変数では なく自動変数を利用するなどするといった手段があ る● ただし、関数内部でさらに別の関数を呼び出し ている場合は、その関数もリエントラントにし なきゃいけない● つまりライブラリ関数全体をリエントラントに する必要がある
  15. 15. 排他処理を入れる● 静的変数を操作している部分で割込み禁止にす ることで、スレッドのディスパッチを防止する ことで再入されなくしてしまう方法もある – INTR_DISABLEやINTR_ENABLEとか使うvoid log_output(char *message){ static char buf[256]; time_t t; time(&t) INTR_DISABLE; strcpy(buf, ctime(&t)); strcpy(buf + strlen(buf), message); puts(buf); INTR_ENABLE;}
  16. 16. 排他● ある資源にアクセスしている最中に他の処理が その資源にアクセスしないようほ保証すること を排他と言う● 排他には割込み禁止/許可の他に、ロック、セ マフォ、ミューテックスと呼ばれる機能を利用 する方法がある● ロックをアプリケーション・レベルで実現しよ うとすると様々な問題があるので、一般にセマ フォという排他の仕組みをOS側で提供する
  17. 17. セマフォ● セマフォとはロックをOS側で行うような仕組み 獲得・解放をカウンタで管理することで、複数 のスレッドが再入する場合のスレッド数の上限 を管理することができる● 上限が1のセマフォはバイナリ・セマフォと呼 ばれ、常にひとつのスレッドしか実行できない● ミューテックスはバイナリ・セマフォに近いvoid log_output(char *message){ . . kz_getsem(ID); ←セマフォ獲得 strcpy(buf, ctime(&t)); strcpy(buf + strlen(buf), message); puts(buf); kz_relsem(ID); ←セマフォ解放}
  18. 18. 割込み禁止でする排他の話● 割込み禁止から有効に戻すまでの間を割り込み 禁止区画と呼ぶ – INTR_DISABLEからINTR_ENABLEの間● この方法での排他は割込みの遅延(遅延割込み) が発生する問題がある – 割込み禁止中に割込みが発生した場合、現在行なっ ている割込み処理を終えてから発生するので、割込 みが遅延する形になる – 割込み禁止区画が長いとキーボードを叩いても反応 が鈍いとか、マウスの動きが鈍くなったりする● 一般に「割込み処理は短く」「割込み禁止は最 小に」が鉄則
  19. 19. 再入が発生しない設計にする● スレッドの優先度を工夫して優先度の大小の関 係で動作が奪われないようにしたりできるが● 優先度が動作に依存するため慎重に設計する必 要がある● 現実的には割込み禁止にするなど確実で小回り の効く対策が人気● 排他が不要な構成にするというのは理想だけ ど、難しいな
  20. 20. サービスをスレッド化する● 再入の根本的な原因はひとつの資源を複数のス レッドから操作してしまっていること● 簡単な解決策は資源を管理するスレッドを実装 して、このスレッドを通して資源を操作する● これができるようにするには、スレッド同士の 通信ができるようにならなきゃいけない – つまりタスク間通信が必要● 組込みOSはカーネルをコンパクトにしたいので 基本的にサービスはスレッドとして実装する – サービスを利用する場合はタスク通信でスレッドに 依頼する
  21. 21. 3.KOZOSでのタスク間通信
  22. 22. メッセージ● KOZOSのタスク間通信はOS内部からシステム・ コールを発行することで、送信と受信の間に構 造体をかませてやりとりするになっている – この構造体をメッセージ・ボックスと本書では呼ん でいる – また、KOZOSのタスク間通信をメッセージと呼ぶ
  23. 23. メッセージの仕組み● メッセージのやり取りは送信用のシステム・ コールを呼び出して、受信側でメッセージ受信 用のシステム・コールを呼び出して受け取る● 受信用のシステム・コールを呼び出してもメッ セージが送信側で送信されていない場合は、ス リープして待ち合わせる – 待ち合わせによりスリープすることを一般に ブロックと言う● 受信用のシステム・コールを読んでいないのに 送信側が複数送信を行ったときは、メッセージ はキューに蓄えられる
  24. 24. メッセージのシステム・コール● kz_send()とkz_recv() – どちらも第1引数にメッセージID、第2と第3 で整数値とchar型のポインタを持つ● 第2と第3でint型のデータ(2バイト)とchar型の ポインタ(4バイト)を渡せるようにしている – バッファのサイズとアドレスを渡すと か、argc、argv[]形式で任意のデータを渡 す、といった融通が効くから
  25. 25. メッセージで同期的処理もできる● スレッド同士で情報のやりとりだけではなく、 動作タイミングを取り合うこともできる – あるスレッドの処理が完了してからもう一方 のスレッドで処理を開始するといったことが 可能● スレッドの動作状態と関係無く別の動作が行わ れることを非同期処理と言う
  26. 26. 4.メッセージ通信の実装
  27. 27. プログラムの修正と追加● 修正ファイル – defines.h...メッセージIDの定義 – syscall.h,syscall.c...システム・コール追加 – kozos.h,kozos.c...システム・コール追加 – main.c...起動するスレッドの修正 – Makefile● 追加ファイル● test11_1.c,test11_2.c
  28. 28. メッセージ送受信● メッセージのやり取りはシステム・コールに よって行い、メッセージボックスの構造体を間 に挟んで行う● 特に難しい処理はないが、メッセージボックス はキューになっている – リンクリスト構造で、headとtailのポインタを持つ – tailポインタを持つのはリンクリストの最後尾を毎 回検索するのが無駄であるため
  29. 29. メッセージ送受信の流れ● 送信側は基本的にメッセージボックスにメッ セージ(構造体)を保存するだけのことをする – 受信待ちスレッドがある場合は受信処理を行い、カ レントスレッドをレディ・キューに繋ぎ直す● 受信側は受信するメッセージがない場合はス リープ状態に入る – スリープ状態で送信処理が行われたときに、そちら で受信処理が行われるわけ● スリープする必要がなければメッセージを取得 する – メッセージボックスは複数のメッセージを持つ場合 にキューとなり、メッセージ取得は順番に取得が為 される
  30. 30. 5.プログラムの実行
  31. 31. プログラムの実行/Users/sandai/12step/src/11/os% sudo cu -l /dev/tty.usbserial-FTG6PQ4H..kzload> runstarting from entry point: ffc020kozos boot succeed!test11_1 started.test11_1 recv in.test11_2 started.test11_2 send in.test11_1 recv out.static memory...test11_2 recv out.allocated memorytest11_2 exit.test11_2 EXIT.
  32. 32. 6.まとめ
  33. 33. まとめ● タスク間通信を実装したことでOSの重い処理を システム・タスクとしてスレッド化できるよう になった● OSの機能をコンパクトにする設計をマイクロ・ カーネル、様々な機能を全て詰め込んだものを モノリシック・カーネルと呼ぶ

×