ucos实时操作系统学习笔记——内核结构和任务创建
对于ucos实时操作系统,邵贝贝的那本书已经写得很详细了,我因为之前不深的研究过ucos,所以在这里做一个笔记,写一些个人对该操作系统的理解,仅仅是个人理解,如果有人看到这边随笔有不对的地方,望给我指正。同时,锻炼一下自己组织语言的能力,有时候知道那么个意思,却总也说不出口。
ucos内种中有几个人变量比较重要,被贯穿在ucos内核的设计中。这几个变量中有在PCB中的局部变量,也有在整个系统内核设计中的全局变量。下面将分别介绍一下这几个变量。
首先,从OS_PCB中的局部变量讲起,如果去掉OS_TASK_CREATE_EXT_EN,OS_EVENT_EN等一些可选项的参数,ucos的OS_TCB结构体中主要的变量主要是这几个(简化OS_PCB结构体如下):
typedef struct os_pcb{
OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */ struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */
struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */ INT32U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */
INT8U OSTCBStat; /* Task status */
INT8U OSTCBStatPend; /* Task PEND status */
INT8U OSTCBPrio; /* Task priority (0 == highest) */ INT8U OSTCBX; /* Bit position in group corresponding to task priority */
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
OS_PRIO OSTCBBitX; /* Bit mask to access bit position in ready table */
OS_PRIO OSTCBBitY; /* Bit mask to access bit position in ready group */
}OS_TCB;
从简化的的OS_PCB结构可看出其结构非常简单,主要包括以上几个部分:栈指针,当前任务所处TCB list的位置,描述任务delay的tick时间,任务状态,任务优先级以及计算当前任务position的四个变量。前面几个变量看一下注释应该可以很容易理解,最后四个变量需要稍作介绍,这也是整个内核结构中比较重要的部分。
接下来介绍一下几个关联比较密切的局部和全局变量,局部变量包括OS_PCB中的OSTCBX, OSTCBY, OSTCBBitX, OSTCBBitY,全局变量包括OSUnMapTbl, OSPrioHighRdy, OSRdyGrp, OSRdyTbl。
在OSTaskCreate的OS_TCBInit函数中有如下一段代码,可以从中看到创建任务的优先级和OS_PCB中四个局部变量的关系。操作系统根据任务优先级把任务分为不同的group,OSTCBY变量中存放的就是group的信息,每个group中有多少个任务则放在OSTCBX中。需要说明的是在ucos的内核设计过程中,通过宏定义将操作系统的可以创建的任务个数(OS_LOWEST_PRIO)分为64和256。在OS_LOWEST_PRIO是64的时候,会将任务分为8个group,每个group中最多会有8个任务,在如下代码中优先级<=63时,prio的最大值是63所以prio最大有6位,可以看到group和每个group任务的个数;在OS_LOWEST_PRIO是256的时候,会将任务分为16个group,每个group最多有16个任务。
通过全局变量OSRdyGrp来记录有属于哪个group的任务处于ready状态等待执行,为了降低操作系统内存的使用,通过Bit位代表每一个group并存储在OSRdyGrp中。OSRdyTbl则是代表属于哪个group中有多少个任务处于ready状态。为了更好的计算,每个操作系统在创建之初会提前计算好自己Bit位值,如下程序中OSTCBBITY和OSTCBBitX(OS_PRIO是根据OS_LOWEST_PRIO来计算定义的)。
#if OS_LOWEST_PRIO <= 63u /* Pre-compute X, Y */
ptcb->OSTCBY = (INT8U)(prio >> 3u);
ptcb->OSTCBX = (INT8U)(prio & 0x07u);
#else /* Pre-compute X, Y */
ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0xFFu);
ptcb->OSTCBX = (INT8U) (prio & 0x0Fu);
#endif
/* Pre-compute BitX and BitY */
ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
上面介绍的几个全局变量中还有两个OSUnMapTbl, OSPrioHighRdy。OSUnMapTbl是一个匹配数组,数组中存放的是每个index值化成2进制,数值是1的bit位的位置是多少。当输入任务处于ready状态的group值时,可以得到那个group值最小;同理,当输入每个group中任务table时,可以得到这个group中优先级数据最小的任务,当然优先级数值越小代表优先级越高,从而通过取到的值经过计算得到优先级的数值。下面代码很好的诠释了OSPrioHighRdy这个是如何计算的。对于当OS_LOWEST_PRIO是256时,计算会复杂一些,当任务group或者table在8-16这个范围,会通过移位计算,因为OSUnMapTbl是按照8位一组设计的数组。
static void OS_SchedNew (void)
{
#if OS_LOWEST_PRIO <= 63 /* See if we support up to 64 tasks */
INT8U y; y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << ) + OSUnMapTbl[OSRdyTbl[y]]);
#else /* We support up to 256 tasks */
INT8U y;
INT16U *ptbl; if ((OSRdyGrp & 0xFF) != ) {
y = OSUnMapTbl[OSRdyGrp & 0xFF];
} else {
y = OSUnMapTbl[(OSRdyGrp >> ) & 0xFF] + ;
}
ptbl = &OSRdyTbl[y];
if ((*ptbl & 0xFF) != ) {
OSPrioHighRdy = (INT8U)((y << ) + OSUnMapTbl[(*ptbl & 0xFF)]);
} else {
OSPrioHighRdy = (INT8U)((y << ) + OSUnMapTbl[(*ptbl >> ) & 0xFF] + );
}
#endif
}
其次,介绍一下内核中几个比较重要的全局变量,如下所示:
OS_EXT OS_TCB *OSTCBCur; /* Pointer to currently running TCB */
OS_EXT OS_TCB *OSTCBFreeList; /* Pointer to list of free TCBs */
OS_EXT OS_TCB *OSTCBHighRdy; /* Pointer to highest priority TCB R-to-R */
OS_EXT OS_TCB *OSTCBList; /* Pointer to doubly linked list of TCBs */
OS_EXT OS_TCB *OSTCBPrioTbl[OS_LOWEST_PRIO + ];/* Table of pointers to created TCBs */
OS_EXT OS_TCB OSTCBTbl[OS_MAX_TASKS + OS_N_SYS_TASKS]; /* Table of TCBs
1. OSTCBCur是一个OS_TCB类型的指针,指向当前正在运行的任务的TCB的地址;
2. OSTCBFreeList是一个指向没有使用的TCB列表的地址的指针;
3. OSTCBHighRdy指向当前处于当前处于ready状态的最高优先级的任务TCB地址的指针;
4. OSTCBList指向TCB列表的地址的指针;
5. OSTCBPrioTbl中存储的是对应优先级创建任务的TCB的地址,对于每一个优先级来说,当值是(OS_TCB *)1时,表示当前优先级reservd,当值时(OS_TCB *)0时,表示当前优先级可用;
6. OSTCBTbl是提前为每个优先级分配的TCB Table的内存。
再次,讲一下任务的创建,将通过简化代码,讲一下代码设计内容,此内容为个人理解,语言有可能"个人味"比较重,可以看一下邵老师对这块的分析。简化代码如下:
INT8U OSTaskCreate (void (*task)(void *p_arg),
void *p_arg,
OS_STK *ptos,
INT8U prio)
{
OS_STK *psp;
INT8U err;
OS_ENTER_CRITICAL();
if (OSIntNesting > 0u) { /* Make sure we don't create the task from within an ISR */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_CREATE_ISR);
}
if (OSTCBPrioTbl[prio] == (OS_TCB *)) { /* Make sure task doesn't already exist at this priority */
OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/* Reserve the priority to prevent others from doing ... */
/* ... the same thing until task is created. */
OS_EXIT_CRITICAL();
psp = OSTaskStkInit(task, p_arg, ptos, 0u); /* Initialize the task's stack */
err = OS_TCBInit(prio, psp, (OS_STK *), 0u, 0u, (void *), 0u);
if (err == OS_ERR_NONE) {
if (OSRunning == OS_TRUE) { /* Find highest priority task if multitasking has started */
OS_Sched();
}
} else {
OS_ENTER_CRITICAL();
OSTCBPrioTbl[prio] = (OS_TCB *);/* Make this priority available to others */
OS_EXIT_CRITICAL();
}
return (err);
}
OS_EXIT_CRITICAL();
return (OS_ERR_PRIO_EXIST);
}
上面已经说过,OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()是成对存在的。任务创建时,会判断当前是否在中断中创建任务,如果是则会开中断,返回一个错误;然后判断当前优先级TCB是否被占用(if (OSTCBPrioTbl[prio] == (OS_TCB *)0) ),如果被占用,则开中断,返回优先级存在错误码;如果没有被占用,则设置当前任务的TCB table为reserved状态,说明当前任务优先级不能再被分配给其他任务,然后开中断;之后,会设置当前任务的堆栈地址和大小,用于切换任务时状态的保存和恢复;然后是对分配得到的TCB进行初始化,对TCB进行初始配置,简化参数主要包括上面提到OS_TCB中的参数配置,在对TCB初始化时,返回OS_ERR_NONE时,说明创建任务成功,这时候会重新进行最高优先级的选择,任务调度OS_Send(任务调度其实就是选择最高优先级的任务,然后将堆栈指针中的数据替换掉然后保存原来的CPU寄存器的过程),如果创建TCB初始化错误即任务创建错误,则会将分配的TCB释放掉,函数返回err。当前函数的临界区开关中断函数成对出现,当进入到子函数时,其实也是成对出现,关系比较清楚。
任务创建相对简单,将代码中一些可选的功能去掉后,代码就变得很简单清楚,需要什么功能,添加什么功能分析,会比较调条理,如果整体的去分析解读会显得比较乱,不利于梳理。
,
ucos实时操作系统学习笔记——内核结构和任务创建的更多相关文章
- ucos实时操作系统学习笔记——操作系统在STM32的移植
使用ucos实时操作系统是在上学的时候,导师科研项目中.那时候就是网上找到操作系统移植教程以及应用教程依葫芦画瓢,功能实现也就罢了,没有很深入的去研究过这个东西.后来工作了,闲来无聊就研究了一下这个只 ...
- ucos实时操作系统学习笔记——任务间通信(信号量)
ucos实时操作系统的任务间通信有好多种,本人主要学习了sem, mutex, queue, messagebox这四种.系统内核代码中,这几种任务间通信机制的实现机制相似,接下来记录一下本人对核心代 ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
- ucos实时操作系统学习笔记——任务间通信(队列)
ucos操作系统中的queue机制同样使用了event机制来实现,其实和前面的sem,mutex实现类似,所不同的是对sem而言,任务想获得信号量,对mutex而言,任务想获得的是互斥锁.任务间通信的 ...
- ucos实时操作系统学习笔记——任务间通信(互斥锁)
想讲一下ucos任务间通信中的mutex,感觉其设计挺巧妙,同sem一样使用的是event机制实现的,代码不每一行都分析,因为讲的没邵贝贝老师清楚,主要讲一下mutex的内核是如何实现的.可以理解互斥 ...
- RTX51 Tiny实时操作系统学习笔记—初识RTX51 Tiny
一,RTX51 Tiny简单介绍 RTX51 Tiny是一种实时操作系统(RTOS),能够用它来建立多个任务(函数)同一时候运行的应用(从宏观上看是同一时候运行的,但从微观上看,还是独立运行的 ...
- 操作系统学习笔记5 | 用户级线程 && 内核级线程
在上一部分中,我们了解到操作系统实现多进程图像需要组织.切换.考虑进程之间的影响,组织就是用PCB的队列实现,用到了一些简单的数据结构知识.而本部分重点就是进程之间的切换. 参考资料: 课程:哈工大操 ...
- 操作系统学习笔记----进程/线程模型----Coursera课程笔记
操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...
- 深挖计算机基础:趣谈Linux操作系统学习笔记
参考极客时间专栏<趣谈Linux操作系统>学习笔记 核心原理篇:内存管理 趣谈Linux操作系统学习笔记:第二十讲 趣谈Linux操作系统学习笔记:第二十一讲 趣谈Linux操作系统学习笔 ...
随机推荐
- 避免重复造轮子的UI自动化测试框架开发
一懒起来就好久没更新文章了,其实懒也还是因为忙,今年上半年的加班赶上了去年一年的加班,加班不息啊,好了吐槽完就写写一直打算继续的自动化开发 目前各种UI测试框架层出不穷,但是万变不离其宗,驱动PC浏览 ...
- SSH实战 · 唯唯乐购项目(下)
后台模块 一:后台用户模块 引入后台管理页面 创建adminuser表: CREATE TABLE `adminuser` ( `uid` int(11) NOT NULL AUTO_INCREM ...
- Eclipse中启动tomcat报错java.lang.OutOfMemoryError: PermGen space的解决方法
有的项目引用了太多的jar包,或者反射生成了太多的类,异或有太多的常量池,就有可能会报java.lang.OutOfMemoryError: PermGen space的错误, 我们知道可以通过jvm ...
- 立即执行函数表达式(IIFE)
原文地址:benalman.com/news/2010/11/immediately-invoked-function-expression/ 译者:nzbin 也许你还没有注意到,我是一个对术语比较 ...
- nginx源码分析之网络初始化
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
- JS继承类相关试题
题目一: //有关于原型继承的代码如下:function Person(name) { this.name = name;}Person.prototype = { getName : f ...
- Android—Service与Activity的交互
service-Android的四大组件之一.人称"后台服务"指其本身的运行并不依赖于用户可视的UI界面 实际开发中我们经常需要service和activity之间可以相互传递数据 ...
- 设置WindowServer2012 时间同步NTP
在powershell中以管理员身份运行以下命令即可 w32tm /config /manualpeerlist:pool.ntp.org /syncfromflags:MANUAL Stop-Ser ...
- JS or C#?不存在的脚本之争
前言: 又来到了周末,小匹夫也终于有了喘口气写写博客的时间和精力.话说周五的下午,小匹夫偶然间晃了一眼蛮牛的QQ群,又看到了一个Unity3D开发中老生长谈的问题,“我的开发语言究竟是选择JavaSc ...
- Lesson 17 Always young
Text My aunt Jennifer is an actress. She must be at least thirty-five years old. In spit of this, sh ...