狠狠撸

狠狠撸Share a Scribd company logo
12ステップで作る组込み翱厂自作入门
      9thステップ




                @sandai
【参考書籍】
12ステップで作る组込み翱厂自作入门
【内容】
1ステップずつ、実際に動かしながらプログラムを発展さ
せていく方式で無理なく学べる。OSやハードウェアに詳
しくない方にも理解できるよう
に十分な説明を提供

坂井 弘亮(著)
カットシステム(2010/5)

【税込価格】
4,410円

【サポートページ】
http://kozos.jp/books/makeos/
もくじ
1.优先度ベースのスケジューリング
2.优先度の実装
3.プログラムの実行
4.まとめ
1.优先度ベースのスケジューリング
優先度
●   組込みのOSでは一般的に優先度をベースにスケ
    ジューリングが行われている
●   優先度の高いスレッドが常に動作する
スレッドの状態
●   ここまでのプログラムのスレッドは常に「動作
    可能」の状態。常に動いているってこと
●   これだと複数スレッド間で同期的な動作をさせ
    られない
    –   あるスレッドが特定の処理を行うまで別スレッドが
        待ち合わせする、といったことができない
●   そこでスレッドに「待ち」という状態を追加す
    る
    –   スレッドを待ちにするシステム?コールを作る
●   待ち状態にするにはレディー?キューからス
    レッドを抜けばいい
スレッドにおける状態の呼び名
●   スレッドが「待ち」状態に入ることをスリープ
    やウェイティングと呼ぶ
●   スレッドがキューに繋がって動作可能の状態を
    レディーと呼ぶ
●   スリープ状態のスレッドをレディー状態に戻す
    ことをウェイクアップと呼ぶ
●   動作中のスレッドはアクティブやランニングな
    どと呼ぶ
●   このように、スレッドにはレディーとスリープ
    の2つの状態が存在する
優先度とプリエンプション
●   ここまでのプログラムだと、実行可能なスレッ
    ドが複数ある場合はシステム?コールによって
    順番に実行するようになっている
●   しかし、組込みシステムではあるスレッドがレ
    ディー状態になったとき、別のスレッドをさし
    おいてでも動作させたい場合がある
    –   たとえば車のエアバック制御は、衝突を検知したら
        一番に処理したい部分
●   ある割込みが発生した場合に、必ず一定時間内
    で処理を開始するという時間保証が行えるかど
    うかを、OSのリアルタイム性と言う
リアルタイムOS
●   リアルタイム性を提供するOSをリアルタイムOS
    と呼ぶ
●   ハードウェア制御だと、ある割込み発生から特
    定の処理を一定時間内に必ず行う必要があるな
    どの時間制約がある場合がある。こういったと
    きにOSのリアルタイム性は重要
●   複数のスレッドがレディー状態のとき、どれを
    動作するのか選択する必要があり、それに優先
    度が利用される
プリエンプション
●   スレッドの動作が別のスレッドに強制的に切り
    替わる動作を一般的にプリエンプションと呼ぶ
    –   優先度を持ったスレッドなら、優先度の低いスレッ
        ドの実行が中断され、優先度の高いスレッドが実行
        されることでこのように動作する
●   プリエンプションが可能であることをプリエン
    プティブと言い(先取り可能とも言う)、スレッ
    ドが突然中断するようなことが無いのであれば
    ノンプリエンプティブと呼ぶ
●   KOZOSはプリエンプティブなOSとして開発して
    いく
アイドル?スレッド
●   スレッドに優先度がつくと、やることがないと
    きにCPUを省電力モードにするアイドル?ス
    レッドが簡単に実装できる
●   今のプログラムだとレディー?キューが空にな
    るとシステムダウンしてしまうため、空になら
    ないよう一番低い優先度で「ムダななんらかの
    処理」をするスレッドを常に動かしておく必要
    がある
while(1) {
    // なにもしない状態
}
省電力モード
●   一般的なCPUには省電力モードという状態があ
    る
    –   x86でいうところのHLT命令かな
