μC/OS-III---I笔记11---就绪任务列表管理
就绪优先级为映像响表
在UCOSIII内,任务调度是要先找到优先级最高的任务,然后执行。理论上对于UCOSIII可以有无数个优先级,每个优先级又可以有无数个任务但是对于这么多的任务如何快速查到到当先就绪的最高优先级的任务是那个,为了完成这个功能ucos的设计了就绪优先级为映像响表组合任务就绪表来实现这个功能。对于32位的CPU就绪优先级为映像响表的数据结构如下:
|
位 数组元素 |
31 |
30 |
29 |
...... |
2 |
1 |
0 |
|
OSPrioTbl[0] |
优先级0 |
优先级1 |
优先级2 |
... |
优先级29 |
优先级30 |
优先级31 |
|
OSPrioTbl[1] |
优先级32 |
33 |
34 |
... |
61 |
62 |
63 |
|
OSPrioTbl[2] |
... |
... |
... |
... |
... |
... |
... |
|
...... |
... |
... |
... |
... |
... |
... |
... |
|
OSPrioTbl[n] |
... |
... |
... |
... |
... |
... |
... |
相关的函数有查找就绪优先级为映像响表中最高的优先级:
OS_PRIO OS_PrioGetHighest (void)
{
CPU_DATA *p_tbl;
OS_PRIO prio; prio = (OS_PRIO)0;
p_tbl = &OSPrioTbl[0];
while (*p_tbl == (CPU_DATA)0) { /* Search the bitmap table for the highest priority */
prio += DEF_INT_CPU_NBR_BITS; /* Compute the step of each CPU_DATA entry */
p_tbl++;
}
prio += (OS_PRIO)CPU_CntLeadZeros(*p_tbl); /* Find the position of the first bit set at the entry */
return (prio);
}
这里因为STM32提供了计算前导零的指令所以程序中直接调用了汇编函数CPU_CntLeadZeros来计算前导零,对于不支持这个指令的CPU程序中也给出了C计算前导零的函数.
CPU_CntLeadZeros
CLZ R0, R0 ; Count leading zeros
BX LR
C计算前导零(32bit)的函数.
#if (CPU_CFG_DATA_SIZE_MAX >= CPU_WORD_SIZE_32)
CPU_DATA CPU_CntLeadZeros32 (CPU_INT32U val)
{
#if (!((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \
(CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32)))
CPU_DATA ix;
#endif
CPU_DATA nbr_lead_zeros; /* ---------- ASM-OPTIMIZED ----------- */
#if ((defined(CPU_CFG_LEAD_ZEROS_ASM_PRESENT)) && \
(CPU_CFG_DATA_SIZE >= CPU_WORD_SIZE_32))
nbr_lead_zeros = CPU_CntLeadZeros((CPU_DATA)val);
nbr_lead_zeros -= (CPU_CFG_DATA_SIZE - CPU_WORD_SIZE_32) * DEF_OCTET_NBR_BITS; #else /* ----------- C-OPTIMIZED ------------ */
if (val > 0x0000FFFFu) {
if (val > 0x00FFFFFFu) { /* Chk bits [31:24] : */
/* .. Nbr lead zeros = .. */
ix = (CPU_DATA)(val >> 24u); /* .. lookup tbl ix = 'val' >> 24 bits */
nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 0u); /* .. plus nbr msb lead zeros = 0 bits.*/ } else { /* Chk bits [23:16] : */
/* .. Nbr lead zeros = .. */
ix = (CPU_DATA)(val >> 16u); /* .. lookup tbl ix = 'val' >> 16 bits */
nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 8u); /* .. plus nbr msb lead zeros = 8 bits.*/
} } else {
if (val > 0x000000FFu) { /* Chk bits [15:08] : */
/* .. Nbr lead zeros = .. */
ix = (CPU_DATA)(val >> 8u); /* .. lookup tbl ix = 'val' >> 8 bits */
nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 16u); /* .. plus nbr msb lead zeros = 16 bits.*/ } else { /* Chk bits [07:00] : */
/* .. Nbr lead zeros = .. */
ix = (CPU_DATA)(val >> 0u); /* .. lookup tbl ix = 'val' >> 0 bits */
nbr_lead_zeros = (CPU_DATA)(CPU_CntLeadZerosTbl[ix] + 24u); /* .. plus nbr msb lead zeros = 24 bits.*/
}
}
#endif return (nbr_lead_zeros);
}
#endif
CPU_CntLeadZeros32 ()
同样8,16,64,位的都是相同的原理。
置位表中某个优先级处于就绪
void OS_PrioInsert (OS_PRIO prio)
{
CPU_DATA bit;
CPU_DATA bit_nbr;
OS_PRIO ix; ix = prio / DEF_INT_CPU_NBR_BITS;
bit_nbr = (CPU_DATA)prio & (DEF_INT_CPU_NBR_BITS - 1u);
bit = 1u;
bit <<= (DEF_INT_CPU_NBR_BITS - 1u) - bit_nbr;
OSPrioTbl[ix] |= bit;
}
表中某个优先级处于就绪位清零:
void OS_PrioRemove (OS_PRIO prio)
{
CPU_DATA bit;
CPU_DATA bit_nbr;
OS_PRIO ix; ix = prio / DEF_INT_CPU_NBR_BITS;
bit_nbr = (CPU_DATA)prio & (DEF_INT_CPU_NBR_BITS - 1u);
bit = 1u;
bit <<= (DEF_INT_CPU_NBR_BITS - 1u) - bit_nbr;
OSPrioTbl[ix] &= ~bit;
}
系统巧妙地设计了就绪优先级位映像表数据结构就是为了能够快速的查找到就绪列表中最高的优先级任务,同时搭配就绪列表就可以方便管理任务的调用了。
任务就绪列表
这是一个用来管理UCOS内就绪任务的列表,系统定义了一个数组OSRdyList[OS_CFG_PRIO_MAX],每个优先级对应其中一个元素,反过来说就是一个元素管理同一个优先级下的所有任务,OSRdyList的数据结构如图,很简单HeadPtr指向优先级上的第一个任务控制块,TailPtr指向最后一个,NbrEnries记录任务及上有多少任务。任务控制块里的NextPtr和PrePtr相互之间串成一个双向链表。如图:

