|
| 浅析μCOS/II v2.85内核OSMutexPend()和OSMutexPost()函数原理 |
| 新闻出处:21ic
发布时间: 2007-09-14 |
gliethttp 发布于 2007-9-14 8:20:00 浅析μCOS/II v2.85内核OSMutexPend()和OSMutexPost()函数工作原理
文章来源:http://gliethttp.cublog.cn[转载请声明出处]
//优先级翻转问题发生在>=3个进程同时访问一个共享的情况下, //所以至少有3个进程才有可能发生优先级翻转,即A>B>C时,B才可能将A翻转. //μCOS/II v2.85内核采用"变相置顶的方式"来解决优先级翻转问题,
//"优先级继承方式"是指一个较高优先级的任务申请某信号量,但此信号量已被一个较低优先级的任务占有,这时,抬升较低优先级任务的优先级到较高优先级任务的优先级,这是一个自动过程. //"置顶方式"是指一旦有进程访问互斥资源,立即把该进程的优先级提升到置顶值.
//"变相置顶的方式"是指我们根据工程应用任务需要,自己内定一个最高优先级,结合优先级继承方式,根据情况来判断当前task进程优先级是否需要抬升到置顶值. //这个最高优先级可能不是0,比如可能是5(5空闲,不能用于创建其他任务),原因是0~4,之间的任务不会访问互斥空间, //仅仅优先级>=6的进程才会访问互斥空间,这时5就是所谓的A,假如优先级为10的进程要访问互斥空间, //这时因为没有任何进程访问互斥空间,所以10作为pevent->OSEventCnt的低8位值,被保存,之后持有 //互斥空间的操作权利,此时优先级为12的进程也要访问互斥空间,因为12处于C的角色,所以不会发生优先级翻转, //12将直接被悬停在Mutexevent事件控制矩阵上,之后8打算访问互斥资源空间, //那么,因为8处于B的角色,这时10需要提升自己到这个所谓的"顶"--优先级5, //这样,以后所有访问互斥资源的进程都因为优先级小于5而直接悬停在Mutexevent事件控制矩阵上, //不会出现因为6、7、8悬停在Mutexevent事件控制矩阵上,而此时9因为获得cpu执行权, //而抢占了10的执行,进而发生优先级翻转现象.[gliethttp] //但是如果真的0~4中的某个进程不守规矩,贸然访问了共享资源,会发生什么呢,让我们来看看: //如2要访问资源,那么2一定是直接悬停在事件控制矩阵上,直到已经提升优先级或未提升优先级的占用互斥资源空间 //的进程退出,重新计算悬停在事件控制矩阵上的优先级最高的任务的时候,2将会被加入到就绪控制矩阵中,等待cpu //调度,进而占用互斥资源,这好像也没有问题,那么继续进行假设,如果4优先级在操作互斥资源,此时2打算操作, //那么2需要等待,被添加到了mutex事件控制矩阵中,这时就那么巧,3又获得了cpu的使用权,那么优先级4将被3抢占 //所以出现了优先级翻转现象--3把2给翻转了,所以对于优先级高于内定置顶值pip的进程访问互斥资源时, //并不能受到mutex互斥保护机制的保护,所以对于这些进程,他们可能会发生优先级翻转,也可能不会. //因此,这使我们更坚定一点,不要存在侥幸心里,踏踏实实的把pip设置成真正的"置顶"值.[gliethttp] //---------------------------------------------------------------------- //1.OSMutexPend()函数 void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *perr) { INT8U pip; INT8U mprio; BOOLEAN rdy; OS_TCB *ptcb; OS_EVENT *pevent2; INT8U y; INT8U pend_stat; #if OS_CRITICAL_METHOD == 3 OS_CPU_SR cpu_sr = 0; #endif
#if OS_ARG_CHK_EN > 0 if (perr == (INT8U *)0) { return; } if (pevent == (OS_EVENT *)0) { *perr = OS_ERR_PEVENT_NULL; return; } #endif if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { //确保该event控制块是Mutex类型 *perr = OS_ERR_EVENT_TYPE; return; } if (OSIntNesting > 0) { //ISR中,不能使用OSMboxPend() *perr = OS_ERR_PEND_ISR; return; } if (OSLockNesting > 0) { //μCOS/II v2.85内核已经被强制锁住 *perr = OS_ERR_PEND_LOCKED; return; } //非法的统统不是,信号正常,所以有必要进一步处理 OS_ENTER_CRITICAL(); //在OSMutexCreate()中 //#define OS_MUTEX_AVAILABLE (INT16U)0x00FFu //pevent->OSEventCnt = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE; //prio为一个空闲的优先级号,没有task使用该prio[gliethttp] pip = (INT8U)(pevent->OSEventCnt >> 8);//变相置顶值pip if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) { //当前没有其他进程使用OSMutexPend()占有共享资源, //所以task将要成为当前唯一占用共享资源的进程,pevent->OSEventCnt的低8位存放 //当前正在使用共享资源task的prio优先级值, //pip=pevent->OSEventCnt的高8位存放 //"变相置顶"--所谓的最高优先级值pip(访问互斥资源的所有进程的优先级都比该pip低) //通过提升到这个所谓的顶,来解决优先级翻转问题[gliethttp] pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; pevent->OSEventPtr = (void *)OSTCBCur; if (OSTCBCur->OSTCBPrio <= pip) { //因为pip是置顶优先级,所以pip必须是所有能够访问互斥资源的进程中优先级最高的[gliethttp] //如果低,那么这时mutex互斥机制失效,mutex不起作用了 OS_EXIT_CRITICAL(); *perr = OS_ERR_PIP_LOWER; } else { OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; } return; } //2007-09-09 gliethttp //说明已经有一个task占用了共享资源,持有共享互斥锁Mutex了,如下做进一步处理 mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); ptcb = (OS_TCB *)(pevent->OSEventPtr); //2007-09-09 gliethttp //[注:未提升优先级之前ptcb->OSTCBPrio等于mprio,提升之后ptcb->OSTCBPrio等于pip(置顶优先级)] //因为μCOS/II v2.85内核采用"变相置顶的方式"来解决优先级翻转问题,所以pip就是A; //所以在工程应用上有这样一个限制,能够访问互斥空间的所有进程优先级都要低于这个pip, //优先级高于pip的进程不能访问,互斥空间,所以这也就要求,我们指定的pip的优先级必须保证, //大于所有能访问互斥空间的进程,[gilethttp] //只有低于pip优先级的进程才能够受"资源互斥机制"的保护【这就是μCOS/II v2.85内核优先级翻转的局限之处】 //但是,这在实际的工程应用中是可以接受的. //优先级A>B>C时,B可能引起优先级翻转,所以下面检测OSTCBCur->OSTCBPrio是否处于B的角色 //如果是,那么需要提升C的优先级,否则不会发生优先级翻转[gliethttp] if (ptcb->OSTCBPrio > pip) { //说明ptcb->OSTCBPrio还没有提升到所谓的最高优先级pip, //否则ptcb->OSTCBPrio将等于pip[gliethttp] //如果mprio < OSTCBCur->OSTCBPrio说明,当前持有mutex资源的task处于B的角色 if (mprio > OSTCBCur->OSTCBPrio) { //这时OSTCBCur->OSTCBPrio处于B的角色,那么可能会发生优先级翻转, //因为可能,所以程序肯定会照着最坏的情况考虑,使用"变相置顶的方式",提升当前持有互斥资源的task的优先级 //到达这个所谓的"顶"--pip. y = ptcb->OSTCBY; if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0) { //如果A已经在就绪控制矩阵中,那么把A从就绪控制矩阵中摘下[gliethttp] //具体参考《浅析μCOS/II v2.85内核OSMboxPend()和OSMboxPost()函数工作原理》 OSRdyTbl[y] &= ~ptcb->OSTCBBitX; if (OSRdyTbl[y] == 0) { OSRdyGrp &= ~ptcb->OSTCBBitY; } rdy = OS_TRUE;//task处于就绪状态 } else { pevent2 = ptcb->OSTCBEventPtr; if (pevent2 != (OS_EVENT *)0) { if ((pevent2->OSEventTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0) { //如果A已经在事件控制矩阵中,那么把A从事件控制矩阵中摘下[gliethttp] //具体参考《浅析μCOS/II v2.85内核OSMboxPend()和OSMboxPost()函数工作原理》 pevent2->OSEventGrp &= ~ptcb->OSTCBBitY; } } rdy = OS_FALSE;//task处于事件等待状态 } ptcb->OSTCBPrio = pip;//将task优先级置顶到pip #if OS_LOWEST_PRIO <= 63 //对于64个tasks配置 //重新就绪控制矩阵和事件控制矩阵中使用到(x,y)值 ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3); ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07); ptcb->OSTCBBitY = (INT8U)(1 << ptcb->OSTCBY); ptcb->OSTCBBitX = (INT8U)(1 << ptcb->OSTCBX); #else //对于255个tasks配置 //重新计算就绪控制矩阵和事件控制矩阵中使用到(x,y)值 ptcb->OSTCBY = (INT8U)((ptcb->OSTCBPrio >> 4) & 0xFF); ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0F); ptcb->OSTCBBitY = (INT16U)(1 << ptcb->OSTCBY); ptcb->OSTCBBitX = (INT16U)(1 << ptcb->OSTCBX); #endif if (rdy == OS_TRUE) { //提升优先级之前该task处于就绪控制矩阵中,等待cpu调度 OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { //提升优先级之前该task处于事件控制矩阵中,等待事件的到来 //需要说明一点,一个task只有两种状态, //1.要么在就绪控制矩阵中等待被cpu调度 //2.要么阻塞在事件控制矩阵中[gliethttp] pevent2 = ptcb->OSTCBEventPtr; if (pevent2 != (OS_EVENT *)0) { pevent2->OSEventGrp |= ptcb->OSTCBBitY; pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } } OSTCBPrioTbl[pip] = ptcb;//添加新pip优先级下的TCB } } OSTCBCur->OSTCBStat |= OS_STAT_MUTEX;//是Mutex事件让本task进入悬停等待的 OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;//假定不是超时,为正常收到信号 //超时,如果timeout=0,那么,本task将一直悬停,仅仅当收到事件触发信号后才重新进入调度队列 OSTCBCur->OSTCBDly = timeout; //OS_EventTaskWait()函数实现的功能: //把本task从就绪控制矩阵中摘下,放到pevent事件专有的进程事件控制矩阵表中. OS_EventTaskWait(pevent); OS_EXIT_CRITICAL(); //因为本task正在运行,所以本task现在的优先级最高的,现在本task已经将自己从就绪控制矩阵--调度器(x,y)矩形阵列中 //把自己摘掉,所以调度函数OS_Sched()一定会切换到另一个task中执行新task的代码[gliethttp] OS_Sched();//具体参见《浅析μC/OS-II v2.85内核调度函数》 OS_ENTER_CRITICAL(); //2007-09-09 gliethttp //可能因为OSMutexPend()中指定的timeout已经超时 //[由OSTimeTick()函数把本task重新置入了就绪队列,具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》], //又或者确实在应用程序的某个地方调用了OSMutexPost(),以下代码将具体解析是有什么引起的:1.超时,2.收到正常信号 if (OSTCBCur->OSTCBStatPend != OS_STAT_PEND_OK) { //是因为timeout超时,使得本task获得重新执行的机会 pend_stat = OSTCBCur->OSTCBStatPend; //清除event事件块上本task的标志 OS_EventTOAbort(pevent); OS_EXIT_CRITICAL(); switch (pend_stat) { case OS_STAT_PEND_TO: default: *perr = OS_ERR_TIMEOUT; break; case OS_STAT_PEND_ABORT: *perr = OS_ERR_PEND_ABORT; break; } return; } //由OSMutexPost()抛出正常事件,唤醒了本task,因为在OSMutexPost()时, //已经将本task在event事件控制矩阵上的对应位清除掉,并且把本task放入了就绪控制矩阵中, //否则本task也不会执行至此. OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; OS_EXIT_CRITICAL(); *perr = OS_ERR_NONE; } //---------------------------------------------------------------------- //2.OS_EventTaskWait()函数 void OS_EventTaskWait (OS_EVENT *pevent) { INT8U y; //2007-09-09 gliethttp //pevent为此次task挂起的EventPtr单元 OSTCBCur->OSTCBEventPtr = pevent; //清除调度器中该task对应的标志位 y = OSTCBCur->OSTCBY; OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX; if (OSRdyTbl[y] == 0) { //当前y行对应的8个或16个task都已经悬停,那么当前y行也清除. OSRdyGrp &= ~OSTCBCur->OSTCBBitY; } //2007-09-09 gliethttp //将该task的prio添加到pevent事件控制矩阵中,这个矩阵的功能和OSRdyGrp、OSRdyTbl就绪控制矩阵没有区别 //都是用来计算出已经就绪tasks中的优先级最高的那个 pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; pevent->OSEventGrp |= OSTCBCur->OSTCBBitY; } //---------------------------------------------------------------------- //3.OS_EventTOAbort()函数 void OS_EventTOAbort (OS_EVENT *pevent) { INT8U y; //清除event事件控制矩阵上本task的标志,因为OSTimeTick()函数未清除该单元 //它仅仅把本task放入就绪控制矩阵,使得本task重新获得被OS调度的机会而已 //具体的清除工作还要自己完成 //具体参考《浅析μC/OS-II v2.85内核OSTimeDly()函数工作原理》 y = OSTCBCur->OSTCBY; pevent->OSEventTbl[y] &= ~OSTCBCur->OSTCBBitX; if (pevent->OSEventTbl[y] == 0x00) { pevent->OSEventGrp &= ~OSTCBCur->OSTCBBitY; } OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; OSTCBCur->OSTCBStat = OS_STAT_RDY; OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;//现在本task不悬停在任何event事件上 } //---------------------------------------------------------------------- //4.OSMutexPost()函数 ..................................
|
| 【关闭】 【打印】 |
|
|
|
|