●   CPUを省電力モードにすると命令の実行を停止
    し、割込みが入るまで待つ状態になる
    –   クロックが止まるので省電になるようだ
●   他に動作する処理がないなら、アイドル?ス
    レッドを実行して待機状態にすれば良い
while(1) {
    // ビジーループよりこうした命令を使うべきだね
    (CPUを省電力モードに遷移する命令);
}
2.优先度の実装
プログラムの修正と追加
●   追加ファイル
    –   test09_1.c,test09_2,test09_3...スレッドとなる
        サンプルプログラム
●   修正ファイル
    –   kozos.h,kozos.c...優先度を実装
    –   syscall.h,syscall.c...スレッド制御のシステム
        コール追加
    –   main.c...アイドル?スレッド追加
    –   Makefile
プログラムの修正内容
●   スレッドの状態を制御するシステム?コールの
    追加
    –   kz_wait(),kz_sleep(),kz_wakeup(),kz_getid(),kz
        _chpri()
●   優先度の追加
    –   構造体に値を持たせて
●   readayqueを配列化
    –   優先度のスレッド別にまとめる形
    –   ここのらへんのスケジューリングのアルゴリズムが
        少し複雑かなってぐらいで、あとは8thステップの
        延長
3.プログラムの実行
ビルドの失敗(kozos.c)
●   パディングのサイズを変更
typedef struct _kz_thread {
    .
    .
    kz_context context;
    char dummy[8]; ←dummy[16]からdummy[8]にした
} kz_thread;
プログラムの実行
/Users/sandai/12step/src/09/os% sudo cu -l /dev/tty.usbserial-FTG6PQ4H
kzload> run
.
.
test09_3 started.
test09_3 wakeup in (test09_1).
test09_1 sleep out.
test09_1 chpri in.
test09_3 wakeup out.
test09_3 wakeup in (test09_2).
test09_2 sleep out.
test09_2 chpri in.
test09_1 chpri out.
test09_1 wait in.
test09_3 wakeup out.
test09_3 wait in.
test09_2 chpri out.
test09_2 wait in.
test09_1 wait out.
test09_1 trap in.
test09_1 DOWN.
test09_1 EXIT.
test09_3 wait out.
test09_3 exit in.
test09_3 EXIT.
test09_2 wait out.
test09_2 exit.
test09_2 EXIT.
4.まとめ
まとめ1
●   8thステップを理解していないと9thステップは
    何をやっているのかわからないはず
●   プログラムの修正部分に難しいコードはない
●   システム?コールとスケジューリング部分のア
    ルゴリズムの処理の流れが難しいので、そこを
    まとめておこう
まとめ2
●   下記のkz_run()のうち、test09_1_id = ...の
    処理の流れを記述しておく
●   kz_start()でstart_threads()が起動した後の
    ことなので注意
