1 /* 2 ************************************************************************************************* 3 * uC/OS-II实时控制内核 4 * 主要的包含文件 5 * 任务管理 6 * 7 * 文 件: OS_TASK.C 任务管理代码 8 * 作 者: Jean J. Labrosse 9 * 中文注解: 钟常慰 zhongcw @ 126.com 整理:lin-credible 译注版本:1.0 请尊重原版内容 10 ************************************************************************************************* 11 */ 12 13 #ifndef OS_MASTER_FILE //是否已经定义OS_MASTER_FILE 14 #include "includes.h" //包含"includes.h"文件 15 #endif //结束定义 16 17 /* 18 ************************************************************************************************* 19 * 改变一个任务的优先级(CHANGE PRIORITY OF A TASK) 20 * 21 * 描述: 改变一个任务的优先级。 22 * 23 * 参数: oldp 是任务原先的优先级。 24 * 25 * newp 是任务的新优先级。 26 * 27 * 返回: OS_NO_ERR 任务优先级成功改变。 28 * OS_PRIO_INVALID 参数中的任务原先优先级或新优先级大于或等于OS_LOWEST_PRIO。 29 * (i.e. >= OS_LOWEST_PRIO) 30 * OS_PRIO_EXIST 优先级为PIP的任务已经存在; 31 * OS_PRIO_ERR 参数中的任务原先优先级不存在。 32 * 33 * 注意: 参数中的新优先级必须是没有使用过的,否则会返回错误码.在OSTaskChangePrio()中还会先 34 * 判断要改变优先级的任务是否存在。 35 * 36 ************************************************************************************************* 37 */ 38 39 #if OS_TASK_CHANGE_PRIO_EN > 0 //允许生成OSTaskChangePrio()函数 40 INT8U OSTaskChangePrio (INT8U oldprio, INT8U newprio) 41 { //改变一个任务的优先级(任务旧的优先级、任务新的优先级) 42 #if OS_CRITICAL_METHOD == 3 //允许生成OSTaskCreate()函数 43 OS_CPU_SR cpu_sr; 44 #endif 45 46 #if OS_EVENT_EN > 0 //消息事件是否 > 0 47 OS_EVENT *pevent; //定义事件指针 48 #endif 49 50 OS_TCB *ptcb; //定义消息事件的任务控制块指针 51 INT8U x; //优先级低3位值 52 INT8U y; //优先级高3位值 53 INT8U bitx; //优先级低3位值计算对应值 54 INT8U bity; //优先级高3位值计算索引值 55 56 57 58 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 59 //当旧任务 >= 最低优先级 并且 旧任务不是本身 并且新任务>= 最低优先级 60 if ((oldprio >= OS_LOWEST_PRIO && oldprio != OS_PRIO_SELF) || 61 newprio >= OS_LOWEST_PRIO) { 62 return (OS_PRIO_INVALID); //参数中的任务原先优先级或新优先级大于或等于OS_LOWEST_PRIO 63 } 64 #endif 65 OS_ENTER_CRITICAL(); //关闭中断 66 if (OSTCBPrioTbl[newprio] != (OS_TCB *)0) { //确认新任务优先级未被使用,即就绪态为0 67 OS_EXIT_CRITICAL(); //打开中断 68 return (OS_PRIO_EXIST); //返回新任务(优先级为PIP的任务已经存在) 69 } else { 70 OSTCBPrioTbl[newprio] = (OS_TCB *)1; //新任务优先级未被使用,保留它(为1) 71 OS_EXIT_CRITICAL(); //打开中断 72 //预先计算新任务优先级任务控制块OS_TCB的某些值 73 y = newprio >> 3; //保留优先级高3位(3-5位) 74 bity = OSMapTbl[y]; //计算索引值 75 x = newprio & 0x07; //保存优先级低3位(0-2位) 76 bitx = OSMapTbl[x]; //计算对应值 77 OS_ENTER_CRITICAL(); //关闭中断 78 if (oldprio == OS_PRIO_SELF) { //要改变的是否使旧任务本身 79 oldprio = OSTCBCur->OSTCBPrio; //如果是(正在运行的优先级(旧任务本身的优先级))钟常慰 80 } 81 if ((ptcb = OSTCBPrioTbl[oldprio]) != (OS_TCB *)0) { //变更的旧任务必须存在(1即就绪) 82 OSTCBPrioTbl[oldprio] = (OS_TCB *)0; //旧任务就绪态去除它(为0) 83 if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { 84 //如果该任务处于就绪态,那么必须在当前的优先级下,从就绪表中移除该任务,然后在新 85 //的优先级下,将该任务插入到就绪表中。 86 if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) { 87 OSRdyGrp &= ~ptcb->OSTCBBitY; 88 } 89 OSRdyGrp |= bity; //利用预先计算值将任务插入到就绪表中 90 OSRdyTbl[y] |= bitx; 91 #if OS_EVENT_EN > 0 //消息事件是否 > 0 92 } else { //(任务未就绪)否则,拾取任务事件指针 93 if ((pevent = ptcb->OSTCBEventPtr) != (OS_EVENT *)0) { //任务事件表为1(有消息) 94 //如果任务正在等待某一事件的发生,该函数必须将任务从事件控制块的等待列表中删除 95 //并在新的优先级下将事件插入到等待队列中。任务也可能正在等待延时时间到,或是被 96 //挂起。 97 if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { 98 pevent->OSEventGrp &= ~ptcb->OSTCBBitY; 99 } 100 pevent->OSEventGrp |= bity; //将任务插入到等待列表中 101 pevent->OSEventTbl[y] |= bitx; 102 } 103 #endif 104 } 105 OSTCBPrioTbl[newprio] = ptcb; //将任务的OS_TCB的指针存到新任务OSTCBPrioTbl[] 106 ptcb->OSTCBPrio = newprio; //设定新的任务优先级,并保存原有计算值 107 ptcb->OSTCBY = y; //高3位计算值 108 ptcb->OSTCBX = x; //低3位计算值 109 ptcb->OSTCBBitY = bity; 110 ptcb->OSTCBBitX = bitx; 111 OS_EXIT_CRITICAL(); //打开中断 112 OS_Sched(); //任务调度,最高任务优先级运行 113 return (OS_NO_ERR); //任务优先级成功改变 114 } else { //否则 115 OSTCBPrioTbl[newprio] = (OS_TCB *)0; //新任务就绪态去除它(为0不存在), 116 OS_EXIT_CRITICAL(); //打开中断 117 return (OS_PRIO_ERR); //返回(参数中的任务原先优先级不存在) 118 } 119 } 120 } 121 #endif 122 /*$PAGE*/ 123 /* 124 ************************************************************************************************* 125 * 建立一个新任务(CREATE A TASK) 126 * 127 * 描述: 建立一个新任务。任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立.中断 128 * 处理程序中不能建立任务.一个任务必须为无限循环结构(如下所示),且不能有返回点。 129 * OSTaskCreate()是为与先前的μC/OS版本保持兼容,新增的特性在OSTaskCreateExt()函数中. 130 * 无论用户程序中是否产生中断,在初始化任务堆栈时,堆栈的结构必须与CPU中断后寄存器入栈的 131 * 顺序结构相同.详细说明请参考所用处理器的手册。 132 * 133 * 参数: task 是指向任务代码的指针。 134 * 135 * pdata 指向一个数据结构,该结构用来在建立任务时向任务传递参数。下例中说明uC/OS中的任 136 * 务结构以及如何传递参数pdata: 137 * void Task (void *pdata) 138 * { 139 * ... // 对参数'pdata'进行操作 140 * for (;;) { // 任务函数体. 141 * ... 142 * ... 143 * // 在任务体中必须调用如下函数之一: 144 * // OSMboxPend() 用于任务等待消息,消息通过中断或另外的任务发送给需要的任务 145 * // OSFlgPend() 用于任务等待事件标志中的事件标志 146 * // OSMutexPend() 任务需要独占资源 147 * // OSQPend() 用于任务等待消息 148 * // OSSemPend() 用于任务试图取得共享资源的使用权,任务需要与其它任务或中断 149 * 同步及任务需要等待特定事件的发生场合 150 * // OSTimeDly() 任务延时若干时钟节拍 151 * // OSTimeDlyHMSM() 任务延时若干时间 152 * // OSTaskSuspend() 挂起任务本身 153 * // OSTaskDel() 删除任务本身 154 * ... 155 * ... 156 * } 157 * ptos 为指向任务堆栈栈顶的指针。任务堆栈用来保存局部变量,函数参数,返回地址以及任务被 158 * 中断时的CPU寄存器内容.任务堆栈的大小决定于任务的需要及预计的中断嵌套层数。计算 159 * 堆栈的大小,需要知道任务的局部变量所占的空间,可能产生嵌套调用的函数,及中断嵌套 160 * 所需空间。如果初始化常量OS_STK_GROWTH设为1,堆栈被设为从内存高地址向低地址增长, 161 * 此时ptos应该指向任务堆栈空间的最高地址。反之,如果OS_STK_GROWTH设为0,堆栈将从内 162 * 存的低地址向高地址增长。 163 * 164 * prio 为任务的优先级。每个任务必须有一个唯一的优先级作为标识。数字越小,优先级越高。 165 * 166 * 返回: OS_NO_ERR 函数调用成功; 167 * OS_PRIO_EXIT 具有该优先级的任务已经存在; 168 * OS_PRIO_INVALID 参数指定的优先级大于OS_LOWEST_PRIO; (i.e. >= OS_LOWEST_PRIO) 169 * OS_NO_MORE_TCB 系统中没有OS_TCB可以分配给任务了。 170 * 171 * 注意: 1、任务堆栈必须声明为OS_STK类型。 172 * 2、在任务中必须调用uC/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待信 173 * 号量,消息邮箱、消息队列),以使其他任务得到CPU。 174 * 3、用户程序中不能使用优先级0,1,2,3,以及OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, 175 * OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。这些优先级μC/OS系统保留,其余的56个优先级提供给 176 * 应用程序。 177 ************************************************************************************************* 178 */ 179 180 #if OS_TASK_CREATE_EN > 0 //允许生成OSTaskCreate()函数 181 INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) 182 { //建立任务(任务代码指针、传递参数指针、分配任务堆栈栈顶指针、任务优先级) 183 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 184 OS_CPU_SR cpu_sr; 185 #endif 186 OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针 187 INT8U err; //定义(获得并定义初始化任务控制块)是否成功 188 189 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 190 if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法 191 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO 192 } 193 #endif 194 OS_ENTER_CRITICAL(); //关闭中断 195 if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0 196 OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为0 197 198 OS_EXIT_CRITICAL(); //打开中断 199 psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); //初始化任务堆栈 200 err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); //获得并初始化任务控制块 201 if (err == OS_NO_ERR) { //任务控制初始化成功 202 OS_ENTER_CRITICAL(); //关闭中断 203 OSTaskCtr++; //任务计数器加1 204 OS_EXIT_CRITICAL(); //打开中断 205 if (OSRunning == TRUE) { //检查是否有(某个)任务在运行 206 OS_Sched(); //任务调度,最高任务优先级运行 207 } 208 } else { //否则,任务初始化失败 209 OS_ENTER_CRITICAL(); //关闭中断 210 OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0 211 OS_EXIT_CRITICAL(); //打开中断 212 } 213 return (err); //返回(获得并定义初始化任务控制块是否成功) 214 } 215 OS_EXIT_CRITICAL(); //打开中断 216 return (OS_PRIO_EXIST); //返回(具有该优先级的任务已经存在) 217 } 218 #endif 219 /*$PAGE*/ 220 /* 221 ************************************************************************************************* 222 * CREATE A TASK (Extended Version) 223 * 224 * 描述: 建立一个新任务。与OSTaskCreate()不同的是,OSTaskCreateExt()允许用户设置更多的细节 225 * 内容.任务的建立可以在多任务环境启动之前,也可以在正在运行的任务中建立,但中断处理 226 * 程序中不能建立新任务。一个任务必须为无限循环结构(如下所示),且不能有返回点。 227 * 228 * 参数: task 是指向任务代码的指针。 229 * 230 * pdata Pdata指针指向一个数据结构,该结构用来在建立任务时向任务传递参数。下例中说 231 * 232 * 为了避免在编译中出现"参数未使用"的警告信息,可以写一句pdata= pdata;) 233 * void Task (void *pdata) 234 * { 235 * ... //对参数pdata进行操作,例如pdata= pdata 236 * for (;;) { // 任务函数体.总是为无限循环结构 237 * ... 238 * ... 239 * // 任务中必须调用如下的函数: 240 * // OSMboxPend() 用于任务等待消息,消息通过中断或另外的任务发送给需要的任务 241 * // OSFlgPend() 用于任务等待事件标志中的事件标志 242 * // OSMutexPend() 任务需要独占资源 243 * // OSQPend() 用于任务等待消息 244 * // OSSemPend() 用于任务试图取得共享资源的使用权,任务需要与其它任务或中断 245 * 同步及任务需要等待特定事件的发生场合 246 * // OSTimeDly() 任务延时若干时钟节拍 247 * // OSTimeDlyHMSM() 任务延时若干时间 248 * // OSTaskSuspend() 挂起任务本身 249 * // OSTaskDel() 删除任务本身 250 * ... 251 * ... 252 * } 253 * } 254 * ptos 为指向任务堆栈栈顶的指针.任务堆栈用来保存局部变量,函数参数,返回地址以及中 255 * 断时的CPU寄存器内容.任务堆栈的大小决定于任务的需要及预计的中断嵌套层数.计 256 * 算堆栈的大小,需要知道任务的局部变量所占的空间,可能产生嵌套调用的函数,及 257 * 中断嵌套所需空间.如果初始化常量OS_STK_GROWTH设为1,堆栈被设为向低端增长 258 * (从内存高地址向低地址增长).此时ptos应该指向任务堆栈空间的最高地址.反之, 259 * 如果OS_STK_GROWTH设为0,堆栈将从低地址向高地址增长. 260 * 261 * prio 任务的优先级。每个任务必须有一个唯一的优先级作为标识.数字越小,优先级越高。 262 * 263 * id 是任务的标识,目前这个参数没有实际的用途,但保留在OSTaskCreateExt()中供今后 264 * 扩展,应用程序中可设置id与优先级相同.(0..65535) 265 * 266 * pbos 为指向堆栈底端的指针。如果初始化常量OS_STK_GROWTH设为1,堆栈被设为从内存高 267 * 地址向低地址增长.此时pbos应该指向任务堆栈空间的最低地址.反之,如果 268 * OS_STK_GROWTH设为0,堆栈将从低地址向高地址增长。pbos应该指向堆栈空间的最高 269 * 地址.参数pbos用于堆栈检测函数OSTaskStkChk(). 270 * 271 * stk_size 指定任务堆栈的大小。其单位由OS_STK定义:当OS_STK的类型定义为INT8U、INT16U、 272 * INT32U的时候, stk_size的单位为分别为字节(8位)、字(16位)和双字(32位)。 273 * 274 * pext 是一个用户定义数据结构的指针,可作为TCB的扩展。例如,当任务切换时,用户定义 275 * 的数据结构中可存放浮点寄存器的数值,任务运行时间,任务切入次数等等信息。 276 * 277 * opt 存放与任务相关的操作信息。opt的低8位由uC/OS保留,用户不能使用。用户可以使用 278 * opt的高8位。每一种操作由opt中的一位或几位指定,当相应的位被置位时,表示选择 279 * 某种操作。当前的μC/OS版本支持下列操作: 280 * OS_TASK_OPT_STK_CHK:决定是否进行任务堆栈检查; 281 * OS_TASK_OPT_STK_CLR:决定是否清空堆栈; 282 * OS_TASK_OPT_SAVE_FP:决定是否保存浮点寄存器的数值。此项操作仅当处理器有浮 283 * 点硬件时有效。保存操作由硬件相关的代码完成。 284 * 285 * 286 * 返回: OS_NO_ERR:函数调用成功; 287 * OS_PRIO_EXIST:具有该优先级的任务已经存在; 288 * OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO; 289 * OS_NO_MORE_TCB:系统中没有OS_TCB可以分配给任务了. 290 * 291 * 注意: 1、任务堆栈必须声明为OS_STK类型; 292 * 2、在任务中必须进行uC/OS提供的下述过程之一:延时等待、任务挂起、等待事件发生(等待 293 * 信号量,消息邮箱、消息队列),以使其他任务得到CPU; 294 * 3、用户程序中不能使用优先级0,1,2,3,以及OS_LOWEST_PRIO-3, OS_LOWEST_PRIO-2, 295 * OS_LOWEST_PRIO-1, OS_LOWEST_PRIO。这些优先级μC/OS系统保留,其余56个优先级提供给 296 * 应用程序. 297 ************************************************************************************************* 298 */ 299 /*$PAGE*/ 300 #if OS_TASK_CREATE_EXT_EN > 0 //允许生成OSTaskCreateExt()函数 301 INT8U OSTaskCreateExt (void (*task)(void *pd), //建立扩展任务(任务代码指针 302 void *pdata, //传递参数指针 303 OS_STK *ptos, //分配任务堆栈栈顶指针 304 INT8U prio, //分配任务优先级 305 INT16U id, //(未来的)优先级标识(与优先级相同) 306 OS_STK *pbos, //分配任务堆栈栈底指针 307 INT32U stk_size, //指定堆栈的容量(检验用) 308 void *pext, //指向用户附加的数据域的指针 309 INT16U opt) //建立任务设定选项) 310 { 311 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 312 OS_CPU_SR cpu_sr; 313 #endif 314 OS_STK *psp; //初始化任务堆栈指针变量,返回新的栈顶指针 315 INT8U err; //定义(获得并定义初始化任务控制块)是否成功 316 317 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 318 if (prio > OS_LOWEST_PRIO) { //检查任务优先级是否合法 319 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO 320 } 321 #endif 322 OS_ENTER_CRITICAL(); //关闭中断 323 if (OSTCBPrioTbl[prio] == (OS_TCB *)0) { //确认优先级未被使用,即就绪态为0 324 OSTCBPrioTbl[prio] = (OS_TCB *)1; //保留这个优先级,将就绪态设为0 325 326 OS_EXIT_CRITICAL(); //打开中断 327 //以下两为1堆栈才能清0 328 if (((opt & OS_TASK_OPT_STK_CHK) != 0x0000) || //检验任务堆栈,CHK=1 329 ((opt & OS_TASK_OPT_STK_CLR) != 0x0000)) { //任务建立时是否清0,CLR=1 330 #if OS_STK_GROWTH == 1 //堆栈生长方向 331 (void)memset(pbos, 0, stk_size * sizeof(OS_STK)); //从下向上递增 332 #else 333 (void)memset(ptos, 0, stk_size * sizeof(OS_STK)); //从上向下递减 334 #endif 335 } 336 337 psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, opt); //初始化任务堆栈 338 err = OS_TCBInit(prio, psp, pbos, id, stk_size, pext, opt); //获得并初始化任务控制块 339 if (err == OS_NO_ERR) { //任务控制初始化成功 340 OS_ENTER_CRITICAL(); //关闭中断 341 OSTaskCtr++; //任务计数器加1 342 OS_EXIT_CRITICAL(); //打开中断 343 if (OSRunning == TRUE) { //检查是否有(某个)任务在运行 344 OS_Sched(); //任务调度,最高任务优先级运行 345 } 346 } else { //否则,任务初始化失败 347 OS_ENTER_CRITICAL(); //关闭中断 348 OSTCBPrioTbl[prio] = (OS_TCB *)0; //放弃任务,设此任务就绪态为0 349 OS_EXIT_CRITICAL(); //打开中断 350 } 351 return (err); //返回(获得并定义初始化任务控制块是否成功) 352 } 353 OS_EXIT_CRITICAL(); //打开中断 354 return (OS_PRIO_EXIST); //具有该优先级的任务已经存在 355 } 356 #endif 357 /*$PAGE*/ 358 /* 359 ************************************************************************************************* 360 * 删除一个指定优先级的任务(DELETE A TASK) 361 * 362 * 描述: 删除一个指定优先级的任务。任务可以传递自己的优先级给OSTaskDel(),从而删除自身.如果任 363 * 务不知道自己的优先级,还可以传递参数OS_PRIO_SELF.被删除的任务将回到休眠状态.任务被删 364 * 除后可以用函数OSTaskCreate()或OSTaskCreateExt()重新建立. 365 * 366 * 参数: prio 为指定要删除任务的优先级,也可以用参数OS_PRIO_SELF代替,此时,下一个优先级最高 367 * 的就绪任务将开始运行。 368 * 369 * 返回: OS_NO_ERR:函数调用成功; 370 * OS_TASK_DEL_IDLE:错误操作,试图删除空闲任务(Idle task); 371 * OS_TASK_DEL_ ERR:错误操作,指定要删除的任务不存在; 372 * OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO; 373 * OS_TASK_DEL_ISR:错误操作,试图在中断处理程序中删除任务. 374 * 375 * 376 * 注意: 1、OSTaskDel()将判断用户是否试图删除uC/OS中的空闲任务(Idle task); 377 * 2、在删除占用系统资源的任务时要小心,此时,为安全起见可以用另一个函数OSTaskDelReq(). 378 379 ************************************************************************************************* 380 */ 381 /*$PAGE*/ 382 #if OS_TASK_DEL_EN > 0 //允许生成 OSTaskDel()函数 383 INT8U OSTaskDel (INT8U prio) //删除任务(任务的优先级) 384 { 385 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 386 OS_CPU_SR cpu_sr; 387 #endif 388 389 #if OS_EVENT_EN > 0 //消息事件是否 > 0 390 OS_EVENT *pevent; //定义事件指针 391 #endif 392 //版本是否 > 2.51 并且 允许产生事件标志相关代码 并且应用中最多事件标志组的数目 > 0 393 #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) 394 OS_FLAG_NODE *pnode; //定义标志节点 395 #endif 396 OS_TCB *ptcb; //定义消息事件的任务控制块指针 397 398 399 400 if (OSIntNesting > 0) { //当前中断嵌套 > 0时,表示还有中断程序运行 401 return (OS_TASK_DEL_ISR); //错误操作,试图在中断处理程序中删除任务 402 } 403 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 404 if (prio == OS_IDLE_PRIO) { //检查任务优先级是否是空闲任务 405 return (OS_TASK_DEL_IDLE); //错误操作,试图删除空闲任务(Idle task) 406 } //当任务 >= 最低优先级 并且 任务不是本身 407 if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的 408 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO 409 } 410 #endif 411 OS_ENTER_CRITICAL(); //关闭中断 412 if (prio == OS_PRIO_SELF) { //检查的删除者是否是任务(优先级)本身 413 prio = OSTCBCur->OSTCBPrio; //正在运行的优先级(任务本身的优先级) 414 } //删除的任务必须存在 415 if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) { //调用这个任务的优先级的就绪值 416 if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) { //当就绪=1(即就绪状态) 417 OSRdyGrp &= ~ptcb->OSTCBBitY; //该任务处于就绪值,从就绪表中去除 418 } 419 #if OS_EVENT_EN > 0 //消息事件是否 > 0 420 pevent = ptcb->OSTCBEventPtr; //拾取该任务的事件控制指针 421 if (pevent != (OS_EVENT *)0) { 422 //指向事件控制块的指针是否为Null 423 if ((pevent->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { 424 //事件(消息)在等待表中将自己所处的表中删除 425 pevent->OSEventGrp &= ~ptcb->OSTCBBitY; 426 } 427 } 428 #endif 429 //版本是否 > 2.51 并且 允许产生事件标志相关代码 并且应用中最多事件标志组的数目 > 0 430 #if (OS_VERSION >= 251) && (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0) 431 pnode = ptcb->OSTCBFlagNode; //标志节点 = 指向事件标志节点的指针 432 if (pnode != (OS_FLAG_NODE *)0) { //如果任务处于事件标志的等待表中 433 OS_FlagUnlink(pnode); //就从此表中删除 434 } 435 #endif 436 ptcb->OSTCBDly = 0; //将任务时钟节拍清0,确保重新开中断,中断程序不使该任务就绪 437 ptcb->OSTCBStat = OS_STAT_RDY; //将任务的状态字处于完毕状态 438 if (OSLockNesting < 255) { //如果锁定嵌套计数器 < 255, 439 OSLockNesting++; //锁定嵌套计数器加1,使这个任务处于休眠状态 440 } 441 OS_EXIT_CRITICAL(); //打开中断 442 OS_Dummy(); //增加一个空指令 443 OS_ENTER_CRITICAL(); //关闭中断 444 if (OSLockNesting > 0) { //(可以继续执行删除任务的操作了) 445 OSLockNesting--; //重新关闭中断后,可以通过锁定嵌套计数器减1,重新允许任务调度 446 } 447 OSTaskDelHook(ptcb); //可在钩子程序中加入自定程序 448 OSTaskCtr--; //任务计数器减1,ucos管理的任务减少一个 449 OSTCBPrioTbl[prio] = (OS_TCB *)0; //将被删除的任务控制块OS_TCB指针=Null, 450 //从任务优先级中把OS_TCB删除 451 if (ptcb->OSTCBPrev == (OS_TCB *)0) { //任务块双向链接表的前链接是否Null 452 ptcb->OSTCBNext->OSTCBPrev = (OS_TCB *)0; //删除该任务的任务控制块OS_TCB 453 OSTCBList = ptcb->OSTCBNext; //链接表指向后一个链接 454 } else { //否则 455 ptcb->OSTCBPrev->OSTCBNext = ptcb->OSTCBNext; // ? 456 ptcb->OSTCBNext->OSTCBPrev = ptcb->OSTCBPrev; // ? 457 } //OSTCBPrev:用于任务块双向链接表的前链接 458 //OSTCBNext:用于任务块双向链接表的后链接 459 //OSTCBFreeList:空任务控制块指针 460 ptcb->OSTCBNext = OSTCBFreeList; //被删除的任务控制块OS_TCB被退回到空闲OS_TCB表中 461 OSTCBFreeList = ptcb; //以供建立其它任务使用 462 OS_EXIT_CRITICAL(); //打开中断 463 OS_Sched(); //任务调度,最高任务优先级运行 464 return (OS_NO_ERR); //函数调用成功 465 } 466 OS_EXIT_CRITICAL(); //打开中断 467 return (OS_TASK_DEL_ERR); //错误操作,指定要删除的任务不存在 468 } 469 #endif 470 /*$PAGE*/ 471 /* 472 ************************************************************************************************* 473 * 请求一个任务删除其它任务或自身(REQUEST THAT A TASK DELETE ITSELF) 474 * 475 * 描述: 请求一个任务删除自身。通常OSTaskDelReq()用于删除一个占有系统资源的任务(例如任务建立 476 * 了信号量)对于此类任务,在删除任务之前应当先释放任务占用的系统资源。 477 * 具体的做法是:在需要被删除的任务中调用OSTaskDelReq()检测是否有其他任务的删除请求,如 478 * 果有,则释放自身占用的资源,然后调用OSTaskDel()删除自身。例如,假设任务5要删除任务10, 479 * 而任务10占有系统资源,此时任务5不能直接调用OSTaskDel(10)删除任务10,而应该调用 480 * OSTaskDelReq(10)向任务10发送删除请求.在任务10中调用OSTaskDelReq(OS_PRIO_SELF),并检测 481 * 返回值。如果返回OS_TASK_DEL_REQ,则表明有来自其他任务的删除请求,此时任务10应该先释放 482 * 资源,然后调用OSTaskDel(OS_PRIO_SELF)删除自己。任务5可以循环调用OSTaskDelReq(10)并检 483 * 测返回值,如果返回OS_TASK_NOT_EXIST,表明任务10已经成功删除。 484 * void Task(void *data) 485 * { 486 * ... 487 * ... 488 * while (1) { 489 * OSTimeDly(1); 490 * if (OSTaskDelReq(OS_PRIO_SELF) == OS_TASK_DEL_REQ) 491 * { 492 * 释放任务占用的系统资源; 493 * 释放动态分配的内存; 494 * OSTaskDel(OS_PRIO_SELF); 495 * } 496 * } 497 * } 498 * 参数: prio 为要求删除任务的优先级。如果参数为OS_PRIO_SELF,则表示调用函数的任务正在查询 499 * 是否有来自其他任务的删除请求。 500 * 501 * 返回: OS_NO_ERR:删除请求已经被任务记录; 502 * OS_TASK_NOT_EXIST:指定的任务不存在,发送删除请求的任务可以等待此返回值,看删除是否成功; 503 * OS_TASK_DEL_IDLE: 错误操作,试图删除空闲任务(Idle task); 504 * OS_PRIO_INVALID: 参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值; 505 * OS_TASK_DEL_REQ: 当前任务收到来自其他任务的删除请求; 506 * 注意:OSTaskDelReq()将判断用户是否试图删除uC/OS中的空闲任务(Idle task)。 507 ************************************************************************************************* 508 */ 509 /*$PAGE*/ 510 #if OS_TASK_DEL_EN > 0 //允许生成 OSTaskDel()函数 511 INT8U OSTaskDelReq (INT8U prio) //请求一个任务删除其它任务或自身?(任务的优先级) 512 { 513 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 514 OS_CPU_SR cpu_sr; 515 #endif 516 BOOLEAN stat; //定义(布尔)任务标志返回值 517 INT8U err; //定义函数成功删除或其它任务正在申请删除 518 OS_TCB *ptcb; //定义消息事件的任务控制块指针 519 520 521 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 522 if (prio == OS_IDLE_PRIO) { //检查任务优先级是否是空闲任务 523 return (OS_TASK_DEL_IDLE); //错误操作,试图删除空闲任务(Idle task) 524 } //当任务 >= 最低优先级 并且 任务不是本身 525 if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的 526 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO 527 } 528 #endif 529 if (prio == OS_PRIO_SELF) { //如果删除者是任务本身 530 OS_ENTER_CRITICAL(); //关闭中断 531 stat = OSTCBCur->OSTCBDelReq; //stat:存储在任务控制块中的标志值 532 OS_EXIT_CRITICAL(); //打开中断 533 return (stat); //返回任务标志值 534 } 535 OS_ENTER_CRITICAL(); //关闭中断 536 if ((ptcb = OSTCBPrioTbl[prio]) != (OS_TCB *)0) { //调用这个任务的优先级的就绪值 537 ptcb->OSTCBDelReq = OS_TASK_DEL_REQ; //当前任务收到来自其他任务的删除请求 538 err = OS_NO_ERR; //删除请求已经被任务记录 539 } else { //否则 540 err = OS_TASK_NOT_EXIST; //该任务可能已经删除了 541 } 542 //指定的任务不存在,发送删除请求的任务可以等待此返回值,看删除是否成功 543 544 OS_EXIT_CRITICAL(); //关闭中断 545 return (err); //返回删除情况标志 546 } 547 #endif 548 /*$PAGE*/ 549 /* 550 ************************************************************************************************* 551 * 唤醒一个用OSTaskSuspend()函数挂起的任务(RESUME A SUSPENDED TASK) 552 * 553 * 描述: 唤醒一个用OSTaskSuspend()函数挂起的任务。OSTaskResume()也是唯一能"解挂"挂起任务的函数。 554 * 555 * 参数: prio 指定要唤醒任务的优先级。 556 * 557 * 返回: OS_NO_ERR: 函数调用成功; 558 * OS_TASK_RESUME_PRIO: 要唤醒的任务不存在; 559 * OS_TASK_NOT_SUSPENDED:要唤醒的任务不在挂起状态; 560 * OS_PRIO_INVALID: 参数指定的优先级大于或等于OS_LOWEST_PRIO。 561 ************************************************************************************************* 562 */ 563 564 #if OS_TASK_SUSPEND_EN > 0 //允许生成 OSTaskDel()函数 565 INT8U OSTaskResume (INT8U prio) //唤醒一个用OSTaskSuspend()函数挂起的任务(任务的优先级) 566 { 567 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 568 OS_CPU_SR cpu_sr; 569 #endif 570 OS_TCB *ptcb; //定义消息事件的任务控制块指针 571 572 573 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 574 if (prio >= OS_LOWEST_PRIO) { //当任务 >= 最低优先级 575 return (OS_PRIO_INVALID); //返回(要唤醒的任务不存在) 576 } 577 #endif 578 OS_ENTER_CRITICAL(); //关闭中断 579 if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { //调用这个任务的优先级的就绪值 580 OS_EXIT_CRITICAL(); //打开中断 581 return (OS_TASK_RESUME_PRIO); //返回(要唤醒的任务不存在) 582 } //任务控制块状态字相与OS_STAT_SUSPEND为1,任务存在 583 if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) != 0x00) { //要恢复的任务必须是存在的 584 //通过清除OSTCBStat域中的OS_STAT_SUSPEND未而取消挂起 585 //要使任务处于就绪状态,OSTCBDly必须是0,这是因为在OSTCBStat中,没有任何标志表明任务正在 586 //等待延时事件到 587 if (((ptcb->OSTCBStat &= ~OS_STAT_SUSPEND) == OS_STAT_RDY) && 588 (ptcb->OSTCBDly == 0)) { 589 //只有以上两个条件满足,任务才能处于就绪态 590 OSRdyGrp |= ptcb->OSTCBBitY; //保存任务就绪标准0-7到OSRdyGrp 591 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; //保存任务优先级别0-7到OSRdyTbl[] 592 OS_EXIT_CRITICAL(); //打开中断 593 OS_Sched(); //任务调度,最高任务优先级运行 594 } else { //否则 595 OS_EXIT_CRITICAL(); //打开中断 596 } 597 return (OS_NO_ERR); //返回(函数调用成功) 598 } 599 OS_EXIT_CRITICAL(); //打开中断 600 return (OS_TASK_NOT_SUSPENDED); //返回(要唤醒的任务不在挂起状态) 601 } 602 #endif 603 /*$PAGE*/ 604 /* 605 ************************************************************************************************* 606 * 检查任务堆栈状态,计算指定任务堆栈中的未用空间和已用空间(STACK CHECKING) 607 * 608 * 描述: 检查任务堆栈状态,计算指定任务堆栈中的未用空间和已用空间。使用OSTaskStkChk()函数要求 609 * 所检查的任务是被OSTaskCreateExt()函数建立的,且opt参数中OS_TASK_OPT_STK_CHK操作项打开。 610 * //计算堆栈未用空间的方法是从堆栈底端向顶端逐个字节比较,检查堆栈中0的个数,直到一个非0的 611 * 数值出现.这种方法的前提是堆栈建立时已经全部清零.要实现清零操作,需要在任务建立初始化 612 * 堆栈时设置OS_TASK_OPT_STK_CLR为1.如果应用程序在初始化时已经将全部RAM清零,且不进行任 613 * 务删除操作,也可以设置OS_TASK_OPT_STK_CLR为0,这将加快OSTaskCreateExt()函数的执行速度。 614 * 615 * 参数: prio 为指定要获取堆栈信息的任务优先级,也可以指定参数OS_PRIO_SELF,获取调用任务本身的 616 * 信息。 617 * 618 * pdata 指向一个类型为OS_STK_DATA的数据结构,其中包含如下信息: 619 * INT32U OSFree; // 堆栈中未使用的字节数 620 * INT32U OSUsed; // 堆栈中已使用的字节数 621 * 622 * 返回: OS_NO_ERR: 函数调用成功; 623 * OS_PRIO_INVALID: 参数指定的优先级大于OS_LOWEST_PRIO,或未指定OS_PRIO_SELF; 624 * OS_TASK_NOT_EXIST:指定的任务不存在; 625 * OS_TASK_OPT_ERR: 任务用OSTaskCreateExt()函数建立的时候没有指定OS_TASK_OPT_STK_CHK 626 * 操作,或者任务是用OSTaskCreate()函数建立的。 627 * 628 * 注意: 1、函数的执行时间是由任务堆栈的大小决定的,事先不可预料; 629 * 2、在应用程序中可以把OS_STK_DATA结构中的数据项OSFree和OSUsed相加,可得到堆栈的大小; 630 * 3、虽然原则上该函数可以在中断程序中调用,但由于该函数可能执行很长时间,所以实际中不提 631 * 倡这种做法。 632 ************************************************************************************************* 633 */ 634 #if OS_TASK_CREATE_EXT_EN > 0 //允许生成 OSTaskStkChk()函数 635 INT8U OSTaskStkChk (INT8U prio, OS_STK_DATA *pdata) 636 { //检查任务堆栈状态(任务优先级、检验堆栈数据结构) 637 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 638 OS_CPU_SR cpu_sr; 639 #endif 640 OS_TCB *ptcb; //定义消息事件的任务控制块指针 641 OS_STK *pchk; //定义指向当前任务堆栈栈底的指针 642 INT32U free; //定义任务堆栈实际空闲字节数 643 INT32U size; //定义存有栈中可容纳的指针数目 644 645 646 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 647 //当任务 >= 最低优先级 并且 任务不是本身 648 if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的 649 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO,或未指定OS_PRIO_SELF 650 } 651 #endif 652 pdata->OSFree = 0; //未使用的字节清0 653 pdata->OSUsed = 0; //已使用的字节清0 654 OS_ENTER_CRITICAL(); //关闭中断 655 if (prio == OS_PRIO_SELF) { //如果检查者是任务本身 656 prio = OSTCBCur->OSTCBPrio; //指向正在运行(优先级)任务控制块的指针 657 } 658 ptcb = OSTCBPrioTbl[prio]; //调用这个优先级别任务的就绪值 659 if (ptcb == (OS_TCB *)0) { //当检验OSTCBPrioTbl[]里是非0值,确定任务存在 660 OS_EXIT_CRITICAL(); //打开中断 661 return (OS_TASK_NOT_EXIST); //指定的任务不存在 662 } 663 //要执行堆栈检验,必须用OSTaskCreateExt()函数建立任务,并且已经传递了选项OS_TASK_OPT_STK_CHK, 664 //而对OSTaskCreate()函数建立的任务,那么会对OPT(传递给OS_TCBInit)为0,而使检验失败 665 if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0) { //如果检验OPT=0 666 OS_EXIT_CRITICAL(); //打开中断 667 return (OS_TASK_OPT_ERR); //返回检验失败 668 } //从堆栈栈底统计堆栈空闲空间,直到遇到一个存储非0值 669 free = 0; //堆栈中未使用的字节数free = 0 670 size = ptcb->OSTCBStkSize; //size = 存有栈中可容纳的指针数目 671 pchk = ptcb->OSTCBStkBottom; //pchk = 指向当前任务堆栈栈底的指针 672 OS_EXIT_CRITICAL(); //打开中断 673 #if OS_STK_GROWTH == 1 //查看堆栈增长方向,为1递增 674 while (*pchk++ == (OS_STK)0) { //当前任务堆栈栈顶的指针加1(内容)是否等于0 675 free++; //定义堆栈中未使用的字节数加1 676 } 677 #else //否则,向下递减 678 while (*pchk-- == (OS_STK)0) { //当前任务堆栈栈底的指针减1(内容)是否等于0 679 free++; //定义堆栈中未使用的字节数加1 680 } 681 #endif 682 pdata->OSFree = free * sizeof(OS_STK); //任务堆栈实际空闲字节数 683 pdata->OSUsed = (size - free) * sizeof(OS_STK); //任务堆栈已被占用的字节数 684 return (OS_NO_ERR); //函数调用成功 685 } 686 #endif 687 /*$PAGE*/ 688 /* 689 ************************************************************************************************* 690 * 无条件挂起一个任务(SUSPEND A TASK) 691 * 692 * 描述: 无条件挂起一个任务. 调用此函数的任务也可以传递参数OS_PRIO_SELF,挂起调用任务本身. 693 * 当前任务挂起后,只有其他任务才能唤醒.任务挂起后,系统会重新进行任务调度,运行下一个 694 * 优先级最高的就绪任务.唤醒挂起任务需要调用函数OSTaskResume(). 695 * //任务的挂起是可以叠加到其他操作上的。例如,任务被挂起时正在进行延时操作,那么任务的 696 * 唤醒就需要两个条件:延时的结束以及其他任务的唤醒操作.又如,任务被挂起时正在等待信 697 * 号量,当任务从信号量的等待对列中清除后也不能立即运行,而必须等到唤醒操作后。 698 * 699 * 参数: prio 为指定要获取挂起的任务优先级,也可以指定参数OS_PRIO_SELF,挂起任务本身.此时, 700 * 下一个优先级最高的就绪任务将运行. 701 * 702 * 返回: OS_NO_ERR: 函数调用成功; 703 * OS_TASK_ SUSPEND_IDLE: 试图挂起uC/OS-II中的空闲任务(Idle task)。此为非法操作; 704 * OS_PRIO_INVALID: 参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值; 705 * OS_TASK_ SUSPEND _PRIO:要挂起的任务不存在。 706 * 707 * 注意: 1、在程序中OSTaskSuspend()和OSTaskResume()应该成对使用; 708 * 2、用OSTaskSuspend()挂起的任务只能用OSTaskResume()唤醒. 709 ************************************************************************************************* 710 */ 711 712 #if OS_TASK_SUSPEND_EN > 0 //允许生成 OSTaskSuspend()函数 713 INT8U OSTaskSuspend (INT8U prio) //无条件挂起一个任务(任务优先级) 714 { 715 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 716 OS_CPU_SR cpu_sr; 717 #endif 718 BOOLEAN self; //定义布尔(=1为任务本身) 719 OS_TCB *ptcb; //定义消息事件的任务控制块指针 720 721 722 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内 723 if (prio == OS_IDLE_PRIO) { //检查任务的优先级是否是空闲任务 724 return (OS_TASK_SUSPEND_IDLE); //试图挂起uC/OS-II中的空闲任务(Idle task)。此为非法操作 725 } //当任务 >= 最低优先级 并且 任务不是本身 726 if (prio >= OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的 727 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO或没有设定OS_PRIO_SELF的值 728 } 729 #endif 730 OS_ENTER_CRITICAL(); //关闭中断 731 if (prio == OS_PRIO_SELF) { //如果删除者是任务本身 732 prio = OSTCBCur->OSTCBPrio; //从当前任务的任务控制块OS_TCB中获取当前任务的优先级 733 self = TRUE; //是任务本身(为1) 734 } else if (prio == OSTCBCur->OSTCBPrio) { //也可以通过指定优先级,挂起调用本函数的任务 735 self = TRUE; //是任务本身(为1) 736 } else { //否则 737 self = FALSE; //要删除的不是任务本身 738 } 739 if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { //检验要挂起的任务是否存在(为1任务存在) 740 OS_EXIT_CRITICAL(); //打开中断 741 return (OS_TASK_SUSPEND_PRIO); //返回(要挂起的任务不存在) 742 } 743 if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) { //如果该任务存在 744 OSRdyGrp &= ~ptcb->OSTCBBitY; //从就绪表中清除它(等待事件的话也删除) 745 } 746 ptcb->OSTCBStat |= OS_STAT_SUSPEND; //在任务的状态字中标明'SUSPENDED',表示任务被挂起 747 OS_EXIT_CRITICAL(); //打开中断 748 if (self == TRUE) { //如果是任务本身(为1) 749 OS_Sched(); //任务调度,最高任务优先级运行 750 //说明:self == TRUE,删除本身,需要进入任务调度执行新的任务 751 //self = FALSE,删除的是其它任务,无需进入调度,可继续执行本任务 752 } 753 return (OS_NO_ERR); //返回(函数调用成功) 754 } 755 #endif 756 /*$PAGE*/ 757 /* 758 ************************************************************************************************* 759 * 获取任务信息,函数返回任务TCB的一个完整的拷贝(QUERY A TASK) 760 * 761 * 描述: 获取任务信息,函数返回任务TCB的一个完整的拷贝.应用程序必须建立一个OS_TCB类型的数据结 762 * 构容纳返回的数据.需要提醒用户的是,在对任务OS_TCB对象中的数据操作时要小心,尤其是数据 763 * 项OSTCBNext和OSTCBPrev.它们分别指向TCB链表中的后一项和前一项. 764 * 765 * 参数: prio 为指定要获取TCB内容的任务优先级,也可以指定参数OS_PRIO_SELF,获取调用任务的信息. 766 * pdata指向一个OS_TCB类型的数据结构,容纳返回的任务TCB的一个拷贝. 767 * 768 * 返回: OS_NO_ERR: 函数调用成功; 769 * OS_PRIO_ERR: 参数指定的任务非法; 770 * OS_PRIO_INVALID:参数指定的优先级大于OS_LOWEST_PRIO. 771 * 注意: 任务控制块(TCB)中所包含的数据成员取决于下述开关量在初始化时的设定(参见OS_CFG.H) 772 * OS_TASK_CREATE_EN 773 * OS_Q_EN 774 * OS_MBOX_EN 775 * OS_SEM_EN 776 * OS_TASK_DEL_EN 777 ************************************************************************************************* 778 */ 779 780 #if OS_TASK_QUERY_EN > 0 //允许(1)生成OSTaskQuery()代码 781 INT8U OSTaskQuery (INT8U prio, OS_TCB *pdata) //获取任务信息(任务指针、保存数据结构指针) 782 { 783 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3 784 OS_CPU_SR cpu_sr; 785 #endif 786 OS_TCB *ptcb; //定义消息事件的任务控制块指针 787 788 789 #if OS_ARG_CHK_EN > 0 790 //当任务 >= 最低优先级 并且 任务不是本身 791 if (prio > OS_LOWEST_PRIO && prio != OS_PRIO_SELF) { //检查任务是否是合法的 792 return (OS_PRIO_INVALID); //参数指定的优先级大于OS_LOWEST_PRIO 793 } 794 #endif 795 OS_ENTER_CRITICAL(); //关闭中断 796 if (prio == OS_PRIO_SELF) { //检查的删除者是否是任务(优先级)本身 797 prio = OSTCBCur->OSTCBPrio; //正在运行的优先级(任务本身的优先级) 798 } //获取(信息)任务必须存在 799 if ((ptcb = OSTCBPrioTbl[prio]) == (OS_TCB *)0) { //调用这个任务的优先级的就绪值 800 OS_EXIT_CRITICAL(); //打开中断 801 return (OS_PRIO_ERR); //返回(参数指定的任务非法) 802 } 803 memcpy(pdata, ptcb, sizeof(OS_TCB)); //所有的域(通过赋值语句)一次性复制 804 OS_EXIT_CRITICAL(); //打开中断 805 return (OS_NO_ERR); //返回获取信息成功(函数调用成功) 806 } 807 #endif 808