1 /*
2 *************************************************************************************************
3 * uC/OS-II实时控制内核
4 * 互斥型信号量项管理
5
6 * 文 件: OS_MUTEX.C 包含主要互斥型信号量代码
7 * 作 者: Jean J. Labrosse
8 * 中文注解: 钟常慰 zhongcw @ 126.com 整理:lin_credible 译注版本:1.0 请尊重原版内容
9 *************************************************************************************************
10 */
11
12 #ifndef OS_MASTER_FILE //是否已定义OS_MASTER_FILE主文件
13 #include "includes.h" //包含"includes.h"文件,部分C语言头文件的汇总打包文件
14 #endif //定义结束
15
16 /*
17 *************************************************************************************************
18 * 局部变量 (LOCAL CONSTANTS)
19 *************************************************************************************************
20 */
21
22 #define OS_MUTEX_KEEP_LOWER_8 0x00FF //设定互斥型信号量低8位有效(相与)
23 #define OS_MUTEX_KEEP_UPPER_8 0xFF00 //设定互斥型信号量高8位有效(相与)
24
25 #define OS_MUTEX_AVAILABLE 0x00FF //置MUTEX的值为有效,同时保存PIP值,高八位有效(相或)
26
27
28 #if OS_MUTEX_EN > 0 //条件编译:当OS_SEM_EN允许产生信号量程序代码
29 /*
30 *************************************************************************************************
31 * 无等待地获取互斥型信号量(ACCEPT MUTUAL EXCLUSION SEMAPHORE)
32 *
33 * 描述: 检查互斥型信号量,以判断某资源是否可以使用,与 OSMutexPend()不同的是,若资源不能使用,
34 * 则调用 OSMutexAccept()函数的任务并不被挂起, OSMutexAccept()仅查询状态。
35 *
36 * 参数: pevent 指向管理某资源的互斥型信号量。程序在建立mutex时,得到该指针(参见 OSMutexCreate())
37 *
38 * err 指向出错代码的指针,为以下值之一:
39 * OS_NO_ERR 调用成功;
40 * OS_ERR_EVENT_TYPE 'pevent'不是指向mutex类型的指针;
41 * OS_ERR_PEVENT_NULL 'pevent'是空指针;
42 * OS_ERR_PEND_ISR 在中断服务子程序中调用 OSMutexAccept().
43 *
44 * 返回: == 1 如果mutex有效, OSMutexAccept()函数返回1;
45 * == 0 如果mutex被其他任务占用,OSMutexAccept()则返回0。
46 *
47 * 警告: 1、必须先建立mutex,然后才能使用;
48 * 2、在中断服务子程序中不能调用 OSMutexAccept()函数;
49 * 3、如使用 OSMutexAccept()获取mutex的状态,那么使用完共享资源后,必须调用 OSMutexPost()
50 * 函数释放mutex
51 *************************************************************************************************
52 */
53
54 #if OS_MUTEX_ACCEPT_EN > 0 //允许生成 OSSemAccept()函数
55 INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err)
56 { //无等待地获取互斥型信号量[任务不挂起](信号量指针、错误代码)
57 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
58 OS_CPU_SR cpu_sr;
59 #endif
60
61 if (OSIntNesting > 0) { //当前中断嵌套 > 0时,表示还有中断程序运行
62 *err = OS_ERR_PEND_ISR; //在中断服务子程序中调用 OSMutexAccept()
63 return (0); //返回Null
64 }
65 #if OS_ARG_CHK_EN > 0 //所有参数必须在指定的参数内
66 if (pevent == (OS_EVENT *)0) { //当互斥型信号量的指针为空(Null)
67 *err = OS_ERR_PEVENT_NULL; //'pevent'是空指针
68 return (0); //返回Null
69 }
70 if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { //当事件类型不是一个互斥型信号量
71 *err = OS_ERR_EVENT_TYPE; //'pevent'不是指向mutex类型的指针
72 return (0); //返回Null
73 }
74 #endif
75 OS_ENTER_CRITICAL(); //关闭中断
76 //获得Mutex的值(0或1),OSEventCnt相与0x00ff后判断OSEventCnt低8为0xff
77 //如果Mutex(高8位PIP)有效
78 //将PIP保存到OSEventCnt的高8位(相与0xffoo)
79 //把该任务的优先级写到OSEventCnt的低8位(相或OSTCBPrio)
80 //将Mutex的事件控制块ECB链接到该任务的任务控制块
81 if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
82 pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;
83 pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
84 pevent->OSEventPtr = (void *)OSTCBCur;
85 OS_EXIT_CRITICAL(); //打开中断
86 *err = OS_NO_ERR; //调用成功
87 return (1); //返回1,表明mutex已经得到,可以使用相应的共享资源
88 }
89 OS_EXIT_CRITICAL(); //打开中断
90 *err = OS_NO_ERR; //调用成功
91 return (0); //返回Null,表明mutex无效,不能使用
92 }
93 #endif
94
95 /*$PAGE*/
96 /*
97 *************************************************************************************************
98 * 建立和初始化互斥型信号量(CREATE A MUTUAL EXCLUSION SEMAPHORE)
99 *
100 * 描述: 互斥型信号量mutual的建立和初始化. 在与共享资源打交道时, 使用mutex可以保证满足互斥条件.
101 *
102 * 参数: prio 优先级继承优先级(PIP).当一个高优先级的任务想要得到某mutex,而此时这个mutex却被
103 * 一个低优先级的任务占用时,低优先级任务的优先级可以提升到PIP,知道其释放共享资源。
104 *
105 * err 指向出错代码的指针,为以下值之一:
106 * OS_NO_ERR 调用成功mutex已被成功的建立;
107 * OS_ERR_CREATE_ISR 试图在中断服务子程序中建立mutex;
108 * OS_PRIO_EXIST 优先级为PIP的任务已经存在;
109 * OS_ERR_PEVENT_NULL 已经没有OS_EVENT结构可以使用的了;
110 * OS_PRIO_INVALID 定义的优先级非法,其值大于OS_LOWEST_PRIO.
111 *
112 * 返回: 返回一个指针,该指针指向分配给mutex的事件控制块.如果得不到事件控制块,则返回一个空指针.
113 *
114 * 注意: 1) 必须先建立mutex,然后才能使用;
115 * 2) 必须确保优先级继承优先级.即prio高于可能与相应共享资源打交道的任务中优先级最高的任
116 * 务的优先级.例如有3个优先级分别为20,25,30的任务会使用mutex,那么prio的值必须小于
117 * 20;并且,已经建立了任务没有占用这个优先级。
118 *************************************************************************************************
119 */
120 //建立并初始化一个互斥型信号量(优先级继承优先级(PIP)、出错代码指针)
121 OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)
122 {
123 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
124 OS_CPU_SR cpu_sr;
125 #endif
126 OS_EVENT *pevent; //定义一个互斥型信号量变量
127
128
129 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行
130 *err = OS_ERR_CREATE_ISR; //试图在中断服务子程序中建立mutex
131 return ((OS_EVENT *)0); //返回0
132 }
133 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内
134 if (prio >= OS_LOWEST_PRIO) { //当任务优先级大于等于最大优先级
135 *err = OS_PRIO_INVALID; //定义的优先级非法,其值大于OS_LOWEST_PRIO
136 return ((OS_EVENT *)0); //返回0
137 }
138 #endif
139 OS_ENTER_CRITICAL(); //关闭中断
140 if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { //确认优先级别未占用,即就绪状态不为0
141 OS_EXIT_CRITICAL(); //打开中断
142 *err = OS_PRIO_EXIST; //优先级为PIP的任务已经存在
143 return ((OS_EVENT *)0); //返回0
144 }
145 OSTCBPrioTbl[prio] = (OS_TCB *)1; //否则优先级别已用,即就绪状态为1
146 pevent = OSEventFreeList; // 试从空余事件控制列表中得到一个控制块ECB
147 if (pevent == (OS_EVENT *)0) { //当控制块=0时
148 OSTCBPrioTbl[prio] = (OS_TCB *)0; //将优先级别就绪态清0
149 OS_EXIT_CRITICAL(); //打开中断
150 *err = OS_ERR_PEVENT_NULL; //错误为(已经没有OS_EVENT结构可以使用的了)
151 return (pevent); //返回pevent指针
152 } //空余事件控制列表指向下一个空余事件控制块(指针)
153 OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
154 OS_EXIT_CRITICAL(); //打开中断
155 pevent->OSEventType = OS_EVENT_TYPE_MUTEX; //事件类型=MUTEX类型
156 pevent->OSEventCnt = (prio << 8) | OS_MUTEX_AVAILABLE; //置MUTEX的值为有效,同时保存PIP值
157 pevent->OSEventPtr = (void *)0; //指向消息指针为0,没有等待这个MUTEX的任务
158 OS_EventWaitListInit(pevent); //调用初始化等待任务列表
159 *err = OS_NO_ERR; //调用成功mutex已被成功的建立
160 return (pevent); //返回对应的OS_EventWaitListInit值
161 }
162
163 /*$PAGE*/
164 /*
165 *************************************************************************************************
166 * 删除互斥型信号量 (DELETE A MUTEX)
167 *
168 * 描述: 删除一个mutex。使用这个函数有风险,因为多任务中其他任务可能还想用这个实际上已经被删除
169 * 了的mutex。使用这个函数时必须十分小心,一般地说,要删除一个mutex,首先应删除可能会用到
170 * 这个mutex的所有任务。
171 *
172 * 参数: pevent 指向mutex的指针。应用程序建立mutex时得到该指针(参见OSMutexCreate()
173 *
174 * opt 该参数定义删除mutex的条件。:
175 * opt == OS_DEL_NO_PEND 只能在已经没有任何任务在等待该mutex时,才能删除;
176 * opt == OS_DEL_ALWAYS 不管有没有任务在等待这个mutex,立刻删除mutex。
177 * -->在第二种情况下,所有等待mutex的任务都立即进入就绪态.
178 *
179 * err 指向出错代码的指针,为以下值之一:
180 * OS_NO_ERR 调用成功,mutex删除成功;
181 * OS_ERR_DEL_ISR 试图在中断服务子程序中删除mutex。
182 * OS_ERR_INVALID_OPT 定义的opt参数无效,不是上面提到的2个参数之一;
183 * OS_ERR_TASK_WAITING 定义了OS_DEL_NO_PEND,而有一个或一个以上的任务在等这个mutex.
184 * OS_ERR_EVENT_TYPE 'pevent'不是指向mutex的指针;
185 * OS_ERR_PEVENT_NULL 已经没有可以使用的OS_EVENT数据结构了。
186 *
187 * 返回: pevent 如果mutex已经删除,则返回空指针;如果mutex没能删除,则返回pevent.
188 * 在后一种情况下,程序应检查出错代码,以查出原因。
189 *
190 * 注意: 1) 使用这个函数时必须十分小心,因为其他任务可能会用到mutex。
191 * 这个的所有任务。
192 *************************************************************************************************
193 */
194
195 #if OS_MUTEX_DEL_EN //允许生成 MutexDel()代码
196 OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
197 { //删除互斥型信号量(信号指针、删除条件、错误指针)
198 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
199 OS_CPU_SR cpu_sr;
200 #endif
201 BOOLEAN tasks_waiting; //定义布尔量,任务等待条件
202 INT8U pip; //定义优先级继承优先级
203
204
205 if (OSIntNesting > 0) { //中断嵌套数 > 0时,表示还有中断任务在运行
206 *err = OS_ERR_DEL_ISR; //试图在中断服务子程序中删除mutex
207 return (pevent); //返回pevent指针
208 }
209 #if OS_ARG_CHK_EN > 0
210 if (pevent == (OS_EVENT *)0) { //所有参数在指定的范围之内
211 *err = OS_ERR_PEVENT_NULL; //已经没有可以使用的OS_EVENT数据结构了
212 return ((OS_EVENT *)0); //返回空值0
213 }
214 if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { //当事件标志不是mutex类型时
215 *err = OS_ERR_EVENT_TYPE; //'pevent'不是指向mutex的指针;
216 return (pevent); //返回pevent指针
217 }
218 #endif
219 OS_ENTER_CRITICAL(); //关闭中断
220 if (pevent->OSEventGrp != 0x00) { //当事件就绪表中有任务在等待该mutex
221 tasks_waiting = TRUE; //任务等待标志为(真)
222 } else {
223 tasks_waiting = FALSE; //否则,该任务等待标志为(假)
224 }
225 switch (opt) { //opt设定选项,删除条件
226 case OS_DEL_NO_PEND: // 1)只能在已经没有任何任务在等待该mutex时,才能删除
227 if (tasks_waiting == FALSE) { //没有任务在等待这个mutex
228 pip = (INT8U)(pevent->OSEventCnt >> 8); //优先级继承优先级 2008.07.29
229 OSTCBPrioTbl[pip] = (OS_TCB *)0; //任务控制块优先级表pip为空
230 pevent->OSEventType = OS_EVENT_TYPE_UNUSED; //事件类型=空闲状态
231 pevent->OSEventPtr = OSEventFreeList; //指向消息的指针=当前空余事件指针
232 OSEventFreeList = pevent; //空余事件列表等于被删除的指针
233 OS_EXIT_CRITICAL(); //打开中断
234 *err = OS_NO_ERR; //调用成功,mutex删除成功
235 return ((OS_EVENT *)0); //返回空指针0
236 } else {
237 OS_EXIT_CRITICAL(); //打开中断
238 *err = OS_ERR_TASK_WAITING; //有一个或一个以上的任务在等这个mutex.
239 return (pevent); //返回pevent指针
240 }
241
242 case OS_DEL_ALWAYS: // 2)多任务等待,尽管有任务在等待,还是要删除
243 while (pevent->OSEventGrp != 0x00) { //等待标志≠0,还是要删除
244 //OS_EventTaskRdy()函数将最高级优先级任务从等待列表中删除
245 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX); //使一个任务进入就绪态
246 }
247 pip = (INT8U)(pevent->OSEventCnt >> 8); //优先级继承优先级
248 OSTCBPrioTbl[pip] = (OS_TCB *)0; //任务控制块优先级表pip为空
249 pevent->OSEventType = OS_EVENT_TYPE_UNUSED; //事件类型=空闲状态
250 pevent->OSEventPtr = OSEventFreeList; //指向消息的指针=当前空余事件指针
251 OSEventFreeList = pevent; //空余事件列表等于被删除的指针
252 OS_EXIT_CRITICAL();
253 if (tasks_waiting == TRUE) { //有任务在等待这个mutex
254 OS_Sched(); //调用调度函数,最高优先级任务运行
255 }
256 *err = OS_NO_ERR; //调用成功,mutex删除成功
257 return ((OS_EVENT *)0); //返回空指针0
258
259 default: // 3)两个条件都不是
260 OS_EXIT_CRITICAL(); //打开中断
261 *err = OS_ERR_INVALID_OPT; //指定的opt无效不是指定的OS_DEL_NO_PEND和OS_DEL_ALWAYS
262 return (pevent); //返回pevent指针
263 }
264 }
265 #endif
266
267 /*$PAGE*/
268 /*
269 *************************************************************************************************
270 * 等待一个互斥型信号量(挂起) (PEND ON MUTUAL EXCLUSION SEMAPHORE)
271 *
272 * 描述: 当任务需要独占共享资源时,应使用OSMutexPend()函数.如果任务在调用本函数时共享资源可
273 * 以使用,则OSMutexPend()函数返回,调用OSMutexPend()函数的任务得到了mutex。
274 *
275 * 注意:OSMutexPend()实际上并没有"给"调用本函数的任务什么值,只不过参数err的值被置为
276 * OS_NO_ERR,调用本函数的任务好像得到了mutex并继续运行。
277 * ---> 然而,如果nutex已经被别的任务占用了,那么OSMutexPend()函数就将调用该函数的任务放入
278 * 等待mutex的任务列表中,这个任务于是进入了等待状态,直到占有mutex的任务释放了mutex以
279 * 及共享资源,或者直到定义的等待时限超时。如果在等待时限内mutex得以释放,那么ucos_ii恢
280 * 复运行等待mutex的任务中优先级最高的任务。
281 * 注意:如果mutex被优先级较低的任务占用了,那么OSMutexPend()会将占用mutex的任务的优先级提升
282 * 到优先级继承优先级PIP。PIP是在mutex建立时定义的(参见OSMutexCreate())
283 *
284 * 参数: pevent 指向mutuex的指针。应用程序在建立mutuex时得到该指针的(参见OSMutexCreate())
285 *
286 * timeout 以时钟节拍数目的等待超时时限。如果在这一时限得不到mutex,任务将恢复执行。
287 * timeout的值为0,表示将无限期地等待mutex。timeout的最大值是65535个时钟节
288 * 拍。timeout的值并不与时钟节拍同步,timeout计数器在下一个时钟节拍到来时
289 * 开始递减。在这里,所谓下一个时钟节拍,也就是立刻就到来了。
290 *
291 * err 指向出错代码的指针,为以下值之一:
292 * OS_NO_ERR 调用成功,mutex可以使用;
293 * OS_TIMEOUT 在定义的时间限内得不到mutex;
294 * OS_ERR_EVENT_TYPE 用户没能向OSMutexPend()传递指向mutex的指针;
295 * OS_ERR_PEVENT_NULL 'pevent'是空指针
296 * OS_ERR_PEND_ISR 试图在中断服务子程序中获得mutex.
297 *
298 * 返回: 无
299 *
300 * 注意: 1) 必须先建立mutex,然后才能使用;
301 * 2) 不要将占用mutex的任务挂起,也不要让占有mutex的任务等待usoc_ii提供的信号量、邮箱及消
302 * 息队列等,不要将占用mutex的任务延迟.换言,用户代码应该抓紧时间,尽量快地释放共享资源。
303 *************************************************************************************************
304 */ 2008.07.29
305 void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
306 {
307 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
308 OS_CPU_SR cpu_sr;
309 #endif
310 INT8U pip; //定义mutex中的PIP
311 INT8U mprio; //定义mutex的优先级
312 BOOLEAN rdy; //布尔量rdy
313 OS_TCB *ptcb; //定义mutex的任务控制块指针
314
315
316 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行
317 *err = OS_ERR_PEND_ISR; //试图在中断服务子程序中获得mutex
318 return; //返回
319 }
320 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内
321 if (pevent == (OS_EVENT *)0) { //pevent=0
322 *err = OS_ERR_PEVENT_NULL; //'pevent'是空指针
323 return; //返回
324 }
325 if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { //当事件类型不否是mutex类型
326 *err = OS_ERR_EVENT_TYPE; //用户没能向OSMutexPend()传递指向mutex的指针
327 return; //返回
328 }
329 #endif
330 OS_ENTER_CRITICAL(); //关闭中断
331 //OSEventCnt:高8位是PIP值,低8位是无任占用务时为OxFF值,有任务占用时为任务优先级
332 //如果OSEventCnt低8位=0xFF
333 if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
334 pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; //计数器=低8位
335 pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; //计数器低8位=调用该函数任务优先级
336 pevent->OSEventPtr = (void *)OSTCBCur; //指针指向调用该函数任务控制块TCB
337 OS_EXIT_CRITICAL(); //打开中断
338 *err = OS_NO_ERR; //调用成功,mutex可以使用
339 return; //返回
340 }
341 pip = (INT8U)(pevent->OSEventCnt >> 8); //提取mutex中的PIP
342 mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); //提取mutex的优先级
343 ptcb = (OS_TCB *)(pevent->OSEventPtr); //占用mutex的任务控制块指针
344 //当前任务优先级不等于占用mutex优先级并且占用mutex的优先级 > 当前运行的任务优先级
345 if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) {
346 //确认占用mutex的任务是否进入就绪态
347 if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) {
348 //如果该任务处于就绪态,那么这个任务已不是处在它原来优先级上的就绪态,
349 if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
350 OSRdyGrp &= ~ptcb->OSTCBBitY;
351 }
352 rdy = TRUE; //置rdy标志,可以运行,占用Mutex的任务进入就绪状态
353 } else {
354 rdy = FALSE; //否则,清rdy标志
355 }
356 ptcb->OSTCBPrio = pip; //当前任务控制块优先级=提取Mutex的PIP
357 ptcb->OSTCBY = ptcb->OSTCBPrio >> 3; //取高3位优先级的值
358 ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY]; //对应的高3位OSMapTbl值
359 ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07; //取低3位优先级的值
360 ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX]; //对应的低3位OSMapTbl值
361 if (rdy == TRUE) { //当rdy=1时,
362 OSRdyGrp |= ptcb->OSTCBBitY;//保存任务就绪标准0-7到OSRdyGrp
363 OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;//保存任务优先级别0-7到OSRdyTbl[]
364 }
365 OSTCBPrioTbl[pip] = (OS_TCB *)ptcb; //确认占用mutex的任务是否PIP优先级进入就绪态
366 }
367 OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; //让任务控制块中的状态标志置位,标明任务等待mutex而挂起
368 OSTCBCur->OSTCBDly = timeout; //等待超时参数也保存在任务控制块中
369 OS_EventTaskWait(pevent); //让任务进入休眠状态
370 OS_EXIT_CRITICAL(); //打开中断
371 OS_Sched(); //任务调度
372 OS_ENTER_CRITICAL(); //关闭中断
373 if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) { //检查任务控制块状态
374 OS_EventTO(pevent); //
375 OS_EXIT_CRITICAL(); //打开中断
376 *err = OS_TIMEOUT; //以时钟节拍数目的等待超时时限
377 return; //返回Null
378 }
379 OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; //指向信号指针=0
380 OS_EXIT_CRITICAL(); //打开中断
381 *err = OS_NO_ERR; //返回调用成功,mutex可以使用
382 }
383 /*$PAGE*/
384 /*
385 *************************************************************************************************
386 * 释放一个互斥型信号量(POST TO A MUTUAL EXCLUSION SEMAPHORE)
387 *
388 * 描述: 调用OSMutexPost()可以发出mutex。只是当用户程序已调用OSMutexAccept()或OSMutexPend()请
389 * 求得到mutex时,OSMutexPost()函数才起作用。当优先级较高的任务试图得到mutex时,如果占用
390 * mutex的任务的优先级已经被升高,那么OSMutexPost()函数使优先级升高了的任务恢复原来的优
391 * 先级。如果有一个以上的任务在等待这个mutex,那么等待mutex的任务中优先级最高的任务将得
392 * 得到mutex。然后本函数会调用调度函数,看被唤醒的任务是不是进入就绪态任务中优先级最高的
393 * 任务。如果是,则做任务切换,让这个任务运行。如果没有等待mutex的任务,那么本函数只不过
394 * 是将nutex的值设为OxFF,表示mutex可以使用。
395 *
396 * 参数: pevent 指向mutuex的指针。应用程序在建立mutuex时得到该指针的(参见OSMutexCreate())
397 *
398 * 返回: OS_NO_ERR 调用成功,mutex被释放;
399 * OS_ERR_EVENT_TYPE OSMutexPost()传递的不是指向mutex的指针;
400 * OS_ERR_PEVENT_NULL 'pevent'是空指针;
401 * OS_ERR_POST_ISR 试图在中断服务子程序中调用OSMutexPost()函数;
402 * OS_ERR_NOT_MUTEX_OWNER 发出mutex的任务实际上并不占用mutex。
403 *
404 * 注意:1) 必须先建立mutex,然后才能使用;
405 * 2) 在中断服务子程序中不能调用OSMutexPost()函数
406 *************************************************************************************************
407 */
408
409 INT8U OSMutexPost (OS_EVENT *pevent) //释放一个互斥型信号量(互斥型信号量指针)
410 {
411 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
412 OS_CPU_SR cpu_sr;
413 #endif
414 INT8U pip; //定义mutex中的PIP
415 INT8U prio; //定义当前mutex的事件优先级
416
417
418 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行
419 return (OS_ERR_POST_ISR); //返回(试图在中断服务子程序中调用OSMutexPost()函数)
420 }
421 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内
422 if (pevent == (OS_EVENT *)0) { //pevent=0
423 return (OS_ERR_PEVENT_NULL); //'pevent'是空指针
424 }
425 if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { //当事件类型不否是mutex类型
426 return (OS_ERR_EVENT_TYPE); //OSMutexPost()传递的不是指向mutex的指针
427 }
428 #endif
429 OS_ENTER_CRITICAL(); //关闭中断
430 //OSEventCnt:高8位是PIP值,低8位是无任占用务时为OxFF值,有任务占用时为任务优先级
431 pip = (INT8U)(pevent->OSEventCnt >> 8); //提取mutex的PIP
432 prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); //拾取mute的优先级
433 //OSMutexPost()确认,释放mutex的任务确实占用mutex的任务,占用mutex的任务的优先级:
434 //或者是被提升到PIP(OSMutexpend()函数已经将该任务的优先级升高);
435 //或仍然是保在mutex之中的优先级。
436 if (OSTCBCur->OSTCBPrio != pip && //任务的优先级是否=当前任务mutex的PIP,并且
437 OSTCBCur->OSTCBPrio != prio) { //任务的优先级是否=当前mutex事件优先级
438 OS_EXIT_CRITICAL(); //打开中断
439 return (OS_ERR_NOT_MUTEX_OWNER); //发出mutex的任务实际上并不占用mutex
440 }
441 //查看占用mutex的任务优先级是否已经上升到了PIP,因为有个高优先级的任务也需要这个mutex。
442 //在这种情况下,占用mutex的任务优先级降到原来的优先级(从OSEventCnt低8为得到)
443 if (OSTCBCur->OSTCBPrio == pip) {
444 //将调用本函数的任务从任务就绪表中pip位置上删除,放回到任务就绪表原来的优先级位置上
445 if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
446 OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
447 }
448 OSTCBCur->OSTCBPrio = prio; //当前任务块优先级=当前mutex的优先级
449 OSTCBCur->OSTCBY = prio >> 3; //取高3位优先级的值
450 OSTCBCur->OSTCBBitY = OSMapTbl[OSTCBCur->OSTCBY]; //对应的高3位OSMapTbl[]表值
451 OSTCBCur->OSTCBX = prio & 0x07; //取低3位优先级的值
452 OSTCBCur->OSTCBBitX = OSMapTbl[OSTCBCur->OSTCBX]; //对应低3位OSMapTbl[]表值
453 OSRdyGrp |= OSTCBCur->OSTCBBitY; //保存任务就绪标准0-7到OSRdyGrp
454 OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; //保存任务优先级别0-7到OSRdyTbl[]
455 //任务控制块优先级表=指向正在运行任务控制块的指针
456 OSTCBPrioTbl[prio] = (OS_TCB *)OSTCBCur;
457 }
458 OSTCBPrioTbl[pip] = (OS_TCB *)1; //确认占用mutex的任务是否PIP优先级进入就绪态
459 if (pevent->OSEventGrp != 0x00) { //查看是否有正在等待mutex的任务,不为0表示有
460 //将最高级的任务从等待mutex的任务列表中删除(OS_EventTaskRdy()使一个任务进入就绪态)
461 prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
462 //OSEventCnt:高8位是PIP值,低8位是无任占用务时为OxFF值,有任务占用时为任务优先级
463 pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; //新占用mutex的任务保存高8位(PIP)
464 pevent->OSEventCnt |= prio; //保存优先级
465 pevent->OSEventPtr = OSTCBPrioTbl[prio]; //mutex指针保存新任务控制块优先级
466 OS_EXIT_CRITICAL(); //打开中断
467 OS_Sched(); //进入调度任务,使就绪态优先级最高任务运行
468 return (OS_NO_ERR); //返回调用成功,mutex被释放
469 }
470 //如果没有等待mutex的任务,则OSEventCnt的低8位置为0xFF,表明mutex有效,立即可以
471 pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;
472 pevent->OSEventPtr = (void *)0; //mutex的指针在=0
473 OS_EXIT_CRITICAL(); //打开中断
474 return (OS_NO_ERR); //返回调用成功,mutex被释放
475 }
476 /*$PAGE*/
477 /*
478 *************************************************************************************************
479 * 得到mutex当前状态信息(QUERY A MUTUAL EXCLUSION SEMAPHORE)
480 *
481 * 描述: 得到mutex当前状态信息。应用程序必须给OS_MUTEX_DATA数据结构分配存储空间,这个数据结构用
482 * 于接受来自mutex的事件控制块的数据。通过调用OSMutexQuery()函数,得知
483 * mutex。计算在.OSEventTbl[]中有几个任务在等待mutex(计算有几个1),得到PIP的值,以及确认
484 * mutex是否可以使用(是1还是0)。
485 *
486 * 参数: pevent 指向管理某资源的互斥型信号量。程序在建立mutex时,得到该指针(参见OSMutexCreate())
487 *
488 * pdata 指向类型为OS_MUTEX_DATA的数据结构的指针。这个数据结构包括以下域:
489 * INT8U OSMutexPIP; // mutex的优先级继承优先级PIP;
490 * INT8U OSOwnerPrio; // 占用mutex任务的优先级
491 * INT8U OSValue; // 当前mutex的值。1表示可以使用,0表示不能使用;
492 * INT8U OSEventGrp; // 复制等待mutex的任务列表。
493 * INT8U OSEventTbl[OS_EVENT_TBL_SIZE] //容量大小由ucos_ii.H
494 *
495 * 返回: OS_NO_ERR 调用成功;
496 * OS_ERR_QUERY_ISR 试图在中断子程序中调用OSMutexQuery();
497 * OS_ERR_PEVENT_NULL 'pevent'是空指针;
498 * OS_ERR_EVENT_TYPE OSMutexQuery()不是指向mutex的指针.
499 *
500 * 注意:1) 必须先建立mutex,然后才能使用;
501 * 2) 在中断服务子程序中不能调用OSMutexPost()函数。
502 *************************************************************************************************
503 */
504
505 #if OS_MUTEX_QUERY_EN > 0 //允许生成 OSMutexQuery()代码
506 INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata)
507 { //查询一个互斥型信号量的当前状态(互斥型信号量指针、状态数据结构指针)
508 #if OS_CRITICAL_METHOD == 3 //中断函数被设定为模式3
509 OS_CPU_SR cpu_sr;
510 #endif
511 INT8U *psrc; //定义8位pevent->OSEventTbl[0]的地址指针
512 INT8U *pdest; //定义8位pdata->OSEventTbl[0]的地址指针
513
514
515 if (OSIntNesting > 0) { //中断嵌套数>0时,表示还有中断任务在运行
516 return (OS_ERR_QUERY_ISR); //错误等于(试图在中断子程序中调用OSMutexQuery())
517 }
518 #if OS_ARG_CHK_EN > 0 //所有参数在指定的范围之内
519 if (pevent == (OS_EVENT *)0) { //当互斥型信号量指针为NULL,即0(空)
520 return (OS_ERR_PEVENT_NULL); //event是空指针
521 }
522 if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { //当事件类型不否是互斥型信号量类型
523 return (OS_ERR_EVENT_TYPE); //OSMutexQuery()不是指向互斥型信号量的指针
524 }
525 #endif
526 OS_ENTER_CRITICAL(); //关闭中断
527 //将事件(互斥型信号量)结构中的等待任务列表复制到pdata数据结构中,计算在.OSEventTbl[]中有几个任务
528 //在等待mutex(计算有几个1),得到PIP的值,以及确认mutex是否可以使用(是1还是0)
529 pdata->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8);
530 pdata->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
531 //保存mutex的优先级继承优先级PIP
532 //保存占用mutex任务的优先级
533 if (pdata->OSOwnerPrio == 0xFF) { //如果占用mutex任务的优先级为255时
534 pdata->OSValue = 1; //当前mutex的值。1表示可以使用。
535 } else { //否则
536 pdata->OSValue = 0; //当前mutex的值。0表示不能使用。
537 } //将事件(互斥型信号量)结构中的等待任务列表复制到pdata数据结构中
538 pdata->OSEventGrp = pevent->OSEventGrp; //等待事件的任务组中的内容传送到状态数据结构中
539 psrc = &pevent->OSEventTbl[0]; //保存pevent->OSEventTbl[0]对应的地址
540 pdest = &pdata->OSEventTbl[0]; //保存pdata->OSEventTbl[0]对应的地址
541 #if OS_EVENT_TBL_SIZE > 0 //当事件就绪对应表中的对应值>0时
542 *pdest++ = *psrc++; //地址指针下移一个类型地址,获取互斥型信号量的值
543 #endif
544
545 #if OS_EVENT_TBL_SIZE > 1 //事件就绪对应表中的对应值>1时
546 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取互斥型信号量的值
547 #endif
548
549 #if OS_EVENT_TBL_SIZE > 2 //事件就绪对应表中的对应值>2时
550 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取互斥型信号量的值
551 #endif
552
553 #if OS_EVENT_TBL_SIZE > 3 //事件就绪对应表中的对应值>3时
554 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取互斥型信号量的值
555 #endif
556
557 #if OS_EVENT_TBL_SIZE > 4 //事件就绪对应表中的对应值>4时
558 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取互斥型信号量的值
559 #endif
560
561 #if OS_EVENT_TBL_SIZE > 5 //事件就绪对应表中的对应值>5时
562 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取互斥型信号量的值
563 #endif
564
565 #if OS_EVENT_TBL_SIZE > 6 //事件就绪对应表中的对应值>6时
566 *pdest++ = *psrc++; //地址指针继续下移一个类型地址,获取互斥型信号量的值
567 #endif
568
569 #if OS_EVENT_TBL_SIZE > 7 //事件就绪对应表中的对应值>7时
570 *pdest = *psrc; //获取最后地址的互斥型信号量的值
571 #endif
572 OS_EXIT_CRITICAL(); //打开中断
573 return (OS_NO_ERR); //返回成功运行
574 }
575 #endif //OS_SEM_QUERY_EN函数结束
576 #endif //OS_MUTEX_EN文件结束
577
OS_MUTEX.C
最新推荐文章于 2023-05-27 13:09:13 发布