osタスクスケジューリング実現原理
4887 ワード
文書ディレクトリ
なぜタスクスケジュールを?
オペレーティングシステムの中で最も顕著な特性はタスクスケジューリングであり、タスクスケジューリングは主に以下のいくつかのニーズから来ている.
タスクのスケジュールには何が必要ですか?what
タスクスケジューリングが実際に行うのは、2つのタスクのコンテキスト切替(context)を実現することであり、あるいは、ある時点であるタスクのすべてのステータス情報を理解することができ、タスクスケジューリングが実際に行うのは、現在のタスクのステータスを保存し、切替するタスクのステータスを復元することであり、一般的に、1つのタスクのコンテキストには主に以下の部分がある.
タスクコンテキストに関する操作は、spポインタの切り替えなど、ハードウェアの特権モードで特定の命令を使用して実行する必要があるため、osは一般的にタスクスケジューリングのハンドルでアセンブリを使用して直接処理する.
タスクのスケジュールをどのように実現しますか?-how
異なるosのタスクスケジューリングの実現構想は基本的に一致しており、ここでは優れたタスク優先度プリエンプトをサポートするLiteosソースコードの例を用いて説明し、Liteosソースコードオープンソースはgithub上でダウンロードすることができる.
タスクのスケジューリングを開始すると、主に4つのステップに分けられます.
/* Find the highest task */
g_stLosTask.pstNewTask = LOS_DL_LIST_ENTRY(osPriqueueTop(), LOS_TASK_CB, stPendList);
/* In case that running is not highest then reschedule */
if (g_stLosTask.pstRunTask != g_stLosTask.pstNewTask) {
// do real schedual
osTaskSchedule();
//....
}
Liteosはタスクプリエンプトをサポートし、タスクキュー内の最も優先度の高いタスクを切り替え対象とします.
osTaskSchedule:
LDR R0, =OS_NVIC_INT_CTRL
LDR R1, =OS_NVIC_PENDSVSET
STR R1, [R0]
BX LR
osTaskScheduleはアセンブリに入り始め、特権モードに入る方法は特定のハードウェアプラットフォームに依存し、ここでarm-cotex-Mアーキテクチャを例に、NVIC_INT_CTRLレジスタセット、pendSVハンドルへの特定の割り込みをトリガー
TaskSwitch:
/**
* R0 = now stack pointer of the current running task.
*/
MRS R0, PSP
STMFD R0!, {R4-R12} /* save the core registers and PRIMASK. */
LDR R5, =g_stLosTask
MOV R8, #OS_TASK_STATUS_RUNNING
/**
* Save the stack pointer of the current running task to TCB.
* (g_stLosTask.pstRunTask->pStackPointer = R0)
*/
LDR R6, [R5]
STR R0, [R6]
/**
* Clear the RUNNING state of the current running task.
* (g_stLosTask.pstRunTask->usTaskStatus &= ~OS_TASK_STATUS_RUNNING)
*/
LDRH R7, [R6, #4]
BIC R7, R7, R8
STRH R7, [R6, #4]
/**
* Switch the current running task to the next running task.
* (g_stLosTask.pstRunTask = g_stLosTask.pstNewTask)
*/
LDR R0, [R5, #4]
STR R0, [R5]
上は現在のタスクcontexを保存するコアコードであり、
MRS R0, PSP
命令は現在のタスクspポインタを取得し、次のSTMFD命令によりr 4~r 12を現在のタスクスタックに保存し、次にグローバルosタスク制御ブロック情報を修正し、現在のタスク状態をrunningからreadyに切り替え、現在のタスク制御ブロックを次のタスクに切り替える注意arm-mアーキテクチャでは、割り込みに入ると、ハードウェアはr 0~r 3,r 12,Lr,pc,xpsrの8つのコアレジスタを自動的にタスクスタックに押し込み、割り込みから戻っても自動的にスタックに対応します
/**
* Set the RUNNING state of the next running task.
* (g_stLosTask.pstNewTask->usTaskStatus |= OS_TASK_STATUS_RUNNING)
*/
LDRH R7, [R0, #4]
ORR R7, R7, R8
STRH R7, [R0, #4]
/**
* Restore the stack pointer of the next running task from TCB.
* (R1 = g_stLosTask.pstNewTask->pStackPointer)
*/
LDR R1, [R0]
LDMFD R1!, {R4-R12} /* restore the core registers and PRIMASK. */
/**
* Set the stack pointer of the next running task to PSP.
*/
MSR PSP, R1
/**
* Restore the interruption state of the next running task.
*/
MSR PRIMASK, R12
BX LR
古いタスクフィールドの保存と同様に、最後に
MSR PSP, R1
命令を使用してタスクスタックポインタspを新しいタスクのスタックトップに切り、ジャンプ命令BXを使用して割り込みから戻り、一旦戻ると、すべてのフィールド情報が新しいタスクの前回割り込みスケジューリングの状態に戻り、PCポインタを含むと、次のマシンサイクルは新しいタスクの前回割り込みの場所から実行され続け、タスクスケジューリングが実現される【REF】
[ref 1]armアセンブリ命令セットマニュアル[ref 2]インラインアセンブリとアセンブリの2つの構文仕様(ATT/intel)