static int start_threads(int argc, char *argv[])
{
    test09_1_id = kz_run(test09_1_main, "test09_1", 1, 0x100, 0,
    .
    .
まとめ3
●   kz_run()
    –   kz_syscall()に渡すデータを構造体に保存
    –   kz_syscall()呼び出し
●   kz_syscall()
    –   current->syscall.xxxにシステムコールのタイプと
        kz_run()で受け取った構造体を設定
    –   asm volatile(“trapa #0”)で割込みが発生して
        thread_intr()呼び出し
まとめ4
●   thread_intr()
    –   handlers[type]()によりsyscall_intr()呼び出し
         ● 最終的にthread_run()が呼び出されてp-

           >un.run.ret = にcurrentが代入される
    –   schedule()呼び出し
         ● この部分でスケジューリングされるため、優先

           順位の高い初期スレッドのidleスレッドが動作
           対象。test09_1_mainには映らないので注意
    –   dispatch()呼び出し
         ● currentにあるidleスレッドのstart_threadsが

           実行を再開
まとめ5
●   dispatch()が呼ばれると、割込みが発生した
    kz_syscall()にあるasm volatile(“trapa
    #0”)から続く
●   特に処理がないので、kz_run()に戻り、return
    param.un.run.retでtest09_1_idにその値が代
    入され、test09_2_id = ...と処理が同じよう
    に続く
まとめまとめ
●   kz_run()の流れは以上のような形
●   優先順位によってschedlue()で動作するスレッ
    ドが決まるので、ここを気をつけてみる必要が
    ある
●   あとはkz_sleep()が難しいかも。レディー?
    キューから外した場合、test09_1_idにスレッ
    ドIDが保存されていて、kz_sleep()ではそれを
    使ってレディー?キューに再度入れていること
    になっている
    –   スリープさせたスレッドの管理が微妙な気がするけ
        れど、こういうものなんだろうか

More Related Content

【学习メモ#9迟丑】12ステップで作る组込み翱厂自作入门

  • 5. 優先度 ● 組込みのOSでは一般的に優先度をベースにスケ ジューリングが行われている ● 優先度の高いスレッドが常に動作する
  • 6. スレッドの状態 ● ここまでのプログラムのスレッドは常に「動作 可能」の状態。常に動いているってこと ● これだと複数スレッド間で同期的な動作をさせ られない – あるスレッドが特定の処理を行うまで別スレッドが 待ち合わせする、といったことができない ● そこでスレッドに「待ち」という状態を追加す る – スレッドを待ちにするシステム?コールを作る ● 待ち状態にするにはレディー?キューからス レッドを抜けばいい
  • 7. スレッドにおける状態の呼び名 ● スレッドが「待ち」状態に入ることをスリープ やウェイティングと呼ぶ ● スレッドがキューに繋がって動作可能の状態を レディーと呼ぶ ● スリープ状態のスレッドをレディー状態に戻す ことをウェイクアップと呼ぶ ● 動作中のスレッドはアクティブやランニングな どと呼ぶ ● このように、スレッドにはレディーとスリープ の2つの状態が存在する
  • 8. 優先度とプリエンプション ● ここまでのプログラムだと、実行可能なスレッ ドが複数ある場合はシステム?コールによって 順番に実行するようになっている ● しかし、組込みシステムではあるスレッドがレ ディー状態になったとき、別のスレッドをさし おいてでも動作させたい場合がある – たとえば車のエアバック制御は、衝突を検知したら 一番に処理したい部分 ● ある割込みが発生した場合に、必ず一定時間内 で処理を開始するという時間保証が行えるかど うかを、OSのリアルタイム性と言う
  • 9. リアルタイムOS ● リアルタイム性を提供するOSをリアルタイムOS と呼ぶ ● ハードウェア制御だと、ある割込み発生から特 定の処理を一定時間内に必ず行う必要があるな どの時間制約がある場合がある。こういったと きにOSのリアルタイム性は重要 ● 複数のスレッドがレディー状態のとき、どれを 動作するのか選択する必要があり、それに優先 度が利用される
  • 10. プリエンプション ● スレッドの動作が別のスレッドに強制的に切り 替わる動作を一般的にプリエンプションと呼ぶ – 優先度を持ったスレッドなら、優先度の低いスレッ ドの実行が中断され、優先度の高いスレッドが実行 されることでこのように動作する ● プリエンプションが可能であることをプリエン プティブと言い(先取り可能とも言う)、スレッ ドが突然中断するようなことが無いのであれば ノンプリエンプティブと呼ぶ ● KOZOSはプリエンプティブなOSとして開発して いく
  • 11. アイドル?スレッド ● スレッドに優先度がつくと、やることがないと きにCPUを省電力モードにするアイドル?ス レッドが簡単に実装できる ● 今のプログラムだとレディー?キューが空にな るとシステムダウンしてしまうため、空になら ないよう一番低い優先度で「ムダななんらかの 処理」をするスレッドを常に動かしておく必要 がある while(1) { // なにもしない状態 }
  • 12. 省電力モード ● 一般的なCPUには省電力モードという状態があ る – x86でいうところのHLT命令かな ● CPUを省電力モードにすると命令の実行を停止 し、割込みが入るまで待つ状態になる – クロックが止まるので省電になるようだ ● 他に動作する処理がないなら、アイドル?ス レッドを実行して待機状態にすれば良い while(1) { // ビジーループよりこうした命令を使うべきだね (CPUを省電力モードに遷移する命令); }
  • 14. プログラムの修正と追加 ● 追加ファイル – test09_1.c,test09_2,test09_3...スレッドとなる サンプルプログラム ● 修正ファイル – kozos.h,kozos.c...優先度を実装 – syscall.h,syscall.c...スレッド制御のシステム コール追加 – main.c...アイドル?スレッド追加 – Makefile
  • 15. プログラムの修正内容 ● スレッドの状態を制御するシステム?コールの 追加 – kz_wait(),kz_sleep(),kz_wakeup(),kz_getid(),kz _chpri() ● 優先度の追加 – 構造体に値を持たせて ● readayqueを配列化 – 優先度のスレッド別にまとめる形 – ここのらへんのスケジューリングのアルゴリズムが 少し複雑かなってぐらいで、あとは8thステップの 延長
  • 17. ビルドの失敗(kozos.c) ● パディングのサイズを変更 typedef struct _kz_thread { . . kz_context context; char dummy[8]; ←dummy[16]からdummy[8]にした } kz_thread;
  • 18. プログラムの実行 /Users/sandai/12step/src/09/os% sudo cu -l /dev/tty.usbserial-FTG6PQ4H kzload> run . . test09_3 started. test09_3 wakeup in (test09_1). test09_1 sleep out. test09_1 chpri in. test09_3 wakeup out. test09_3 wakeup in (test09_2). test09_2 sleep out. test09_2 chpri in. test09_1 chpri out. test09_1 wait in. test09_3 wakeup out. test09_3 wait in. test09_2 chpri out. test09_2 wait in. test09_1 wait out. test09_1 trap in. test09_1 DOWN. test09_1 EXIT. test09_3 wait out. test09_3 exit in. test09_3 EXIT. test09_2 wait out. test09_2 exit. test09_2 EXIT.
  • 20. まとめ1 ● 8thステップを理解していないと9thステップは 何をやっているのかわからないはず ● プログラムの修正部分に難しいコードはない ● システム?コールとスケジューリング部分のア ルゴリズムの処理の流れが難しいので、そこを まとめておこう
  • 21. まとめ2 ● 下記のkz_run()のうち、test09_1_id = ...の 処理の流れを記述しておく ● kz_start()でstart_threads()が起動した後の ことなので注意 static int start_threads(int argc, char *argv[]) { test09_1_id = kz_run(test09_1_main, "test09_1", 1, 0x100, 0, . .
  • 22. まとめ3 ● kz_run() – kz_syscall()に渡すデータを構造体に保存 – kz_syscall()呼び出し ● kz_syscall() – current->syscall.xxxにシステムコールのタイプと kz_run()で受け取った構造体を設定 – asm volatile(“trapa #0”)で割込みが発生して thread_intr()呼び出し
  • 23. まとめ4 ● thread_intr() – handlers[type]()によりsyscall_intr()呼び出し ● 最終的にthread_run()が呼び出されてp- >un.run.ret = にcurrentが代入される – schedule()呼び出し ● この部分でスケジューリングされるため、優先 順位の高い初期スレッドのidleスレッドが動作 対象。test09_1_mainには映らないので注意 – dispatch()呼び出し ● currentにあるidleスレッドのstart_threadsが 実行を再開
  • 24. まとめ5 ● dispatch()が呼ばれると、割込みが発生した kz_syscall()にあるasm volatile(“trapa #0”)から続く ● 特に処理がないので、kz_run()に戻り、return param.un.run.retでtest09_1_idにその値が代 入され、test09_2_id = ...と処理が同じよう に続く
  • 25. まとめまとめ ● kz_run()の流れは以上のような形 ● 優先順位によってschedlue()で動作するスレッ ドが決まるので、ここを気をつけてみる必要が ある ● あとはkz_sleep()が難しいかも。レディー? キューから外した場合、test09_1_idにスレッ ドIDが保存されていて、kz_sleep()ではそれを 使ってレディー?キューに再度入れていること になっている – スリープさせたスレッドの管理が微妙な気がするけ れど、こういうものなんだろうか