OS_MUTEX.C

简介: 1 /*2 *************************************************************************************************3 * uC/OS-II实时控制内核4 * 互
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

目录
相关文章
Python线程锁(Thread Lock)和进程锁(Process Lock)
Python线程锁(Thread Lock)和进程锁(Process Lock)
|
3月前
|
存储 缓存 安全
C语言进程(第二章,wait,sleep,waitpid,pthread_mutex_lock,pthread_mutex_unlock)
C语言进程(第二章,wait,sleep,waitpid,pthread_mutex_lock,pthread_mutex_unlock)
29 0
|
7月前
|
C++
C++11/14/17中提供的mutex系列区别
C++11/14/17中提供的mutex系列类型如下:
|
Linux API
pthread_mutex_init & 互斥锁pthread_mutex_t的使用
pthread_mutex_init l         头文件: #include l         函数原型: int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; l         函数作用: 该函数用于C函数的多线程编程中,互斥锁的初始化。
1822 0
18.pthread POSIX线程
(创建于 2018/3/1 上午7:11:44) 查看pthread所有方法 man -k pthread 输出结果 pthread_attr_destroy (3) - initialize and destroy thread attribute...
976 0
|
Linux 计算机视觉 C++
linux C++ 多线程使用pthread_cond 条件变量
1. 背景 多线程中经常需要使用到锁(pthread_mutex_t)来完成多个线程之间的互斥操作。 但是互斥锁有一个明显到缺点: 只有两种状态,锁定和非锁定。 而条件变量则通过允许线程阻塞并等待另一个线程发送唤醒信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用。
1992 0