TOPPERS Confidential TOPPERSプロジェクト ディスカッションメモ ミューテックス機能に関する検討 作成者: 高田広章(名古屋大学) 最終更新: 2009年12月31日 ○メモの位置付け このドキュメントは,TOPPERS新世代カーネルにおけるミューテックス機能の仕 様と実装について検討するものである.TOPPERS/ASPカーネルのミューテックス 機能拡張に関する設計メモも含んでいる. ○前提となる方針 TOPPERS新世代カーネルにおいては,現時点では,μITRON4.0仕様のミューテッ クス機能の優先度継承プロトコルはサポートしない.また,厳密な優先度制御 規則のみをサポートし,簡略化した優先度制御規則はサポートしないものとす る. ○μITRON4.0仕様およびHRPカーネル仕様の問題点 μITRON4.0仕様およびHRPカーネルにおけるミューテックスの仕様に対して,以 下の問題が指摘されている.なお,問題点を示す順序は,おおよそ指摘のあっ た順序であり,問題点の重大性を示すものではない. ●問題点の指摘1(μITRON4.0仕様) ---------------------------------------- ・ミューテックス機能を使用していた場合の、chg_priの動作について  μITRON仕様書の"chg_pri"の説明欄に、以下の記載があるかと思います.  「・・・.このサービスコールを実行した結果、対象タスクの現在優先度  がベース優先度に一致している場合には、次の処理を行う.・・・」  対象となるタスクが、優先度上限もしくは継承プロトコルのミューテックス  をロックしている、あるいは解除待ち状態の場合でも、上記条件を満たして  いるならば、指定された優先度の中で最低の優先順位に変更する必要がある  のでしょうか.  この仕様を適用するのが正しい場合、特にミューテックスをロックしている  タスクに対して、同じ優先度の中でも優先順位を下げること自体が、  ミューテックス本来の使用意図に反しているように思えるのですが、如何で  しょうか. ---------------------------------------- ●問題点の指摘2(HRPカーネル) ---------------------------------------- 低優先度タスクAがディスパッチ禁止した後,高優先度タスクBがレディ状態に なり(ディスパッチ禁止なのでタスク切換えは起こらない),その後にタスク Aが優先度上限がタスクBと同じミューテックスに対してploc_mtxを発行して, タスクBと同じ優先度まで上がった場合を考える.HRPカーネルでは,タスクAは タスクBよりも優先順位が低くなる.その後,タスクAがディスパッチ許可する と,タスクBに切り換わることになり,排他制御対象のタスク全体と排他される わけではなくなる. ---------------------------------------- ●問題点3(μITRON4.0仕様) ---------------------------------------- 同じ優先度のタスクAとタスクB,それらよりも高い上限優先度を持った優先度 上限ミューテックスがある場合を考える.タスクAがミューテックスをロックし, タスクBがミューテックスを待っている状況で,タスクAがミューテックスをロッ ク解除した場合に,タスクBがミューテックスをロックして優先度が上がり,タ スクBに切り換わってしまう.タスクAが一連で実行されない. この問題は,タスクBの優先度が,タスクAよりも低い場合にも起こる. → スケジューリング理論的には,優先度上限ミューテックスに対して待ち状態 になることはないので,こういうケースは考慮されていない. → タスクAが一連で実行されないのは,大きい問題ではないという意見も. 類似だが優先順位の扱いによっては回避可能なケース: (a) 高優先度のタスクAと低優先度のタスクB,タスクAの優先度と同じ上限優先 度を持った優先度上限ミューテックスがある場合を考える.タスクAがミューテッ クスをロックし,タスクBがミューテックスを待っている状況で,タスクAが ミューテックスをロック解除した場合に,タスクBがミューテックスをロックし て優先度が上がる.優先順位の扱いによっては,タスクBに切り換わってしまう. (b) 同じ優先度のタスクAとタスクB,それらと同じ上限優先度を持った優先度 上限ミューテックスがある場合を考える.タスクAがミューテックスをロックし, タスクBがミューテックスを待っている状況で,タスクAがミューテックスをロッ ク解除した場合に,優先順位の扱いによっては,タスクBに切り換わってしまう. ---------------------------------------- ●問題点3-2(μITRON4.0仕様をマルチプロセッサ拡張した場合) ---------------------------------------- マルチプロセッサにおいて,プロセッサ1にタスクA,プロセッサ2に優先度の低 いタスクB1,B2,B3と優先度の高いタスクC,それらよりも高い上限優先度を持っ た優先度上限ミューテックスがある場合を考える.タスクAがミューテックスを ロックし,タスクB1,B2,B3がミューテックスを待っており,プロセッサ2ではタ スクCが実行されている状況で,タスクAがミューテックスをロック解除した場 合に,タスクB1がミューテックスをロックして優先度が上がり,タスクB1に切 り換わってしまう.さらに,タスクB2,B3も高い優先度で実行され,タスクCが タスクB1,B2,B3のクリティカルセクションに待たされてしまう. ---------------------------------------- ●問題点4(HRPカーネル) ---------------------------------------- HRPカーネルでは,優先度継承に伴ってタスクの現在優先度が変化する場合に, 同優先度内での優先順位を最低にする(μITRON4.0仕様では実装依存としてい る).この仕様には,次のような問題がある. 同じ優先度のタスクAとタスクB,それらよりも高い上限優先度を持った優先度 上限ミューテックスがある場合を考える.タスクAが実行状態,タスクBが実行 可能状態であるとする.タスクAがミューテックスをロックし,その後ロック解 除すると,タスクAの優先順位が同優先度内で最低となり,タスクBに切り換わっ てしまう. この振舞いは,一度タスクの実行が開始すると優先度逆転にあわないという優 先度上限プロトコルの性質に反する. ---------------------------------------- ○問題点3の考察と方針 問題点3を回避するためには,優先度上限ミューテックスをロック解除した時 に,ロック待ち状態のタスクにすぐにミューテックスをロックさせてはならな いことになる.すなわち,ロック待ち状態のタスクの待ち解除のみを行い,そ のタスクが次にスケジュールされた時にミューテックスをロックし,優先度を 変更する処理を行えばよい.POSIXのミューテックスは,この方針で実装すべき ものと思われる. このように仕様変更した場合,rel_waiの扱いや,タイムアウトの扱いが問題に なる.タイムアウトは,ミューテックスの待ち行列につながれて待ち状態となっ ている時間だけでなく,待ち解除されて次にスケジュールされるのを待ってい る時間も含めて扱うべきである.また,そのタイミングでrel_waiが発行された 場合の扱いも,どちらにするか決めておくことが必要である(どちらの仕様で も成立すると考えられる).これまでのITRON仕様の同期・通信オブジェクトに なかった振舞いであり,あちこちに影響が及ぶ可能性がある. このような大規模な仕様変更を避けるためには,そもそも,優先度上限ミュー テックスを取得したタスクが待ち状態になるような使い方が推奨されるもので はなく,その場合には想定通りには振る舞わないことを制限事項とする以外に ないと思われる.優先度上限ミューテックスを取得したタスクが待ち状態にな るなどの理由で実行権を失わなければ,優先度上限ミューテックスに対して待 ち状態になる状況も起こらない(マルチプロセッサの場合を除く).そのため, この制限事項を設ければ,問題点3の状況は起こらず,問題ではないことにな る. ユーザに対しては,優先度上限ミューテックスをロックする時にはploc_mtxを 使うことを推奨すれば,この問題を確実に回避することができる. マルチプロセッサの場合には,優先度上限ミューテックスを取得したタスクが 実行権を失わなくても,優先度上限ミューテックスに対して待ち状態になる状 況が起こる.そのため,問題点3-2のような問題が避けられない. 今のところ,マルチプロセッサの場合にこれに対処するには,POSIXの実装方針 を採用するしかないものと思われるが,POSIXの実装方針には,ミューテックス 解放時にすべてのタスクが動き出してしまうためにオーバヘッドが大きいとい う別の問題がある. 結局,マルチプロセッサの場合の良い解決法がないのが現状である. 以上より,(特にマルチプロセッサの場合に)問題は残っているが,現時点で は,現状の仕様でやむなしとする. ○問題点4の考察と方針 問題点4については,想定された使用方法で発生するため,制限事項とするこ とはできず,何らかの仕様の見直しが必要である. 問題点4を回避するには,少なくとも,次の変更が必要である. ・優先度上限ミューテックスを解放したことによりタスクの現在優先度が低く  なる場合には,同優先度内での優先順位を最高にする. これは,優先度上限ミューテックスを獲得して実行していたタスクは,低くなっ た後の優先度と同じ優先度を持つ他タスクよりも先に実行可能になったはずで あり,その中では最高優先順位を持つべきと考えられるためである. 優先度上限ミューテックスを解放したことによりタスクの現在優先度が変化し ない場合にも同じことが言えるが,その現在優先度で実行状態であったという ことは,同優先度内では最高優先順位を持っていたことになり(ディスパッチ 保留状態の場合を除く),優先順位は変化しないものとしても同じ結果となる. ただし,ディスパッチ保留状態の場合の振る舞いを規定するために,優先順位 を最高とするか変更しないとするかは決めておく必要がある. 仕様の単純さを考えると,特殊な状況(優先度上限ミューテックスを解放した ことによりタスクの現在優先度が低くなる場合)でのみ最高優先順位とするよ り,最高優先順位とする場合をできる限り一般的にした方がよいと考えられる. このことから,次の仕様が有力な案として出てくる. ・ミューテックス機能によりタスクの現在優先度が変化する場合には,同じ優  先度のタスクの中で最高優先順位となる.現在優先度が変化しない場合には,  タスクの優先順位は変更されない. ここで,現在優先度が変化するタスクが待ち状態の場合の振舞いを規定する必 要がある.上と整合させるなら,タスクが待ち状態で,タスクの優先度順の待 ち行列につながれている場合には,同じ優先度のタスクの中で最初にするのが 自然であるが,待ち状態の間まで優先順位を保持するのはやりすぎとも考えら れる.また,タスク状態が変化すると同時に,優先度が変化する場合も考える 必要がある. これらを考慮して,次の仕様とする. ・ミューテックス機能によりタスクの現在優先度が変化する場合の扱いは次の  通りとする.対象タスクがサービスコールの前後とも実行できる状態である  場合には,同じ優先度のタスクの中で最高優先順位となる.そうでない場合  には,同じ優先度のタスクの中で最低優先順位となる.現在優先度が変化し  ない場合には,タスクの優先順位は変更されない. !対象タスクが待ち状態の場合の振舞いは,より厳密に規定する必要がある. さらに,複数のタスクの現在優先度が同時に変化する場合には,タスクの現在 優先度を変化させる順序によって結果が異なってくるため,優先度を変化させ る順序を明確化することが必要である. -------------------- ★上の仕様で問題がないことを確認するための検討(優先度上限ミューテック スによる場合) 優先度上限ミューテックスを(待ち状態に入ることなく)獲得したことにより タスクの現在優先度が上がる場合には,それまでの現在優先度で実行状態であっ たことから,新しい現在優先度と同じ優先度を持つタスクは他にないことにな り(ディスパッチ保留状態の場合を除く),優先順位を最高としても最低とし ても同じ結果となる. 優先度上限ミューテックスを(待ち状態に入ることなく)獲得したことにより タスクの現在優先度が変化しない場合には,それまでの現在優先度で実行状態 であったことから,同優先度内では最高優先順位を持っていたことになり(ディ スパッチ保留状態の場合を除く),優先順位を最高としても変化しないものと しても同じ結果となる. 優先度上限ミューテックス待ち状態から待ち解除され,優先度上限ミューテッ クスを獲得する場合は,制限事項としていることから,どのように決めてもよ い. -------------------- ○他の問題点の考察と方針 制限事項を設けることで問題点3は問題ではないとすると,問題点2について も,ディスパッチ禁止と併用すると想定通りには振る舞わないとすればよい. その他に,rot_rdqと併用した場合には,明らかに制限事項を設けなければなら ない. 問題点1についても,ベース優先度の変更と併用すると想定通りには振る舞わ ないとする手もあるが,次のように仕様を修正する手もある. ・chg_priでタスクのベース優先度を変更した場合の扱いは次の通りとする.対  象タスクがベース優先度を変更した後の状態でミューテックス経由でベース  優先度と同じかそれより高い優先度を継承している場合には,現在優先度が  変化するなら同じ優先度のタスクの中で最高優先順位となり,現在優先度が  変化しないなら優先順位も変化しない.それ以外の場合には,同じ優先度の  タスクの中で最低優先順位となる. ここで,優先度継承ミューテックスをサポートしない場合には,次のことが言 える.タスクがロックすることができる優先度上限ミューテックスの上限優先 度は,そのタスクの変更前後のベース優先度と同じかそれより高い.そのため, 優先度上限ミューテックスをロックしている場合には,必ず,「ミューテック ス経由でベース優先度と同じかそれより高い優先度を継承している」.つまり, 「ミューテックス経由でベース優先度と同じかそれより高い優先度を継承して いる場合」は「優先度上限ミューテックスをロックしている場合」と一致する. さらに,優先度上限ミューテックスをロックしている場合には,chg_priでタス クのベース優先度変更しても,そのタスクの現在優先度が変化することはない. 以上のことから,上の修正仕様は,次の通りに簡単化することができる. ・chg_priでタスクのベース優先度を変更した場合の扱いは次の通りとする.対  象タスクが優先度上限ミューテックスをロックしていない場合,同じ優先度  のタスクの中で最低優先順位となる.それ以外の場合には,対象タスクの現  在優先度が変更されることはなく,優先順位も変更されない. ○chg_priの機能記述(関連部分のみ) ---------------------------------------------------------------------- 対象タスクが休止状態でない場合には,対象タスクのベース優先度が,tskpri で指定した優先度に変更される.それに伴って,対象タスクの現在優先度も変 更される. 対象タスクが,優先度上限ミューテックスをロックしていない場合には,次の 処理が行われる.対象タスクが実行できる状態の場合には,同じ優先度のタス クの中で最低優先順位となる.対象タスクが待ち状態で,タスクの優先度順の 待ち行列につながれている場合には,対象タスクの変更後の現在優先度に従っ て,その待ち行列中での順序が変更される.待ち行列中に同じ現在優先度のタ スクがある場合には,対象タスクの順序はそれらの中で最後になる. 対象タスクが,優先度上限ミューテックスをロックしている場合には,対象タ スクの現在優先度が変更されることはなく,優先順位も変更されない. ---------------------------------------------------------------------- ○ASPカーネルへの実装方針 ●タスク管理ブロックとミューテックス管理ブロック ミューテックス機能を実現するためのデータ構造として,ミューテックスの待 ち行列(ミューテックスを待っているタスクのリスト)に加えて,タスクに対 してそれがロックしているミューテックスのリストと,ミューテックスに対し てそれを保持しているタスクを管理する必要がある. そこで,TCBには,ロックしているミューテックスのキューヘッダのフィールド を追加する.また,現在優先度に加えて,ベース優先度を保持するフィールド を追加する. ---------------------------------------- typedef struct task_control_block { ... BIT_FIELD_UINT bpriority : TBIT_TCB_PRIORITY; /* ベース優先度(内部表現)*/ BIT_FIELD_UINT priority : TBIT_TCB_PRIORITY; /* 現在優先度(内部表現)*/ ... QUEUE mutex_queue; /* ロックしているミューテックスのキュー */ ... } TCB; ---------------------------------------- bpriorityは,休止状態以外で有効な変数であるため,make_dormantで初期化す る. mutex_queueは,休止状態以外で有効な変数であるが,休止状態に遷移する際に 必ず空にするので,(make_dormantではなく)initialize_taskにおいて初期化 する. また,tstatフィールドに入れるタスク状態の内部表現に,TS_WAIT_MTX(ミュー テックスのロック待ち)を追加する. ミューテックス管理ブロックには,ミューテックス待ちキューに加えて,ミュー テックスをロックしているタスクのTCBへのポインタと,タスクがロックしてい るミューテックスのキューにつなぐためのフィールドを用意する. ---------------------------------------- typedef struct mutex_control_block { QUEUE wait_queue; /* ミューテックス待ちキュー */ const MTXINIB *p_mtxinib; /* 初期化ブロックへのポインタ */ TCB *p_loctsk; /* ミューテックスをロックしているタスク */ QUEUE mutex_queue; /* ロックしているミューテックスのキュー */ } MTXCB; ---------------------------------------- ミューテックスがロックされていないことは,p_loctskをNULLに設定すること で表す.ミューテックスがロックされていない時には,mutex_queueは無効で ある. ミューテックス初期化ブロックには,ミューテックス属性とミューテックスの 上限優先度を保持する. ---------------------------------------- typedef struct mutex_initialization_block { ATR mtxatr; /* ミューテックス属性 */ uint_t ceilpri; /* ミューテックスの上限優先度(内部表現)*/ } MTXINIB; ---------------------------------------- タスクを手掛かりに,それがロックしているミューテックスを操作することが 多いため,ミューテックス管理ブロック中のmutex_queueへのポインタから, ミューテックス管理ブロックへのポインタを取り出すためのマクロを用意して おく(mutex.c). ---------------------------------------- #define MTXCB_QUEUE(p_queue) \ ((MTXCB *)(((char *) p_queue) - offsetof(MTXCB, mutex_queue))) ---------------------------------------- ●優先度制御規則と現在優先度の計算 TOPPERS新世代カーネルでは,μITRON4.0仕様の厳密な優先度制御規則のみを実 装する.厳密な優先度制御規則においては,タスクの現在優先度を,常に,以 下の優先度の最高値に一致するように設定する. (1) タスクのベース優先度 (2) タスクが優先度上限ミューテックスをロックしている場合,それらのミュー テックス中で,最も高い上限優先度を持つミューテックスの上限優先度 (3) タスクが優先度継承ミューテックスをロックしている場合,それらのミュー テックスのロックを待っているタスクの中で,最も高い現在優先度を持つ タスクの現在優先度 これらの優先度を,ここでは,現在優先度を決定する要素となるという意味で, 要素優先度と呼ぶ. ASPカーネルのミューテックス拡張では,優先度継承ミューテックスはサポート しないため,(3)は考える必要がない. まずは,すべての要素優先度をスキャンし,タスクの現在優先度を計算する関 数を実装する.この関数を呼ぶことにより,タスクの現在優先度に設定すべき 値を計算することができる. ---------------------------------------- /* * タスクの現在優先度の計算 */ static uint_t mutex_calc_priority(TCB *p_tcb) { uint_t priority; QUEUE *p_queue; MTXCB *p_mtxcb; priority = p_tcb->bpriority; p_queue = p_tcb->mutex_queue.p_next; while (p_queue != &(p_tcb->mutex_queue)) { p_mtxcb = MTXCB_QUEUE(p_queue); if (MTX_CEILING(p_mtxcb) && p_mtxcb->p_mtxinib->ceilpri < priority) { priority = p_mtxcb->p_mtxinib->ceilpri; } p_queue = p_queue->p_next; } return(priority); } ---------------------------------------- ●現在優先度の変更後の処理 ミューテックス機能によりタスクの現在優先度を変更した場合には,TCB中の現 在優先度を更新することに加えて,次の処理を行う必要がある ---------------------------------------- ミューテックス機能によりタスクの現在優先度が変化する場合には,次の処理 が行われる.現在優先度を変化させるサービスコールの前後とも,当該タスク が実行できる状態である場合には,同じ優先度のタスクの中で最高優先順位と なる.そのサービスコールにより,当該タスクが実行できる状態に遷移する場 合には,同じ優先度のタスクの中で最低優先順位となる.そのサービスコール の後で,当該タスクが待ち状態で,タスクの優先度順の待ち行列につながれて いる場合には,当該タスクの変更後の現在優先度に従って,その待ち行列中で の順序が変更される.待ち行列中に同じ現在優先度のタスクがある場合には, 当該タスクの順序はそれらの中で最後になる. ---------------------------------------- この処理を実現するために,現在優先度を変更する際に,同じ優先度のタスク の中で最高優先順位とする関数が必要である.このような関数を新たに用意す ることも可能であるが,多くの部分がchange_priorityと共通であるため, change_priorityに新たなパラメータmtxmodeを追加し,mtxmodeがfalseの時は 同じ優先度のタスクの中で最低優先順位,mtxmodeがtrueの時は同じ優先度のタ スクの中で最高優先順位とするように修正する. ---------------------------------------- bool_t change_priority(TCB *p_tcb, uint_t newpri, bool_t mtxmode) { uint_t oldpri; oldpri = p_tcb->priority; p_tcb->priority = newpri; if (TSTAT_RUNNABLE(p_tcb->tstat)) { /* * タスクが実行できる状態の場合 */ queue_delete(&(p_tcb->task_queue)); if (queue_empty(&(ready_queue[oldpri]))) { primap_clear(oldpri); } if (mtxmode) { queue_insert_next(&(ready_queue[newpri]), &(p_tcb->task_queue)); } else { queue_insert_prev(&(ready_queue[newpri]), &(p_tcb->task_queue)); } primap_set(newpri); if (p_schedtsk == p_tcb) { if (newpri >= oldpri) { p_schedtsk = search_schedtsk(); return(p_schedtsk != p_tcb && dspflg); } } else { if (mtxmode ? newpri <= p_schedtsk->priority : newpri < p_schedtsk->priority) { p_schedtsk = p_tcb; return(dspflg); } } } else { if (TSTAT_WAIT_WOBJCB(p_tcb->tstat)) { /* * タスクが,同期・通信オブジェクトの管理ブロックの共通部 * 分(WOBJCB)の待ちキューにつながれている場合 */ wobj_change_priority(((WINFO_WOBJ *)(p_tcb->p_winfo))->p_wobjcb, p_tcb); } } return(false); } ---------------------------------------- ここで,同じ優先度のタスクの中で最高優先順位となるのは,現在優先度を変 化させるサービスコールの前後とも当該タスクが実行できる状態である場合に 限られるため,wobj_change_priorityを修正する必要はない. chg_priからchange_priorityを呼ぶ場合には,mtxmodeをfalseにする. 一方,ミューテックス機能により,タスクの状態が変化せずに,タスクの現在 優先度が変化する時は,mtxmodeをtrueにしてchange_priorityを呼ぶ.タスク の状態が変化する場合には,別途検討する. ●現在優先度の制御処理 現在優先度の制御を行う際に,現在優先度を決定するための要素優先度が上が る(または増える)場合と,下がる(または減る)場合では大きい違いがある. 要素優先度が上がる(または増える)場合には,上がった後の要素優先度とタ スクの現在優先度を比較するだけで,現在優先度の変更の必要性が判断できる. すべての要素優先度をスキャンする必要はない. それに対して,要素優先度が下がる(または減る)場合で,下がる前の要素優 先度がタスクの現在優先度と一致していた場合(言い換えると,その要素優先 度がタスクの現在優先度を決定していた場合)には,すべての要素優先度をス キャンしてタスクの現在優先度を計算することが必要である.下がる前の要素 優先度がタスクの現在優先度と一致していなかった場合には,現在優先度が変 更になる可能性はなく,この処理は必要ない. 言うまでもなく,要素優先度が変化しない場合には,タスクの現在優先度も変 化せず,処理は必要ない. 要素優先度が上がる(または増える)場合の処理は次の通り.newpriには,上 がった後の(または増えた)要素優先度を渡す. ---------------------------------------- /* * 要素優先度が上がる(または増える)場合の現在優先度変更処理 */ Inline bool_t mutex_raise_priority(TCB *p_tcb, uint_t newpri) { if (newpri < p_tcb->priority) { return(change_priority(p_tcb, newpri, true)); } return(false); } ---------------------------------------- 要素優先度が下がる(または減る)場合の処理は次の通り.oldpriには,下が る前の(または減った)要素優先度を渡す. ---------------------------------------- /* * 要素優先度が下がる(または減る)場合の現在優先度変更処理 */ Inline bool_t mutex_drop_priority(TCB *p_tcb, uint_t oldpri) { uint_t newpri; if (oldpri == p_tcb->priority) { newpri = mutex_calc_priority(p_tcb); if (newpri != p_tcb->priority) { return(change_priority(p_tcb, newpri, true)); } } return(false); } ---------------------------------------- いずれの関数も,タスクディスパッチが必要な場合にtrue,必要ない場合に falseを返す. ●優先度制御の必要箇所 前述の(1)および(2)の優先度が変化する場合に,タスクの現在優先度の変更が 必要になる可能性がある.そこで,(1)および(2)の優先度のそれぞれについて, どのような場合に変化するかを検討し,プログラム中のどの箇所で現在優先度 を変更すべきか洗い出す. (1)「タスクのベース優先度」が変化するのは,chg_priによってタスクのベー ス優先度を変更した場合のみである.この時は,要素優先度が上がる場合 も下がる場合もある. (2)「タスクが優先度上限ミューテックスをロックしている場合,それらのミュー テックス中で,最も高い上限優先度を持つミューテックスの上限優先度」 が変化するのは,以下のいずれかの状況である. (2-1) 優先度上限ミューテックスをロックした時.この時は,要素優先度が増 える. (2-2) 優先度上限ミューテックスをロック解除した時.この時は,要素優先度 が減る. ●優先度制御の実装 上で整理した優先度制御の必要箇所毎に,実装方法を検討する.(1)のchg_pri の処理については後でまとめて検討することとし,ここでは(2-1)と(2-2)につ いて検討する. (2-1) 優先度上限ミューテックスをロックした時 タスクがミューテックスをロックする処理は,loc_mtx,ploc_mtx,tloc_mtxに 加えて,unl_mtx,ext_tsk,ter_tskにある. loc_mtx,ploc_mtx,tloc_mtxでタスクがミューテックスをロックした場合には, ミューテックスをロックしたタスクをp_loctsk,ロックしたミューテックスを p_mtxcbとすると,次の処理を行えばよい. ---------------------------------------- mutex_raise_priority(p_loctsk, p_mtxcb->p_mtxinib->ceilpri); ---------------------------------------- 一方,unl_mtx,ext_tsk,ter_tskでタスクがミューテックスをロックするのは, ミューテックス待ち状態のタスクが待ち解除された場合である.この場合には, 「現在優先度を変化させるサービスコールの前後とも当該タスクが実行できる 状態である場合」に該当しないため,待ち解除されたタスクは,同じ優先度の タスクの中で最低優先順位となる. そこで,この場合にはmtxmodeをtrueにしてchange_priorityを呼び出す mutex_raise_priorityを使わずに,新しい現在優先度をTCBに設定した後に, make_non_waitを呼び出す形で実装する.具体的には,待ち解除されてミューテッ クスをロックしたタスクをp_tcb,ロックしたミューテックスをp_mtxcbとする と,次の処理を行う. ---------------------------------------- if (MTX_CEILING(p_mtxcb)) { if (p_mtxcb->p_mtxinib->ceilpri < p_tcb->priority) { p_tcb->priority = p_mtxcb->p_mtxinib->ceilpri; } } make_non_wait(p_tcb); ---------------------------------------- 上記のコードは,ミューテックスのロック解除処理を行うmutex_releaseの中に 含める.mutex_releaseの実装は次の通り. ---------------------------------------- static bool_t mutex_release(MTXCB *p_mtxcb) { TCB *p_tcb; if (queue_empty(&(p_mtxcb->wait_queue))) { p_mtxcb->p_loctsk = NULL; return(false); } else { /* * ミューテックス待ちキューの先頭タスク(p_tcb)に,ミューテッ * クスをロックさせる. */ p_tcb = (TCB *) queue_delete_next(&(p_mtxcb->wait_queue)); wait_dequeue_tmevtb(p_tcb); p_tcb->p_winfo->wercd = E_OK; p_mtxcb->p_loctsk = p_tcb; queue_insert_prev(&(p_tcb->mutex_queue), &(p_mtxcb->mutex_queue)); if (MTX_CEILING(p_mtxcb)) { if (p_mtxcb->p_mtxinib->ceilpri < p_tcb->priority) { p_tcb->priority = p_mtxcb->p_mtxinib->ceilpri; } } return(make_non_wait(p_tcb)); } } ---------------------------------------- この関数の後半は,次のように実装することも可能に思える. ---------------------------------------- else { bool_t dspreq = false; p_tcb = (TCB *) queue_delete_next(&(p_mtxcb->wait_queue)); if (wait_complete(p_tcb)) { dspreq = true; } if (mutex_acquire(p_tcb, p_mtxcb)) { dspreq = true; } return(dspreq); } ---------------------------------------- しかしこのコードには,ミューテックスをロックしたタスクの優先順位が,同 じ優先度のタスクの中で最高となってしまうという問題がある.仕様に合わせ るためには,mutex_acquireに対してパラメータmtxmodeを追加するなどの修正 が必要である. またこのコードは,wait_compleateでタスクをレディキューにつないだ後, mutex_acquireから呼んだmutex_raise_priorityでレディキューからの削除と挿 入を行う場合があり,効率が悪い. (2-2) 優先度上限ミューテックスをロック解除した時 タスクがミューテックスをロック解除する処理は,unl_mtxに加えて,ext_tsk, ter_tsk,ini_mtxにある.この場合には,ミューテックスをロック解除したタ スクをp_loctsk,ロック解除したミューテックスをp_mtxcbとすると,次の処理 を行えばよい. ---------------------------------------- mutex_drop_priority(p_loctsk, p_mtxcb->p_mtxinib->ceilpri); ---------------------------------------- ●各処理の実装 ・loc_mtx,ploc_mtx,tloc_mtx loc_mtxの中では,ミューテックスをロックする処理と,ミューテックスのロッ クを待ち始める処理を行う.そのため,前述の優先度変更箇所の(2-1) に対応 しなければならない.この内(2-1)の処理は,mutex_acquireの中で行う. ・unl_mtx unl_mtxの中では,ミューテックスをロック解除する処理と,待ち状態であった タスクにミューテックスをロックさせる処理を行う.そのため,前述の優先度 変更箇所の(2-1),(2-2)に対応しなければならない.この内(2-1)の処理は, mutex_releaseの中で行う. ・ini_mtx ini_mtxの中では,ミューテックスをロック解除する処理と,ミューテックスの ロックを待つのをやめる処理を行う.そのため,前述の優先度変更箇所の (2-2)に対応しなければならない. ・ext_tsk ext_tskの中では,ミューテックスをロック解除する処理と,待ち状態であった タスクにミューテックスをロックさせる処理を行う.そのため,前述の優先度 変更箇所の(2-1),(2-2)に対応しなければならない.(2-1)の処理は, mutex_release_allから呼び出されるmutex_releaseの中で行う. (2-2)の処理については,次の理由により省略することができる.この処理は, ミューテックスのロック解除により自タスクの優先を変更する処理であるが, 自タスクはこのサービスコールにより終了するため,優先度を更新する必要は ない. ・ter_tsk ter_tskの中では,ミューテックスのロックを待つのをやめる処理,ミューテッ クスをロック解除する処理と,待ち状態であったタスクにミューテックスをロッ クさせる処理を行う.そのため,前述の優先度変更箇所の(2-1),(2-2)に対応 しなければならない.(2-1)の処理は,mutex_release_allから呼び出される mutex_releaseの中で行う. (2-2)の処理については,次の理由により省略することができる.この処理は, ミューテックスのロック解除により対象タスクの優先を変更する処理であるが, 対象タスクはこのサービスコールにより終了するため,優先度を更新する必要 はない. ●chg_priの修正 まず,ミューテックスをサポートすることにより,chg_priに以下のエラーチェッ クを追加する必要がある. ---------------------------------------- 対象タスクが優先度上限ミューテックスをロックしているかロックを待ってい る場合,tskpriは,それらのミューテックスの上限優先度と同じかそれより低 くなければならない. ---------------------------------------- このエラーを検出するために,chg_priには次のコードを追加する. ---------------------------------------- else if ((!queue_empty(&(p_tcb->mutex_queue)) || TSTAT_WAIT_MTX(p_tcb->tstat)) && !mutex_check_ceilpri(p_tcb, newbpri)) { ercd = E_ILUSE; } ---------------------------------------- mutex_check_ceilpriの実装は次の通り.この関数は,エラーを検出した場合 にfalseを,そうでない場合にtrueを返す. ---------------------------------------- bool_t mutex_check_ceilpri(TCB *p_tcb, uint_t bpriority) { QUEUE *p_queue; MTXCB *p_mtxcb; /* * タスクがロックしている優先度上限ミューテックスの中で,上限優先 * 度がbpriorityよりも低いものがあれば,falseを返す. */ p_queue = p_tcb->mutex_queue.p_next; while (p_queue != &(p_tcb->mutex_queue)) { p_mtxcb = MTXCB_QUEUE(p_queue); if (MTX_CEILING(p_mtxcb) && bpriority < p_mtxcb->p_mtxinib->ceilpri) { return(false); } p_queue = p_queue->p_next; } /* * タスクが優先度上限ミューテックスのロックを待っている場合に,そ * の上限優先度がbpriorityよりも低くければ,falseを返す. */ if (TSTAT_WAIT_MTX(p_tcb->tstat)) { p_mtxcb = ((WINFO_MTX *)(p_tcb->p_winfo))->p_mtxcb; if (MTX_CEILING(p_mtxcb) && bpriority < p_mtxcb->p_mtxinib->ceilpri) { return(false); } } /* * いずれの条件にも当てはまらなければtrueを返す. */ return(true); } ---------------------------------------- 次に,ベース優先度を変更した後,次の処理を行う必要がある. ---------------------------------------- それに伴って,対象タスクの現在優先度も変更される. 対象タスクが,優先度上限ミューテックスをロックしていない場合には,次の 処理が行われる.対象タスクが実行できる状態の場合には,同じ優先度のタス クの中で最低優先順位となる.対象タスクが待ち状態で,タスクの優先度順の 待ち行列につながれている場合には,対象タスクの変更後の現在優先度に従っ て,その待ち行列中での順序が変更される.待ち行列中に同じ現在優先度のタ スクがある場合には,対象タスクの順序はそれらの中で最後になる. 対象タスクが,優先度上限ミューテックスをロックしている場合には,対象タ スクの現在優先度が変更されることはなく,優先順位も変更されない. ---------------------------------------- これを実現するためには,優先度上限ミューテックスをロックしていない場合 にのみchange_priorityを呼ぶように修正すればよい(change_priorityは, mtxmodeをfalseにして呼ぶ).具体的には,chg_priの主要部分は次のようにな る. ---------------------------------------- p_tcb->bpriority = newbpri; if (queue_empty(&(p_tcb->mutex_queue)) || !mutex_scan_ceilmtx(p_tcb)) { if (change_priority(p_tcb, newbpri, false)) { dispatch(); } } ercd = E_OK; ---------------------------------------- ここで,mutex_scan_ceilmtxは,タスクが優先度上限ミューテックスをロック している場合にtrueを返す関数で,次のように実装される. ---------------------------------------- bool_t mutex_scan_ceilmtx(TCB *p_tcb) { QUEUE *p_queue; MTXCB *p_mtxcb; p_queue = p_tcb->mutex_queue.p_next; while (p_queue != &(p_tcb->mutex_queue)) { p_mtxcb = MTXCB_QUEUE(p_queue); if (MTX_CEILING(p_mtxcb)) { return(true); } p_queue = p_queue->p_next; } return(false); } ---------------------------------------- ●rot_rdqの修正 rot_rdqは,tskpriにTPRI_SELFが指定された場合に,自タスクのベース優先度 を対象優先度とする.ミューテックスの導入により,ベース優先度を表すフィー ルドが新設されたため,その部分のコードを修正する必要がある.具体的には, rot_rdq中の ---------------------------------------- pri = (tskpri == TPRI_SELF) ? p_runtsk->priority : INT_PRIORITY(tskpri); ---------------------------------------- の行を,次のように修正する. ---------------------------------------- pri = (tskpri == TPRI_SELF) ? p_runtsk->bpriority : INT_PRIORITY(tskpri); ---------------------------------------- ●ref_tskの修正 ref_tskは,tskbpriに対象タスクのベース優先度を返す.ミューテックスの導 入により,ベース優先度を表すフィールドが新設されたため,その部分のコー ドを修正する必要がある.具体的には,ref_tsk中の ---------------------------------------- pk_rtsk->tskbpri = EXT_TSKPRI(p_tcb->priority); ---------------------------------------- の行を,次のように修正する. ---------------------------------------- pk_rtsk->tskbpri = EXT_TSKPRI(p_tcb->bpriority); ---------------------------------------- ●ミューテックス機能をリンクしない工夫 最後に,ミューテックス機能を使用しない場合に,ミューテックス関連のコー ドをリンクしない工夫を行う. ミューテックスモジュールの外から呼び出すミューテックスモジュールの内部 関数は次の通り. mutex_check_ceilpri(chg_priより) mutex_scan_ceilmtx(chg_priより) mutex_release_all(ext_tsk,ter_tskより) これらの関数はフックルーチンであるものとし,呼び出す際には,変数参照を はさむことにする.例えば「mutex_release_all(p_runtsk)」の代わりに, (*mtxhook_release_all)(p_runtsk); と記述する.mtxhook_release_allには,ミューテックスモジュールがリンクさ れた場合にはmutex_release_allへのポインタを格納する.具体的には, initialize_mutexにおいて設定する.ミューテックスモジュールがリンクされ ない場合には,mtxhook_release_allを参照してはならないものとする(0が入 ることは仮定しない). 例えば,ext_tskからmutex_release_allを呼ぶ箇所は次のようになる. ---------------------------------------- if (!queue_empty(&(p_runtsk->mutex_queue))) { (void) (*mtxhook_release_all)(p_runtsk); } ---------------------------------------- TCB中のmutex_queueが空でなくなるのは,タスクがミューテックスをロックし ている場合のみで,これはミューテックスモジュールがリンクされた場合に限 られる.そのため上のコードで,ミューテックスモジュールがリンクされない 場合には,mtxhook_release_allが参照されることはない. 他の2つの関数についてもこれと同様に扱う. ●ミューテックス機能拡張のコールグラフ chg_pri -- mutex_check_ceilpri -- change_priority -- wobj_change_priority ext_tsk -- mutex_release_all -- mutex_release ter_tsk -- mutex_release_all -- mutex_release initialize_mutex mutex_check_ceilpri mutex_calc_priority mutex_raise_priority -- change_priority -- wobj_change_priority mutex_drop_priority -- mutex_calc_priority -- change_priority -- wobj_change_priority mutex_acquire -- mutex_raise_priority -- mutex_release_all -- mutex_release loc_mtx -- mutex_acquire -- mutex_raise_priority -- ploc_mtx -- mutex_acquire -- mutex_raise_priority -- tloc_mtx -- mutex_acquire -- mutex_raise_priority -- unl_mtx -- mutex_drop_priority -- -- mutex_release ini_mtx -- mutex_drop_priority -- ref_mtx ○ミューテックス機能のテスト ●ミューテックスのテスト(1) FIFO順ミューテックスを,ロックする処理とロック解除する処理を一通りテス トする. ●ミューテックスのテスト(2) 優先度順ミューテックスを,ロックする処理とロック解除する処理を一通りテ ストする. ●ミューテックスのテスト(3) 優先度上限ミューテックスを,ロックする処理とロック解除する処理を一通り テストする.ref_tskによるベース優先度と現在優先度の参照処理のテストも兼 ねている. ●ミューテックスのテスト(4) 優先度上限ミューテックスに対して,loc_mtxとunl_mtxに伴う優先度の変更処 理を網羅的にテストする.ただし,change_priorityとmutex_calc_priorityの 内容には踏み込まない. ●ミューテックスのテスト(5) 優先度上限ミューテックスに対して,ミューテックスの再初期化処理を網羅的 にテストする.ただし,change_priorityとmutex_calc_priorityの内容には踏 み込まない. ●ミューテックスのテスト(6) 優先度上限ミューテックスに対して,タスクの終了時,タスクの優先順位の回 転時のミューテックス関連の処理を網羅的にテストする. ●ミューテックスのテスト(7) 優先度上限ミューテックスに対して,タスクの強制終了時のミューテックス関 連の処理を網羅的にテストする. ●ミューテックスのテスト(8) 優先度上限ミューテックスに対して,chg_priに伴うミューテックス関連の優先 度変更処理を網羅的にテストする.ただし,change_priorityと mutex_check_ceilpri,mutex_scan_ceilmtxの内容には踏み込まない. 以上 ********************************************************************** 採用されなかった検討 ********************************************************************** ○ミューテックス機能の修正仕様案 ミューテックス機能の仕様については,μITRON4.0仕様のミューテックス機能 をベースとするが,次の修正を加える. ・ミューテックス操作に伴いタスクの現在優先度が変化する場合には,同じ優  先度のタスクの中で最高優先順位となる. ★タスクが実行できる状態の場合に限るべきか 実行状態に限るとする案もある → 不採用 サービスコールの前後とも実行できる状態である場合に限る案もある → 採用 ★ミューテックスをロックしている場合に限られる (新たにロックする場合,これまでロックしていた場合も含む) ・chg_priでタスクのベース優先度を変更した場合で,ベース優先度を変更した  後の状態でミューテックス経由で優先度を継承していない場合に限り,同じ  優先度のタスクの中で最低優先順位となる.ミューテックス経由で優先度を  継承している場合にどうなるかは要検討(優先度が変わる時は最高優先順位,  変わらない場合はそのままとするのが妥当か). ★タスクが実行できる状態の場合に限るべきか → 採用 実行状態に限るとする案もある → 不採用 上の検討を受けて,次のように詳細化する. ・ミューテックス操作に伴いタスクの現在優先度が変化する場合の扱いは次の  通りとする.対象タスクがサービスコールの前後とも実行できる状態である  場合には,同じ優先度のタスクの中で最高優先順位となる.そうでない場合  には,同じ優先度のタスクの中で最低優先順位となる. ・chg_priでタスクのベース優先度を変更した場合の扱いは次の通りとする.対  象タスクが実行できる状態で,ベース優先度を変更した後の状態でミューテッ  クス経由でベース優先度と同じかそれより高い優先度を継承している場合に  は,現在優先度が変化するなら同じ優先度のタスクの中で最高優先順位とな  り,現在優先度が変化しないなら優先順位も変化しない.それ以外の場合に  は,同じ優先度のタスクの中で最低優先順位となる. 注)ミューテックス経由でベース優先度よりも低い優先度を継承する状況は, 優先度継承ミューテックスのみで起こり,優先度上限ミューテックスでは 起こらない.そのため,優先度継承ミューテックスをサポートしない場合 には,「ミューテックス経由でベース優先度と同じかそれより高い優先度 を継承している場合」は「優先度上限ミューテックスをロックしている場 合」と一致する. 【参考】 優先度継承処理は,本来は,優先度ではなく優先順位を継承すべきであるべき という意見があるが,現状の実装では優先順位を記憶していないため,実現が 難しいという問題がある. ○chg_priの機能記述(関連部分のみ) ---------------------------------------------------------------------- tskidで指定したタスク(対象タスク)のベース優先度を,tskpriで指定した優 先度に変更する.具体的な振舞いは以下の通り. 対象タスクが休止状態でない場合には,対象タスクのベース優先度が,tskpri で指定した優先度に変更される.それに伴って,対象タスクの現在優先度も変 更される. 対象タスクが実行できる状態の場合には,対象タスクの優先順位は次の通りと なる.変更後の現在優先度がミューテックス経由で優先度を継承していない場 合には,同じ優先度のタスクの中で最低優先順位となる.ミューテックス経由 で優先度を継承している場合には,現在優先度が変化するなら同じ優先度のタ スクの中で最高優先順位となり,現在優先度が変化しないなら優先順位も変化 しない. ここで,現在優先度がミューテックス経由で優先度を継承しているとは,対象 タスクがミューテックスをロックしていることにより,ベース優先度と同じか それより高い優先度を継承していることを言う.すなわち,次のいずれか(ま たは両方)の条件を満たす場合である.  ・対象タスクがロックしている優先度継承ミューテックスを,対象タスクの ベース優先度と同じかそれより高い優先度を持ったタスクが待っている.  ・対象タスクが優先度上限ミューテックスをロックしている(タスクがロッ クしている優先度上限ミューテックスの上限優先度は,必ず,そのタスク のベース優先度と同じかそれより高い). 対象タスクが待ち状態で,タスクの優先度順の待ち行列につながれている場合 には,対象タスクの変更後の現在優先度に従って,その待ち行列中での順序が 変更される.待ち行列中に同じ現在優先度のタスクがある場合には,対象タス クの順序はそれらの中で最後になる. ---------------------------------------------------------------------- ○参考:μITRON4.0仕様(4.02.00)におけるchg_pri ---------------------------------------------------------------------- このサービルコールを実行した結果,対象タスクの現在優先度が変化した場合 および現在優先度がベース優先度に一致している場合(ミューテックス機能を 使わない場合には,この条件は常に成り立つ)には,次の処理を行う.対象タ スクが実行できる状態である場合,タスクの優先順位を,変更後の優先度にし たがって変化させる.変更後の優先度と同じ優先度を持つタスクの間では,対 象タスクの優先順位を最低とする.対象タスクが何らかのタスク優先度順の待 ち行列につながれている場合にも,その待ち行列の中での順序を,変更後の優 先度にしたがって変化させる.変更後の優先度と同じ優先度を持つタスクの間 では,対象タスクを最後につなぐ. ---------------------------------------------------------------------- ○chg_priにおける優先順位変化に関する分析 (a) このサービスコールを実行した結果,対象タスクの現在優先度が変化した 場合および現在優先度がベース優先度に一致している場合 (a1)「現在優先度がベース優先度に一致」 ミューテックス経由で優先度を継承していない or ミューテックス経由で優先度を継承している優先度がベース優先度と 同じかそれより低い (a2) 対象タスクの現在優先度が変化した (a-) このサービスコールを実行した結果,対象タスクの現在優先度が変化せず, 現在優先度がベース優先度に一致していない場合 (a1-)「現在優先度がベース優先度に一致していない」 ミューテックス経由で,ベース優先度よりも高い優先度を継承している (a2-) 対象タスクの現在優先度が変化した ベース優先度が,chg_priの前後でどのように変化したかを,ミューテックス経 由で継承している最高優先度との比較で分類する.下の表で「高い」とは,ベー ス優先度が,ミューテックス経由で継承している最高優先度よりも高いことを 示す.また,「(変化あり)」とは,chg_priの前後でベース優先度の値が変わる ことを示す. 優先順位の変化 chg_pri前 chg_pri後 成立条件 実行できる状態 待ち状態 高い 高い(変化あり) (a1)(a2)(a) (b) 最低 最低 高い 高い(変化なし) (a1) (a) (b) 最低 最低 高い 同じ (a1)(a2)(a) 最低→最高 最低 高い 低い (a2)(a) 最低→最高 最低 同じ 高い (a1)(a2)(a) (b) 最低 最低 同じ 同じ(変化なし) (a1) (a) 最低→変化なし 最低→? 同じ 低い 変化なし 変化なし 低い 高い (a1)(a2)(a) (b) 最低 最低 低い 同じ (a1) (a) 最低→変化なし 最低→? 低い 低い(変化あり) 変化なし 変化なし 低い 低い(変化なし) 変化なし 変化なし (b) 変更後の現在優先度がミューテックス経由で優先度を継承していない場合 (b-) 変更後の現在優先度がミューテックス経由で優先度を継承している場合 ○検討過程のメモ ☆優先度上限にしぼって考える 優先度上限では,優先度が変化するのは,以下の状況. ・ミューテックスをロックしたとき 優先度が上がる(または,変わらない) → 指摘2の状況を考えると,同優先度内では最高優先順位であるべき ・ミューテックスをロック解除したとき 優先度が下がる(または,変わらない) → 他の優先度上限ミューテックスをロックしている場合には, 同優先度内では最高優先順位であるべき → そうでない場合には,どちらでも問題ないと思われるが, stack resource policy を実現するには,最高優先順位であるべき 課題:あるタスクがミューテックスをロック解除し,他のタスクがロックする時 上の2つが同時に起こる → 待ち状態から実行可能状態になる時は,最高優先順位である必要がない ロックを取得する「他のタスク」は最低優先順位とする 言い換えると, 他タスクにミューテックスをロックさせた時は,最低優先順位とする ・ミューテックスが初期化された時 ロックしていたタスクの優先度が下がる(または,変わらない) ・chg_priが発行された時 ミューテックスをロックしている時 ベース優先度を上げる時 ベース優先度が,ロックしているミューテックスの優先度上 限よりも高くなることはないため,ベース優先度を上げたこ とで,現在優先度の変更はない. ベース優先度を下げる時 それまでのベース優先度が,ロックしているミューテックス の優先度上限よりも高いことはないため,ベース優先度を下 げたことで,現在優先度の変更はない. → ロックしているミューテックスの優先度上限は,変更前後のベー ス優先度と同じかそれより高いため,現在優先度の変更はない. よって,優先順位は変更しないのが素直. ★優先度継承ミューテックスがあると成り立たなくなる. ミューテックスをロックしていない時は,通常の振る舞いと一致すべき つまり,最低優先順位とする ・タスクが終了した時・強制終了された時 ミューテックスをロックしていれば,ロック解除することになるが, タスクが終了してしまうので,優先順位は意味がなくなる ○実装に向けての仕様の詳細検討(古い) μITRON4.0仕様の厳密な優先度制御規則においては,タスクの現在優先度を, 常に,次の優先度の最高値に一致するように設定する. (1) タスクのベース優先度 (2) タスクがTA_INHERIT属性のミューテックスをロックしている場合,それら のミューテックスのロックを待っているタスクの中で,最も高い現在優先 度を持つタスクの現在優先度 (3) タスクがTA_CEILING属性のミューテックスをロックしている場合,それら のミューテックス中で,最も高い上限優先度を持つミューテックスの上限 優先度 これらの優先度を,ここでは,現在優先度を決定する要素となるという意味で, 要素優先度と呼ぶ. 修正仕様(A)により,(2)と(3)の要素優先度は,同優先度内の最高優先順位とみ なすことになる. また(2)において,TA_INHERIT属性のミューテックスの待ちキューはタスクの優 先度順であるため,最も高い現在優先度を持つタスクは,待ちキューの先頭の タスクである.つまり,(2)の要素優先度を求めるために,待ちキューをスキャ ンする必要はない. **********************************************************************