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