初始化任务就绪表函数其实就是对OSRdyList[]每个结构体进行0值初始化。
使任务就绪函数其中OS_PrioInsert是将就绪优先级为映像响表对应位置1的操作。OS_RdyListInsertTail是将任务插入同优先级的就绪表的末尾,OS_RdyListInsertHead为插入开头,OS_RdyListMoveHeadToTail是将同优先级的任务的开头的任务移到末尾的操作,在时间轮片调度处调用。
void OS_RdyListInsert (OS_TCB *p_tcb)
{
OS_PrioInsert(p_tcb->Prio);
if (p_tcb->Prio == OSPrioCur) { /* Are we readying a task at the same prio? */
OS_RdyListInsertTail(p_tcb); /* Yes, insert readied task at the end of the list */
} else {
OS_RdyListInsertHead(p_tcb); /* No, insert readied task at the beginning of the list */
}
最后看到OSStart()函数内的一段代码就知道,系统内核是如何调度一个高优先级的任务开始运行的。
if (OSRunning == OS_STATE_OS_STOPPED) {
OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority */
OSPrioCur = OSPrioHighRdy;
OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
OSTCBCurPtr = OSTCBHighRdyPtr;
OSRunning = OS_STATE_OS_RUNNING;
OSStartHighRdy(); /* Execute target specific code to start task */
*p_err = OS_ERR_FATAL_RETURN; /* OSStart() is not supposed to return */
其中OSStartHighRdy()为一个汇编函数是任务管理相关的函数,就知道他的功能就是开始当前最高优先级的任务的运行就可以。
OSStartHighRdy
LDR R0, =NVIC_SYSPRI14 ; Set the PendSV exception priority
LDR R1, =NVIC_PENDSV_PRI
STRB R1, [R0] MOVS R0, #0 ; Set the PSP to 0 for initial context switch call
MSR PSP, R0 LDR R0, =OS_CPU_ExceptStkBase ; Initialize the MSP to the OS_CPU_ExceptStkBase
LDR R1, [R0]
MSR MSP, R1 LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch)
LDR R1, =NVIC_PENDSVSET
STR R1, [R0] CPSIE I ; Enable interrupts at processor level OSStartHang
B OSStartHang ; Should never get here
OSStartHighRdy
任务轮片调度:
在创建任务时设置任务轮片的时间节拍数,当任务执行到一定的时钟节拍后就会将任务同优先级的任务进行调度运行,这个函数在系统时钟的中断函数里有调用。
void OSTimeTick (void)
{
OS_ERR err;
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
CPU_TS ts;
#endif OSTimeTickHook(); /* Call user definable hook */ #if OS_CFG_ISR_POST_DEFERRED_EN > 0u ts = OS_TS_GET(); /* Get timestamp */
OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK, /* Post to ISR queue */
(void *)&OSRdyList[OSPrioCur],
(void *) 0,
(OS_MSG_SIZE) 0u,
(OS_FLAGS ) 0u,
(OS_OPT ) 0u,
(CPU_TS ) ts,
(OS_ERR *)&err); #else (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB, /* Signal tick task */
(OS_OPT ) OS_OPT_POST_NONE,
(OS_ERR *)&err); #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
#endif
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
void OS_SchedRoundRobin (OS_RDY_LIST *p_rdy_list)
{
OS_TCB *p_tcb;
CPU_SR_ALLOC(); if (OSSchedRoundRobinEn != DEF_TRUE) { /* Make sure round-robin has been enabled */
return;
} CPU_CRITICAL_ENTER();
p_tcb = p_rdy_list->HeadPtr; /* Decrement time quanta counter */ if (p_tcb == (OS_TCB *)0) {
CPU_CRITICAL_EXIT();
return;
} if (p_tcb == &OSIdleTaskTCB) {
CPU_CRITICAL_EXIT();
return;
} if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
p_tcb->TimeQuantaCtr--;
} if (p_tcb->TimeQuantaCtr > (OS_TICK)0) { /* Task not done with its time quanta */
CPU_CRITICAL_EXIT();
return;
} if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) { /* See if it's time to time slice current task */
CPU_CRITICAL_EXIT(); /* ... only if multiple tasks at same priority */
return;
} if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't round-robin if the scheduler is locked */
CPU_CRITICAL_EXIT();
return;
} OS_RdyListMoveHeadToTail(p_rdy_list); /* Move current OS_TCB to the end of the list */
p_tcb = p_rdy_list->HeadPtr; /* Point to new OS_TCB at head of the list */
if (p_tcb->TimeQuanta == (OS_TICK)0) { /* See if we need to use the default time slice */
p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
} else {
p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* Load time slice counter with new time */
}
CPU_CRITICAL_EXIT();
}
OS_SchedRoundRobin ()
轮片调度就是将同一优先级就绪列表的的任务从头到尾的轮换执行。
μC/OS-III---I笔记11---就绪任务列表管理的更多相关文章
- Python3+Selenium3+webdriver学习笔记11(cookie处理)
#!/usr/bin/env python# -*- coding:utf-8 -*-'''Selenium3+webdriver学习笔记11(cookie处理)'''from selenium im ...
- 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析
前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...
- Ext.Net学习笔记11:Ext.Net GridPanel的用法
Ext.Net学习笔记11:Ext.Net GridPanel的用法 GridPanel是用来显示数据的表格,与ASP.NET中的GridView类似. GridPanel用法 直接看代码: < ...
- SQL反模式学习笔记11 限定列的有效值
目标:限定列的有效值,将一列的有效字段值约束在一个固定的集合中.类似于数据字典. 反模式:在列定义上指定可选值 1. 对某一列定义一个检查约束项,这个约束不允许往列中插入或者更新任何会导致约束失败的值 ...
- uc/os iii移植到STM32F4---IAR开发环境
也许是先入为主的原因,时钟用不惯Keil环境,大多数的教程都是拿keil写的,尝试将官方的uc/os iii 移植到IAR环境. 1.首先尝试从官网上下载的官方移植的代码,编译通过,但是执行会报堆栈溢 ...
- JAVA自学笔记11
JAVA自学笔记11 1:Eclipse的安装 2:用Eclipse写一个HelloWorld案例,最终在控制台输出你的名字 A:创建项目 B:在src目录下创建包.cn.itcast C:在cn.i ...
- 基于μC/OS—III的CC1120驱动程序设计
基于μC/OS—III的CC1120驱动程序设计 时间:2014-01-21 来源:电子设计工程 作者:张绍游,张贻雄,石江宏 关键字:CC1120 嵌入式操作系统 STM32F103ZE ...
- golang学习笔记11 golang要用jetbrain的golang这个IDE工具开发才好
golang学习笔记11 golang要用jetbrain的golang这个IDE工具开发才好 jetbrain家的全套ide都很好用,一定要dark背景风格才装B 从File-->s ...
- Spring MVC 学习笔记11 —— 后端返回json格式数据
Spring MVC 学习笔记11 -- 后端返回json格式数据 我们常常听说json数据,首先,什么是json数据,总结起来,有以下几点: 1. JSON的全称是"JavaScript ...
随机推荐
- 微信登录1-OAuth2简介
一.OAuth2解决什么问题 1.开放系统间授权 照片拥有者想要在云冲印服务上打印照片,云冲印服务需要访问云存储服务上的资源 2.图例 资源拥有者:照片拥有者 客户应用:云冲印 受保护的资源:照片 3 ...
- Hmailserver搭建邮箱服务器
由于阿里云,谷歌云,腾讯云等服务器都不开放25端口和pop3端口,想要使用邮箱服务得购买他们的企业邮箱,但是对于个人而言比较贵. 所以我们需要利用家庭宽带申请公网IP. 首先打电话给运营商客服,申请动 ...
- 风险识别系统-大数据智能风控管理平台-企业风控解决方案– 阿里云 https://www.aliyun.com/product/saf
风险识别系统-大数据智能风控管理平台-企业风控解决方案– 阿里云 https://www.aliyun.com/product/saf
- webmvc 拦截器 允许跨域 跨域问题 sessionid不一样
package cn.com.yitong.ares.filter; import java.io.IOException; import javax.servlet.Filter;import ja ...
- 语言反射规则 - The Laws of Reflection
[译]Go反射的三个原则(官方博客) | seven的分享 https://sevenyu.top/2019/12/21/laws-of-reflection.html wilhg/The-Laws- ...
- 从epoll构建muduo-1 mini-muduo介绍
https://blog.csdn.net/voidccc/article/details/8719752 ========== https://blog.csdn.net/liangzhao_jay ...
- 洛谷P4981
Description 给定 n 个点,组成一棵树,有多少种组合方法: Analysis 首先,结合题目简化意义和这句话 最多可能存在多少种父子关系 我们可以知道当且仅当有至少一个节点的儿子不同时称他 ...
- docker基本使用-常用命令
一. 常用命令 #查看docker服务 docker ps #启动docker服务 systemctl start docker #查看本地镜像 docker images #删除本地镜像 docke ...
- 如何使用Conda源快速安装PyTorch?
数据科学交流群,群号:189158789,欢迎各位对数据科学感兴趣的小伙伴的加入! 1.切换国内源 1.1.在家目录生成.condarc conda config --set show_channel ...
- 如何在windows下切换node版本
安装nvm 最近的项目中,一个是用vue项目开发,一个是使用react开发,但是ant design pro使用了umi框架,所需要的node版本>10.0.0,vue那个项目中又不兼容node ...