LiteOS-任务篇-源码分析-任务调度函数
2020-10-13 09:32
155 查看
目录调度上层源码分析 LOS_Schedule函数源码分析 辅助参考代码 LiteOS中断向量表(二次命名版) 参考
设置如图,触发 PendSV 中断
恢复 R12和LR
指令 CBZ
语句
小端模式:低编号寄存器对应低地址
压栈:先压 LR,PS -= 4
压栈:再压 R12,PS -= 4
压栈:先出 R12,PS += 4
压栈:再压 LR,PS += 4
更新当前运行任务栈 g_stLosTask.pstRunTask.pStackPointer 指针
更新当前任务状态,取消 OS_TASK_STATUS_RUNNING 运行态
再取消 OS_TASK_STATUS_RUNNING 运行态
最后再赋值回
更新当前运行任务变量
更新准备运行的任务的状态,更新运行态 OS_TASK_STATUS_RUNNING (注:此时
准备运行的任务手动出栈
更新准备运行的任务的 PSP 值
恢复原有的中断状态
返回到上层函数中,如
否
解锁中断
任务控制块
前言
- 20201012
- LiteOS 2018
- 建议先瞄一眼 辅助参考代码 章节
笔录草稿
核心源码分析
- 这里主要分析系统调度的汇编部分,也是调度的底层核心部分。
osTaskSchedule函数源码分析
- osTaskSchedule 源码 ( 位于文件 los_dispatch_keil.S 中 )
往寄存器 OS_NVIC_INT_CTRL 中写入 OS_NVIC_PENDSVSET 值
OS_NVIC_INT_CTRL 为 Interrupt Control State Register,该寄存器可配置内容如下 set a pending Non-Maskable Interrupt (NMI) - set or clear a pending SVC
- set or clear a pending SysTick
- check for pending exceptions
- check the vector number of the highest priority pended exception
- check the vector number of the active exception.
退出 osTaskSchedule 函数,即是返回上层函数
osTaskSchedule LDR R0, =OS_NVIC_INT_CTRL LDR R1, =OS_NVIC_PENDSVSET STR R1, [R0] BX LR
- OS_NVIC_INT_CTRL 定义 ( 位于文件 los_hwi.h 中 )
/** * @ingroup los_hwi * Interrupt control and status register. */ #define OS_NVIC_INT_CTRL 0xE000ED04
- OS_NVIC_INT_CTRL 定义 ( 位于文件 los_dispatch_keil.S 中 )
OS_NVIC_PENDSVSET EQU 0x10000000
osPendSV函数源码分析
- PendSV 中断的回调函数就是
void osPendSV(void);
- osPendSV 源码 ( 位于文件 los_dispatch_keil.S 中 ) 读取 PRIMASK 的值到 R12 中,即是保存中断状态
- 屏蔽全局中断
- 判断是否调用 TaskSwitch 函数 如果宏 LOSCFG_BASE_CORE_TSK_MONITOR 为 NO,则运行 TaskSwitch 函数
- 如果宏 LOSCFG_BASE_CORE_TSK_MONITOR 为 YES,则在下面运行 osTaskSwitchCheck 函数 压栈保护寄存器 R12和LR
- 运行 R2 函数,也就是 osTaskSwitchCheck 函数
源码解析路径:
LOS_KernelInit() --> osTaskMonInit() --> g_pfnTskSwitchHook = osTaskSwitchCheck;
- 读者可以自己追踪一下
osPendSV MRS R12, PRIMASK CPSID I LDR R2, =g_pfnTskSwitchHook ; C: R2 = &g_pfnTskSwitchHook; LDR R2, [R2] ; C: R2 = *R2; ==》 R2 = g_pfnTskSwitchHook; CBZ R2, TaskSwitch ; C: if(g_pfnTskSwitchHook == 0) TaskSwitch(); PUSH {R12, LR} ; 将 R12 和 LR 寄存器压栈 BLX R2 ; 跳到 R2 POP {R12, LR} ; 出栈到寄存器 R12 和 LR
- PRIMASK 说明 这是个只有单一比特的寄存器
- 被置 1 后,就关掉所有可屏蔽的异常,只剩下 NMI 和 硬fault 可以响应
- 缺省值是0,表示没有关中断。
-
比较 为 0 则跳转,如:
CBZ x1,fun; 表示如果 x1 为 0,则跳转到 fun。
PUSH 3687 {R12, LR}和
POP {R12, LR}(个人理解,望指正)
-
{} 内先排序,根据寄存器 PS 的走向排序,最终目标是,下面那点
PUSH {R12, LR}顺序:LR R12
PUSH {R12, LR}
-
顺序:R12 LR
TaskSwitch函数源码分析
- 如果用户没有开启任务堆栈监测,即宏 LOSCFG_BASE_CORE_TSK_MONITOR 配置为 NO,就运行本函数。
- PSP 更新给 R0
- 手动把 R4-R12 压栈 R0-R3,R12,LR,PC,xPSR 这些寄存器已经自动压栈了
-
先获取当前任务的状态寄存器
g_stLosTask.pstRunTask.usTaskStatus
*g_stLosTask.pstRunTask= *g_stLosTask.pstNewTask;
*g_stLosTask.pstRunTask和
*g_stLosTask.pstNewTask是一样的,指向同一个任务)
osSchedule或
LOS_Schedule函数中
TaskSwitch MRS R0, PSP ;// R0 = PSP; STMFD R0!, {R4-R12} ;// 手动压栈,先减再压,小端,且栈往下生长 LDR R5, =g_stLosTask ;// R5 = g_stLosTask; ==> R5 = g_stLosTask.pstRunTask; LDR R6, [R5] ;// R6 = *(g_stLosTask.pstRunTask); ==> R6 = g_stLosTask.pstRunTask.pStackPointer; STR R0, [R6] ;// *(g_stLosTask.pstRunTask.pStackPointer) = R0; LDRH R7, [R6 , #4] ;// R7 = *(&(g_stLosTask.pstRunTask.usTaskStatus)); ==> R7 = g_stLosTask.pstRunTask.usTaskStatus; MOV R8,#OS_TASK_STATUS_RUNNING ;// R8 = OS_TASK_STATUS_RUNNING; BIC R7, R7, R8 ;// R7 &= ~R8; STRH R7, [R6 , #4] ;// g_stLosTask.pstRunTask.usTaskStatus = R7; LDR R0, =g_stLosTask ;// R0 = g_stLosTask; ==> R0 = g_stLosTask.pstRunTask; LDR R0, [R0, #4] ;// R0 = *(g_stLosTask.pstNewTask); ==> R0 = g_stLosTask.pstNewTask.pStackPointer; STR R0, [R5] ;// g_stLosTask.pstRunTask.pStackPointer = g_stLosTask.pstNewTask.pStackPointer; ==> *g_stLosTask.pstRunTask= *g_stLosTask.pstNewTask; LDRH R7, [R0 , #4] ;// R7 = *(&(g_stLosTask.pstNewTask.usTaskStatus)); ==> R7 = g_stLosTask.pstNewTask.usTaskStatus; MOV R8, #OS_TASK_STATUS_RUNNING ;// R8 = OS_TASK_STATUS_RUNNING; ORR R7, R7, R8 ;// R7 |= R8; STRH R7, [R0 , #4] ;// g_stLosTask.pstNewTask.usTaskStatus = R7; LDR R1, [R0] ;// R1 = *(g_stLosTask.pstNewTask.pStackPointer); LDMFD R1!, {R4-R12} ;// 手动出栈,先出栈后增,小端,且栈往上生长 MSR PSP, R1 ;// PSP = R1; // 更新 PSP 值 MSR PRIMASK, R12 ;// 恢复原有的中断状态 BX LR ;// 返回到上层函数中,如 `osSchedule` 或 `LOS_Schedule` 函数中 ALIGN END
调度上层源码分析
osSchedule函数源码分析
- osSchedule 函数多用于创建任务函数和删除任务函数。
/***************************************************************************** Function : osSchedule Description : task scheduling Input : None Output : None Return : None *****************************************************************************/ LITE_OS_SEC_TEXT VOID osSchedule(VOID) { osTaskSchedule(); }
LOS_Schedule函数源码分析
- LOS_Schedule 函数为系统常用的调度函数。
- 简单流程 锁中断
- 从就绪列表中获取最合适的任务,赋值给 g_stLosTask.pstNewTask ,为下一个运行的任务
- 判断当前运行的任务和就绪列表中最适合的任务是否为同一个任务 是 判断是否锁任务调度 是
- 否 解锁中断
- 进行调度操作:
osTaskSchedule();
return
;
/***************************************************************************** Function : LOS_Schedule Description : Function to determine whether task scheduling is required Input : None Output : None Return : None *****************************************************************************/ LITE_OS_SEC_TEXT VOID LOS_Schedule(VOID) { UINTPTR uvIntSave; uvIntSave = LOS_IntLock(); // 锁中断 /* Find the highest task */ g_stLosTask.pstNewTask = LOS_DL_LIST_ENTRY(osPriqueueTop(), LOS_TASK_CB, stPendList); // 从就绪列表中获取最合适的任务,赋值给 g_stLosTask.pstNewTask ,为下一个运行的任务 /* In case that running is not highest then reschedule */ if (g_stLosTask.pstRunTask != g_stLosTask.pstNewTask) // 不是同一个任务就进行调度准备 { if ((!g_usLosTaskLock)) // 判断是否锁任务了 { (VOID)LOS_IntRestore(uvIntSave); // 解锁中断 osTaskSchedule(); // 调度操作 return; // 返回 } } (VOID)LOS_IntRestore(uvIntSave); // 解锁中断 }
辅助参考代码
任务控制块 LOS_TASK_CB
源码参考
- 上述代码分析理解时需要了解这个结构体布局。
/** * @ingroup los_task * Define the task control block structure. */ typedef struct tagTaskCB { VOID *pStackPointer; /**< Task stack pointer */ UINT16 usTaskStatus; UINT16 usPriority; UINT32 uwStackSize; /**< Task stack size */ UINT32 uwTopOfStack; /**< Task stack top */ UINT32 uwTaskID; /**< Task ID */ TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function */ VOID *pTaskSem; /**< Task-held semaphore */ VOID *pTaskMux; /**< Task-held mutex */ UINT32 uwArg; /**< Parameter */ CHAR *pcTaskName; /**< Task name */ LOS_DL_LIST stPendList; LOS_DL_LIST stTimerList; UINT32 uwIdxRollNum; EVENT_CB_S uwEvent; UINT32 uwEventMask; /**< Event mask */ UINT32 uwEventMode; /**< Event mode */ VOID *puwMsg; /**< Memory allocated to queues */ } LOS_TASK_CB;
LiteOS中断向量表(二次命名版)
- 中断向量表源码 (位于文件 los_hwi.c 中)
HWI_PROC_FUNC m_pstHwiForm[OS_VECTOR_CNT] = { (HWI_PROC_FUNC)0, // [0] Top of Stack (HWI_PROC_FUNC)Reset_Handler, // [1] reset (HWI_PROC_FUNC)osHwiDefaultHandler, // [2] NMI Handler (HWI_PROC_FUNC)osHwiDefaultHandler, // [3] Hard Fault Handler (HWI_PROC_FUNC)osHwiDefaultHandler, // [4] MPU Fault Handler (HWI_PROC_FUNC)osHwiDefaultHandler, // [5] Bus Fault Handler (HWI_PROC_FUNC)osHwiDefaultHandler, // [6] Usage Fault Handler (HWI_PROC_FUNC)0, // [7] Reserved (HWI_PROC_FUNC)0, // [8] Reserved (HWI_PROC_FUNC)0, // [9] Reserved (HWI_PROC_FUNC)0, // [10] Reserved (HWI_PROC_FUNC)osHwiDefaultHandler, // [11] SVCall Handler (HWI_PROC_FUNC)osHwiDefaultHandler, // [12] Debug Monitor Handler (HWI_PROC_FUNC)0, // [13] Reserved (HWI_PROC_FUNC)osPendSV, // [14] PendSV Handler (HWI_PROC_FUNC)osHwiDefaultHandler, // [15] SysTick Handler };
参考
链接
- LiteOS源码链接
- 常见问题
- 华为开发者社区
- 华为LiteOS官方教程
- 我的源码 包含 裸机源码
- LiteOS 工程模板
- 其它关于 LiteOS 的 demo 及 note
相关文章推荐
- Yarn源码分析之MapReduce作业中任务Task调度整体流程(一)
- spark[源码]-任务调度源码分析[三]
- Quartz任务调度源码分析
- 【Spark篇】---Spark中资源和任务调度源码分析与资源配置参数应用
- 学习笔记---分布式调度之xxlJob的调度任务源码分析
- ucos-II 任务调度源码分析(三)
- zeppelin源码分析(4)——interpreter的调度和任务封装
- ucos-II 任务调度源码分析(二)
- Hadoop调度源码分析 任务调度阶段
- Spark1.3从创建到提交:3)任务调度初始化源码分析
- ucos-II 任务调度源码分析(一)
- Linux-0.11内核源码分析系列:进程调度sleep_on()函数分析
- Java定时任务调度工具详解(2)— Timer 函数的综合应用
- FFMPEG源码分析:avformat_open_input()(媒体打开函数)
- MapReduce的MapTask任务的运行源码级分析
- Spark1.6.3 Driver端 task调度源码分析
- Spark源码分析之Master资源调度算法原理
- Linux-0.11内核源码分析系列:内存管理copy_page_tables()函数分析
- Kubernetes 1.8抢占式调度Preemption源码分析
- ThreadPoolExecutor源码分析(二):任务提交主逻辑execute()