uC/OS-II源码分析(四)
内核结构
1, 临界区,OS_ENTER_CRITICAL和OS_EXIT_CRITICAL
为了处理临界区代码,必须关中断,等处理完毕后,再开中断。关中断可以避免其他任务或中断进入临界区代码。uC/OS-II定义了这两个宏来实现,但注意一条:调用uC/OS-II功能函数时,中断应该总是开着的。
1)当OS_CRITICAL_METHOD= = 1时,简单实现如下:
# define OS_EXIT_CRITICAL() enable_int()
但这样有一个问题,如果禁止中断的情况下调用uC/OS-II功能函数,那么从功能函数返回时,中断可能变成允许的了,而实际上还是希望是禁止的。
2)当OS_CRITICAL_METHOD= = 2时,实现如下:
asm(“PUSH PSW”);
asm(“DI”);
#define OS_EXIT_CRITICAL()
asm(“POP PSW”);
执行OS_ENTER_CRITICAL()时,先将中断状态保存到堆栈,然后关中断;执行OS_EXIT_CRITICAL()时,再从堆栈中恢复原来的中断开/关状态。这种方法不会改变中断状态,避免前面的问题。
3)当OS_CRITICAL_METHOD= = 3时,实现如下:
cpu_sr = get_processor_psw();
disable_interrupts();
#define OS_EXIT_CRITICAL()
set_ processor_psw(cpu_sr);
将处理器状态字保存在局部变量中。
2, 任务是一个无限循环,返回类型为void,参数void*,用于传数据给任务。任务可以调用OSTaskDel(OS_PRIO_SELF)进行自我删除。任务有5种状态:
1) 睡眠态。任务驻留在程序空间(ROM或RAM),还未交给uC/OS-II来管理。
2) 就绪态。OSTaskCreate()或OSTaskCreateExt()来创建一个任务后,就进入就绪态。任务可以调用OSTaskDel返回到睡眠态,或调用该函数让另一个任务进入睡眠态。
3) 运行态。OSStart()启动多任务运行。它只在启动时调用一次,运行就绪列表中优先级最高的任务。就绪的任务只有当所以优先级比其高的任务转为等待状态,或者是被删除了,才能进入运行态。
4) 等待状态。正在运行的任务可以调用OSTimeDly()或OSTimeDlyHMSM()将自身延迟一段时间进入等待状态,一直到延迟时间到来。这两个函数会强制执行任务切换,选择下一个优先级最高的任务运行。等待时间过去后,系统服务函数OSTimeTick()使延迟了的任务进入就绪态。
正在运行的任务也可能需要等待某一事件的发生,可以调用:OSFlagPend(),OSSemPend(),OSMutexPend(),OSMboxPend(),OSQPend()等函数。若某事件未发生,则任务进入等待状态,直到事件发生。当任务因等待事件被挂起时,下一个优先级最高的任务得到CPU。当事件发生了或超时,被挂起的任务进入就绪态。事件发生的报告可能来自另一个任务或中断服务子程序。
5) 中断服务态 。被中断的任务进入中断服务态,从而被挂起,中断服务子程序得到CPU,后者可能报告一个或多个事件发生,从而使一个或多个任务进入就绪态。因此从中断服务子程序返回前,uC/OS-II要判断被中断的任务的优先级和就绪列表中其他任务的优先级高低,选择最高的任务进入运行态。
6) 当所以任务都在等待事件发生或等待延迟的时间结束时,uC/OS-II运行OSTaskIdle()任务。
3, 任务控制块(OS_TCB)
建立一个任务时,一个OS_TCB就被赋值。当任务的CPU被剥夺时,用它来保存任务的状态,当任务重新得到CPU时,它也能保证任务从当时被中断的那一点继续执行。OS_TCB全部驻留在RAM中。
{
OS_STK *OSTCBStkPtr; /*指向当前任务堆栈栈顶的指针*/
#if OS_TASK_CREATE_EXT_EN > 0
void *OSTCBExtPtr; /* 指向用户定义的任务控制块扩展*/
OS_STK *OSTCBStkBottom; /* 指向栈底的指针*/
INT32U OSTCBStkSize; /* 栈中可容纳的元素数目(
uC/OS-II允许每个任务的堆栈容量任意,)*/
INT16U OSTCBOpt; /* 传给OSTaskCreateExt()的任务选择项*/
INT16U OSTCBId; /* Task ID (0..65535) */
#endif
struct os_tcb *OSTCBNext; /*TCB列表中指向下一个TCB的指针*/
struct os_tcb *OSTCBPrev; /* TCB列表中指向上一个TCB的指针*/
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0) || (OS_SEM_EN > 0) || (OS_MUTEX_EN > 0)
OS_EVENT *OSTCBEventPtr; /*指向事件控制块的指针*/
#endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
void *OSTCBMsg; /*指向传递给任务的消息的指针,消息来自OSMboxPost() or OSQPost() */
#endif
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
#if OS_TASK_DEL_EN > 0
OS_FLAG_NODE *OSTCBFlagNode; /*指向事件标志节点的指针*/
#endif
OS_FLAGS OSTCBFlagsRdy; /* 使任务进入就绪态的事件标志*/
#endif
INT16U OSTCBDly; /* 让任务延时若干节拍或把任务挂起一段时间等待某一事件发生时使用的计时变量*/
INT8U OSTCBStat; /* 任务状态*/
INT8U OSTCBPrio; /* 任务优先级(0 == highest, 63 == lowest)*/
//下面四个变量用于加速任务进入就绪态或进入等待事件发生状态的过程,算法比较巧妙
INT8U OSTCBX; /* Bit position in group corresponding to task priority (0..7) */
INT8U OSTCBY; /* Index into ready table corresponding to task priority
INT8U OSTCBBitX; /* Bit mask to access bit position in ready table
INT8U OSTCBBitY; /* Bit mask to access bit position in ready group
#if OS_TASK_DEL_EN > 0
BOOLEAN OSTCBDelReq; /* 表面任务是否需要删除自己*/
#endif
} OS_TCB;
uC/OS-II在通过OS_MAX_TASKS定义了最大的任务数目,这也决定了分配给用户程序的任务控制块OS_TCB的数目,但此外uC/OS-II还分配给系统任务OS_N_SYS_TASKS若干个额外的任务控制块,供其内部使用。uC/OS-II初始化时,所以任务控制块都被链接成单向空任务链表,任务一旦建立,空任务控制块指针OSTCBFreeList指向的任务控制块就赋给该任务,然后OSTCBFreeList调整为指向链表中下一个空任务控制块。一旦任务被删除,任务控制块被还给空任务链表。
任务建立时,OS_TCBInit()初始化任务控制块,函数OSTaskCreate()或OSTaskCreateExt()调用任务控制块初始化函数TCBInit。
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配内存*/
OS_CPU_SR cpu_sr;
#endif
OS_TCB *ptcb;
OS_ENTER_CRITICAL();
ptcb = OSTCBFreeList; /* 从空闲TCB链表中取一个空TCB*/
if (ptcb != (OS_TCB *)0)
{//取到了空TCB
OSTCBFreeList = ptcb->OSTCBNext; /* 更新空闲TCB链表头指针*/
OS_EXIT_CRITICAL();
ptcb->OSTCBStkPtr = ptos; /* 保存栈顶指针到TCB*/
ptcb->OSTCBPrio = (INT8U)prio; /* 保存任务优先级到TCB*/
ptcb->OSTCBStat = OS_STAT_RDY; /* 任务状态设置为就绪*/
ptcb->OSTCBDly = 0; /* 任务不延时等待*/
#if OS_TASK_CREATE_EXT_EN > 0//使用扩展
ptcb->OSTCBExtPtr = pext; /* 保存TCB扩展指针*/
ptcb->OSTCBStkSize = stk_size; /* 保存栈大小*/
ptcb->OSTCBStkBottom = pbos; /* 保存栈底*/
ptcb->OSTCBOpt = opt; /* 保存任务选择项*/
ptcb->OSTCBId = id; /*保存任务ID*/
#else//不使用扩展
pext = pext;
stk_size = stk_size;
pbos = pbos;
opt = opt;
id = id;
#endif
#if OS_TASK_DEL_EN > 0
ptcb->OSTCBDelReq = OS_NO_ERR; //初始化删除标志
#endif
ptcb->OSTCBY = prio >> 3; /* 预先计算X, Y, BitX and BitY*/
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = prio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
#if OS_EVENT_EN > 0
ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* 任务不等待任何事件发生*/
#endif
#if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) && (OS_TASK_DEL_EN > 0)
ptcb->OSTCBFlagNode = (OS_FLAG_NODE *)0; /* 任务不等待事件标志*/
#endif
#if (OS_MBOX_EN > 0) || ((OS_Q_EN > 0) && (OS_MAX_QS > 0))
ptcb->OSTCBMsg = (void *)0; /* 没有接收任何消息*/
#endif
#if OS_VERSION >= 204
OSTCBInitHook(ptcb);
#endif
OSTaskCreateHook(ptcb); /* 调用用户定义的钩子函数*/
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = ptcb;
ptcb->OSTCBNext = OSTCBList; /*将TCB插入已经建立任务的双向链表中*/
ptcb->OSTCBPrev = (OS_TCB *)0;
if (OSTCBList != (OS_TCB *)0) {
OSTCBList->OSTCBPrev = ptcb;
}
OSTCBList = ptcb;
OSRdyGrp |= ptcb->OSTCBBitY; /*让用户进入就绪态*/
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
OS_EXIT_CRITICAL();
return (OS_NO_MORE_TCB);
}
作者:洞庭散人
出处:http://phinecos.cnblogs.com/
uC/OS-II源码分析(四)的更多相关文章
- 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入
使用react全家桶制作博客后台管理系统 前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...
- ABP源码分析四:Configuration
核心模块的配置 Configuration是ABP中设计比较巧妙的地方.其通过AbpStartupConfiguration,Castle的依赖注入,Dictionary对象和扩展方法很巧妙的实现了配 ...
- ABP源码分析四十七:ABP中的异常处理
ABP 中异常处理的思路是很清晰的.一共五种类型的异常类. AbpInitializationException用于封装ABP初始化过程中出现的异常,只要抛出AbpInitializationExce ...
- docker 源码分析 四(基于1.8.2版本),Docker镜像的获取和存储
前段时间一直忙些其他事情,docker源码分析的事情耽搁了,今天接着写,上一章了解了docker client 和 docker daemon(会启动一个http server)是C/S的结构,cli ...
- ABP源码分析四十:ZERO的Application和Tenant
ABP的Zero模块以数据库为数据源实现了ABP框架中的tenant management (multi-tenancy), role management, user management, ses ...
- ABP源码分析四十一:ZERO的Audit,Setting,Background Job
AuditLog: 继承自Entity<long>的实体类.封装AuditLog的信息. AuditingStore: 实现了IAuditingStore接口,实现了将AuditLog的信 ...
- ABP源码分析四十二:ZERO的身份认证
ABP Zero模块通过自定义实现Asp.Net Identity完成身份认证功能, 对Asp.Net Identity做了较大幅度的扩展.同时重写了ABP核心模块中的permission功能,以实现 ...
- ABP源码分析四十三:ZERO的本地化
ABP Zero模块扩展了ABP基础框架中的本地化功能,实现了通过数据库管理本地化的功能.其通过数据库保存本地化语言及其资源. ApplicationLanguage:代表本地化语言的实体类.一种语言 ...
- ABP源码分析四十四:ZERO的配置
ABP Zero模块中需要配置的地方主要集中在三块:配置静态的role,配置外部认证源,以及配置本地化语言和资源. UserManagementConfig/IUserManagementConfig ...
- ABP源码分析四十五:ABP ZERO中的EntityFramework模块
AbpZeroDbContext:配置ABP.Zero中定义的entity的Dbset EntityFrameworkModelBuilderExtensions:给PrimitiveProperty ...
随机推荐
- Chrome自带恐龙小游戏的源码研究(七)
在上一篇<Chrome自带恐龙小游戏的源码研究(六)>中研究了恐龙的跳跃过程,这一篇研究恐龙与障碍物之间的碰撞检测. 碰撞盒子 游戏中采用的是矩形(非旋转矩形)碰撞.这类碰撞优点是计算比较 ...
- 基于Python的安卓图形锁破解程序
安卓手机的图形锁是3x3的点阵,按次序连接数个点从而达到锁定/解锁的功能.最少需要连接4个点,最多能连接9个点.网上也有暴力删除手机图形锁的方法,即直接干掉图形锁功能.但假如你想进入别人的手机,但又不 ...
- xml 操作
/////////////////////////////////jaxp对xml文档进行解析/////////////////////////////////////////// 要操作的xml文件 ...
- Codeforces 309C Memory for Arrays 二进制模拟进位
题目链接:点击打开链接 题意: 给定n个箱子m个物品 以下n个数字表示箱子的容量 以下m个数字b1-bm 表示物品体积为2^bi大 问最多有多少个物品能够放入箱子. 思路: 贪心,先放小的,小的不能放 ...
- coreos 之flannel
提要: coreos 中 flannel 工具是coreos 网络划分工具.通过flannel 划分子网并向etcd 注册网络信息.可以做到宿主机集群中容器间网络通信. 1. 启动etcd2 服务: ...
- javascript onclick中post提交
对post提交进行封装: function post(URL, PARAMS) { var temp = document.createElement("form"); temp. ...
- wpf 获取datagrid 模板列中的控件
目前采用的 方法 (网上提供的一款) public static DataGridRow GetRow(DataGrid datagrid, int columnIndex) { ...
- yii2学习笔记
之前看过Yii2框架,也在其他框架实现其Gii手脚架功能,现在开始使用Yii做项目,顺便记录一下学习笔记 先推荐一个网址 Yii2速查表(中文版)http://nai8.me/tool-sc.html ...
- 【BZOJ4408】[Fjoi 2016]神秘数 主席树神题
[BZOJ4408][Fjoi 2016]神秘数 Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13},1 = 12 = 1 ...
- EasyPlayer播放海康大华RTSP流时RTSPClient客户端连接兼容问题的解决
在之前的博客<EasyPlayer RTSP播放器对RTSP播放地址url的通用兼容修改意见>中,我描述了遇到的一个客户在播放大华某款摄像机时地址不兼容的问题,这不,团队刚刚参考我的这个意 ...