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