UCOSII学习之路3 -任务同步之互斥
来源:互联网 发布:painter中文版mac 编辑:程序博客网 时间:2024/05/19 16:04
上一节我们引入了信号量的概念,这一讲我们将揭晓互斥信号量的奥秘。
互斥信号量和信号量虽然都带了信号量的帽子,但是二者却有着不同的运用场合,互斥信号量相比而言经常用于一些资源的互斥访问,比如打印机、厕所等,这里的厕所指的是单厕,哈哈哈。这样有的人就要问了,那信号量设置起始cnt为1不也可以实现资源的互斥访问吗,这样的话我们直接使用信号量的实现不就可以了吗?答案当然是否认的,作为OS的开发者,哪些大咖们怎么可能没有想到这些问题。-----为了解决在信号量使用过程中一些任务的优先级反转问题(就是低优先级抢占CPU在高优先级任务前得到运行的现象),于是乎给信号量来了一个优先级提升,但凡低优先级任务抢占CPU后,如果后面来了一个高优先级任务申请该"信号量",那么低优先级任务将被提升到所有任务中最高优先级来保证"信号量"可以尽早的得到释放。然后就成了我们今天要谈的互斥信号量。
首先来看看互斥信号量在事件控制块的基础上使用了哪些资源。
从图中 可以看出,OSEventType用于指示资源的类型,而对于,其实OSEventCnt的高八位用于存放提升后的优先级,而前面则用于指示资源的状态,以及在优先级提升后短暂的存放开始的任务优先级,后两个OSEventGrp和OSEventTbl[]在任何一种类型的等待事件过程中都会使用,我们不讲,那我们就来说说OSEventPtr,很多人都任务在互斥里边他没有被使用,直接指向NULL,其实不然,他其实指向了任务的TCB。
互斥信号量的操作一共6个函数
OS_EVENT *OSMutexCreate(INT8U prio, INT8U *perr); //互斥信号量的创建
void OSMutexPend (OS_EVENT *pevent, INT32U timeout, INT8U *perr);//挂起
INT8U OSMutexPost (OS_EVENT *pevent);//释放
BOOLEAN OSMutexAccept (OS_EVENT *pevent, INT8U *perr);//无等待挂起
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *perr);//删除互斥量
INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data);//查询
一个内部函数
static void OSMutex_RdyAtPrio (OS_TCB *ptcb, INT8U prio);
其通讯机理如下图
好了 相信大家对互斥信号量有了一个初步的认识。那我们继续
与以往相同,我们来分析分析这些函数的内部实现
[cpp] view plain copy
- OS_EVENT *OSMutexCreate (INT8U prio,
- INT8U *perr)
- {
- OS_EVENT *pevent;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return ((OS_EVENT *)0);
- }
- #endif
- #ifdef OS_SAFETY_CRITICAL_IEC61508
- if (OSSafetyCriticalStartFlag == OS_TRUE) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return ((OS_EVENT *)0);
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (prio != OS_PRIO_MUTEX_CEIL_DIS) { //Prio安全范围检测,其可通过OS_PRIO_MUTEX_CEIL_DIS来失能
- if (prio >= OS_LOWEST_PRIO) { /* Validate PCP */
- *perr = OS_ERR_PRIO_INVALID;
- return ((OS_EVENT *)0);
- }
- }
- #endif
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- *perr = OS_ERR_CREATE_ISR; /* ... can't CREATE mutex from an ISR */
- return ((OS_EVENT *)0);
- }
- OS_ENTER_CRITICAL();
- if (prio != OS_PRIO_MUTEX_CEIL_DIS) { //
- if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { //检查提升的优先级是否占用
- OS_EXIT_CRITICAL(); /* Task already exist at priority ... */
- *perr = OS_ERR_PRIO_EXIST;
- return ((OS_EVENT *)0);
- }
- OSTCBPrioTbl[prio] = OS_TCB_RESERVED; //没有被占用 将保留 */
- }
- pevent = OSEventFreeList; /* Get next free event control block */
- if (pevent == (OS_EVENT *)0) { //事件控制块资源耗尽
- if (prio != OS_PRIO_MUTEX_CEIL_DIS) { //
- OSTCBPrioTbl[prio] = (OS_TCB *)0; //释放占用的TCB优先级资源
- }
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_PEVENT_NULL; /* No more event control blocks */
- return (pevent);
- }
- OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* Adjust the free list */
- OS_EXIT_CRITICAL();
- pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
- pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE;// 将提升的优先级放到cnt的高八位
- pevent->OSEventPtr = (void *)0; /* No task owning the mutex */
- #if OS_EVENT_NAME_EN > 0u
- pevent->OSEventName = (INT8U *)(void *)"?";
- #endif
- OS_EventWaitListInit(pevent);//初始化事件等待list
- *perr = OS_ERR_NONE;
- return (pevent);
- }
[cpp] view plain copy
- void OSMutexPend (OS_EVENT *pevent,
- INT32U timeout,
- INT8U *perr)
- {
- INT8U pcp; /* Priority Ceiling Priority (PCP) */
- INT8U mprio; /* Mutex owner priority */
- BOOLEAN rdy; /* Flag indicating task was ready */
- OS_TCB *ptcb;
- OS_EVENT *pevent2;
- INT8U y;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return;
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return;
- }
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
- return;
- }
- if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */
- *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
- return;
- }
- /*$PAGE*/ //前面全部是一些参数的范围检查之类的我们不做解释
- OS_ENTER_CRITICAL();
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */
- /* Is Mutex available? */
- if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) { //表明当前资源未被占用
- pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; //设置资源被占用
- pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; //将原优先级保存到cnt低八位
- pevent->OSEventPtr = (void *)OSTCBCur; //指向提升前的TCB块
- if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
- (OSTCBCur->OSTCBPrio <= pcp)) { //进入表示允许优先级提升
- OS_EXIT_CRITICAL(); /* ... than current task! */
- *perr = OS_ERR_PCP_LOWER; //提升优先级失败,原因在于提升后的优先级<当前优先级
- } else {
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- }
- return;
- } //以上为资源没有被占用的情况
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); //获取原优先级
- ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
- if (ptcb->OSTCBPrio > pcp) { //当提升优先级高于原优先级
- if (mprio > OSTCBCur->OSTCBPrio) { //同时当前申请互斥资源的任务优先级高于原优先级,将实现优先级提升
- y = ptcb->OSTCBY; //获取以前优先级的组号
- if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) { //存在就绪任务
- OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/
- if (OSRdyTbl[y] == 0u) { /* ... list at current prio */
- OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
- }
- rdy = OS_TRUE; //清除就绪标志 并设立标志
- } else {
- pevent2 = ptcb->OSTCBEventPtr;
- if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */
- y = ptcb->OSTCBY;
- pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
- if (pevent2->OSEventTbl[y] == 0u) {
- pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
- }
- }
- rdy = OS_FALSE; /* No */
- }
- ptcb->OSTCBPrio = pcp; //提升原优先级为pcp
- #if OS_LOWEST_PRIO <= 63u
- ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u);
- ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u);
- #else
- ptcb->OSTCBY = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);
- ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);
- #endif
- ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
- ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
- if (rdy == OS_TRUE) { //完成未完成前任务的就绪状态
- OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */
- OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- } else {
- pevent2 = ptcb->OSTCBEventPtr;
- if (pevent2 != (OS_EVENT *)0) { /* Add to event wait list */
- pevent2->OSEventGrp |= ptcb->OSTCBBitY;
- pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- }
- }
- OSTCBPrioTbl[pcp] = ptcb; //写入优先级组
- }
- }
- }
- OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */
- OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
- OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */
- OS_EventTaskWait(pevent); //挂起本任务
- OS_EXIT_CRITICAL();
- OS_Sched(); //任务调度,当占有资源释放时执行以下内容
- OS_ENTER_CRITICAL();
- switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
- case OS_STAT_PEND_OK:
- *perr = OS_ERR_NONE;
- break;
- case OS_STAT_PEND_ABORT:
- *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted getting mutex */
- break;
- case OS_STAT_PEND_TO:
- default:
- OS_EventTaskRemove(OSTCBCur, pevent);
- *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get mutex within TO */
- break;
- }
- OSTCBCur->OSTCBStat = OS_STAT_RDY; //任务等待资源完成
- OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
- OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
- #if (OS_EVENT_MULTI_EN > 0u)
- OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
- #endif
- OS_EXIT_CRITICAL();
- }
本函数稍稍复杂一点,其实也比较简单,他的功能主要考虑四种情况:
1、不执行优先级提升时,资源不占用。
这种比较简单,也是执行时间最短的及最快的,任务直接抢占资源并返回。
2、不执行优先级提升,资源被占用。
这种也简单,如果是这种情况的话,互斥信号量操作和信号量完全一样。基本是等号。
3、执行提升时资源不占用
这种也是执行最快的,资源直接占用并返回。
4、提升时资源被占用
这个就是核心了,也是互斥信号量最难以理解的地方,他处理的情况也分为2种,
1>让资源被占用,后申请资源的任务优先级高于正在占用任务的优先级,执行优先级提升,因为这将会导致优先级反转,这也是互斥信号量为解决优先级反转而引入的概念。
2>当其优先级低于正在占用任务的优先级,类型不会被提升,操作如信号量
有的朋友可能会有这样的疑问,执行类型提升后,那么原来的优先级资源如何处理,其实UCOSII对其基本未处理,只是将该任务的Prio赋值到一个较高的水平,而原Prio此时将一直被占用,并同样保存了一个指向该任务TCB的指针。
[cpp] view plain copy
- BOOLEAN OSMutexAccept (OS_EVENT *pevent,
- INT8U *perr)
- {
- INT8U pcp; /* Priority Ceiling Priority (PCP) */
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return (OS_FALSE);
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return (OS_FALSE);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return (OS_FALSE);
- }
- if (OSIntNesting > 0u) { /* Make sure it's not called from an ISR */
- *perr = OS_ERR_PEND_ISR;
- return (OS_FALSE);
- }
- OS_ENTER_CRITICAL(); /* Get value (0 or 1) of Mutex */
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */
- if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
- pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Mask off LSByte (Acquire Mutex) */
- pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save current task priority in LSByte */
- pevent->OSEventPtr = (void *)OSTCBCur; /* Link TCB of task owning Mutex */
- if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
- (OSTCBCur->OSTCBPrio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
- OS_EXIT_CRITICAL(); /* ... than current task! */
- *perr = OS_ERR_PCP_LOWER;
- } else {
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- }
- return (OS_TRUE);
- } //其实以上的内容和OSMutexPend都是一样的,我们不做即使
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- return (OS_FALSE);
- }
相信看完OSMutexPend()函数的朋友再来理解该函数是不是感觉就太简单了,他们仅有的区别在于,一个执行完,如果资源被占用将被挂起,而另一个会直接返回。
[cpp] view plain copy
- INT8U OSMutexPost (OS_EVENT *pevent)
- {
- INT8U pcp; /* Priority ceiling priority */
- INT8U prio;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */
- }
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- return (OS_ERR_PEVENT_NULL);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- return (OS_ERR_EVENT_TYPE);
- }
- OS_ENTER_CRITICAL();
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); // 获取PCP优先级
- prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); //获取原优先级
- if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */
- OS_EXIT_CRITICAL();
- return (OS_ERR_NOT_MUTEX_OWNER);//互斥信号量错误
- }
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- if (OSTCBCur->OSTCBPrio == pcp) { /* Did we have to raise current task's priority? */
- OSMutex_RdyAtPrio(OSTCBCur, prio); //恢复原优先级
- }
- OSTCBPrioTbl[pcp] = OS_TCB_RESERVED; //OS_TCB_RESERVED=1
- }
- if (pevent->OSEventGrp != 0u) { /* Any task waiting for the mutex? */
- /* Yes, Make HPT waiting for mutex ready */
- prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
- pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */
- pevent->OSEventCnt |= prio;
- pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to new mutex owner's OS_TCB */
- if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
- (prio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
- OS_EXIT_CRITICAL(); /* ... than current task! */
- OS_Sched(); /* Find highest priority task ready to run */
- return (OS_ERR_PCP_LOWER);
- } else {
- OS_EXIT_CRITICAL();
- OS_Sched(); /* Find highest priority task ready to run */
- return (OS_ERR_NONE);
- }
- }
- pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */
- pevent->OSEventPtr = (void *)0;
- OS_EXIT_CRITICAL();
- return (OS_ERR_NONE);
- }
- //以上主要是恢复原优先级,并并将占用的资源释放
- OS_EVENT *OSMutexDel (OS_EVENT *pevent,
- INT8U opt,
- INT8U *perr)
- {
- BOOLEAN tasks_waiting;
- OS_EVENT *pevent_return;
- INT8U pcp; /* Priority ceiling priority */
- INT8U prio;
- OS_TCB *ptcb;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return ((OS_EVENT *)0);
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return (pevent);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return (pevent);
- }
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
- return (pevent);
- }
- OS_ENTER_CRITICAL();
- if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on mutex */
- tasks_waiting = OS_TRUE; /* Yes */
- } else {
- tasks_waiting = OS_FALSE; /* No */
- }
- switch (opt) { //opt为删除类型
- case OS_DEL_NO_PEND: //任务没有挂起的时候删除互斥信号 /* DELETE MUTEX ONLY IF NO TASK WAITING --- */
- if (tasks_waiting == OS_FALSE) {
- #if OS_EVENT_NAME_EN > 0u
- pevent->OSEventName = (INT8U *)(void *)"?";
- #endif
- pcp = (INT8U)(pevent->OSEventCnt >> 8u);
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- OSTCBPrioTbl[pcp] = (OS_TCB *)0; //释放占用的PCP提升资源 */
- }
- pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
- pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
- pevent->OSEventCnt = 0u;
- OSEventFreeList = pevent;//重新将互斥量链接到空闲表
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
- } else {
- OS_EXIT_CRITICAL(); //存在将返回错误,此时不能删除
- *perr = OS_ERR_TASK_WAITING;
- pevent_return = pevent;
- }
- break;
- case OS_DEL_ALWAYS: //总是删除互斥量 /* ALWAYS DELETE THE MUTEX ---------------- */
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP of mutex */
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's orig prio */
- ptcb = (OS_TCB *)pevent->OSEventPtr;
- if (ptcb != (OS_TCB *)0) { /* See if any task owns the mutex */
- if (ptcb->OSTCBPrio == pcp) { /* See if original prio was changed */
- OSMutex_RdyAtPrio(ptcb, prio); /* Yes, Restore the task's original prio */
- }
- }
- }
- //别占用的资源强制释放
- while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for mutex */
- (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_ABORT);
- }
- #if OS_EVENT_NAME_EN > 0u
- pevent->OSEventName = (INT8U *)(void *)"?";
- #endif
- pcp = (INT8U)(pevent->OSEventCnt >> 8u);
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- OSTCBPrioTbl[pcp] = (OS_TCB *)0; /* Free up the PCP */
- }
- pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
- pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
- pevent->OSEventCnt = 0u;
- OSEventFreeList = pevent; /* Get next free event control block */
- OS_EXIT_CRITICAL();
- if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
- OS_Sched(); //存在就绪任务将开展调度 /* Find highest priority task ready to run */
- }
- *perr = OS_ERR_NONE;
- pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
- break;
- default:
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_INVALID_OPT; //无效opt输入
- pevent_return = pevent;
- break;
- }
- return (pevent_return); //返回删除的互斥量地址
- }
该任务主要是删除一个互斥量。
1、不占用任务删除类型:互斥量将在没有任务挂起时删除
2、总是删除类型:互斥量将总是删除任务,当存在任务挂起时将强制就绪释放
[cpp] view plain copy
- INT8U OSMutexQuery (OS_EVENT *pevent,
- OS_MUTEX_DATA *p_mutex_data)
- {
- INT8U i;
- OS_PRIO *psrc;
- OS_PRIO *pdest;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- return (OS_ERR_QUERY_ISR); /* ... can't QUERY mutex from an ISR */
- }
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- return (OS_ERR_PEVENT_NULL);
- }
- if (p_mutex_data == (OS_MUTEX_DATA *)0) { /* Validate 'p_mutex_data' */
- return (OS_ERR_PDATA_NULL);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- return (OS_ERR_EVENT_TYPE);
- }
- OS_ENTER_CRITICAL();
- p_mutex_data->OSMutexPCP = (INT8U)(pevent->OSEventCnt >> 8u);
- p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
- if (p_mutex_data->OSOwnerPrio == 0xFFu) {
- p_mutex_data->OSValue = OS_TRUE; //查看资源是否被占用
- } else {
- p_mutex_data->OSValue = OS_FALSE;
- }
- p_mutex_data->OSEventGrp = pevent->OSEventGrp; /* Copy wait list */
- psrc = &pevent->OSEventTbl[0];
- pdest = &p_mutex_data->OSEventTbl[0];
- for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { //执行数据拷贝
- *pdest++ = *psrc++;
- }
- OS_EXIT_CRITICAL();
- return (OS_ERR_NONE);
- }
- //该函数比较简单,直接拷贝pevent信息到p_mutex_data数据结构中。
- static void OSMutex_RdyAtPrio (OS_TCB *ptcb,
- INT8U prio)
- {
- INT8U y;
- y = ptcb->OSTCBY; /* Remove owner from ready list at 'pcp' */
- OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; //清除原就绪标志
- if (OSRdyTbl[y] == 0u) {
- OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
- }
- ptcb->OSTCBPrio = prio;
- OSPrioCur = prio; /* The current task is now at this priority */
- #if OS_LOWEST_PRIO <= 63u
- ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 3u) & 0x07u);
- ptcb->OSTCBX = (INT8U)(prio & 0x07u);
- #else
- ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0x0Fu);
- ptcb->OSTCBX = (INT8U) (prio & 0x0Fu);
- #endif
- ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); //在新的优先级上就绪任务
- ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
- OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready at original priority */
- OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- OSTCBPrioTbl[prio] = ptcb;
- }
该函数主要是将一个任务优先级提升到prio层次,并将提升后的任务就绪。
到这里,互斥信号量的源码分析也就结束了,总结一点,互斥信号量和信号量其实大同小异,当然这是考虑信号量在只有一个时(及cnt=1)的情况,二者仅有的区别在于互斥信号量可以有效地防止优先级反转,而这在一些安全相关的系统中将是至关重要的。因此在处理对任务顺序较为敏感的任务的时候,需要使用互斥量来防止反转,增加系统的可预测性。
好了,互斥量就讲到这里
时间:170708
[cpp] view plain copy
- void OSMutexPend (OS_EVENT *pevent,
- INT32U timeout,
- INT8U *perr)
- {
- INT8U pcp; /* Priority Ceiling Priority (PCP) */
- INT8U mprio; /* Mutex owner priority */
- BOOLEAN rdy; /* Flag indicating task was ready */
- OS_TCB *ptcb;
- OS_EVENT *pevent2;
- INT8U y;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return;
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return;
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return;
- }
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- *perr = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
- return;
- }
- if (OSLockNesting > 0u) { /* See if called with scheduler locked ... */
- *perr = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
- return;
- }
- /*$PAGE*/ //前面全部是一些参数的范围检查之类的我们不做解释
- OS_ENTER_CRITICAL();
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */
- /* Is Mutex available? */
- if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) { //表明当前资源未被占用
- pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; //设置资源被占用
- pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; //将原优先级保存到cnt低八位
- pevent->OSEventPtr = (void *)OSTCBCur; //指向提升前的TCB块
- if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
- (OSTCBCur->OSTCBPrio <= pcp)) { //进入表示允许优先级提升
- OS_EXIT_CRITICAL(); /* ... than current task! */
- *perr = OS_ERR_PCP_LOWER; //提升优先级失败,原因在于提升后的优先级<当前优先级
- } else {
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- }
- return;
- } //以上为资源没有被占用的情况
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); //获取原优先级
- ptcb = (OS_TCB *)(pevent->OSEventPtr); /* Point to TCB of mutex owner */
- if (ptcb->OSTCBPrio > pcp) { //当提升优先级高于原优先级
- if (mprio > OSTCBCur->OSTCBPrio) { //同时当前申请互斥资源的任务优先级高于原优先级,将实现优先级提升
- y = ptcb->OSTCBY; //获取以前优先级的组号
- if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) { //存在就绪任务
- OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; /* Yes, Remove owner from Rdy ...*/
- if (OSRdyTbl[y] == 0u) { /* ... list at current prio */
- OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
- }
- rdy = OS_TRUE; //清除就绪标志 并设立标志
- } else {
- pevent2 = ptcb->OSTCBEventPtr;
- if (pevent2 != (OS_EVENT *)0) { /* Remove from event wait list */
- y = ptcb->OSTCBY;
- pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
- if (pevent2->OSEventTbl[y] == 0u) {
- pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
- }
- }
- rdy = OS_FALSE; /* No */
- }
- ptcb->OSTCBPrio = pcp; //提升原优先级为pcp
- #if OS_LOWEST_PRIO <= 63u
- ptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u);
- ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u);
- #else
- ptcb->OSTCBY = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);
- ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);
- #endif
- ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
- ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
- if (rdy == OS_TRUE) { //完成未完成前任务的就绪状态
- OSRdyGrp |= ptcb->OSTCBBitY; /* ... make it ready at new priority. */
- OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- } else {
- pevent2 = ptcb->OSTCBEventPtr;
- if (pevent2 != (OS_EVENT *)0) { /* Add to event wait list */
- pevent2->OSEventGrp |= ptcb->OSTCBBitY;
- pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- }
- }
- OSTCBPrioTbl[pcp] = ptcb; //写入优先级组
- }
- }
- }
- OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* Mutex not available, pend current task */
- OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;
- OSTCBCur->OSTCBDly = timeout; /* Store timeout in current task's TCB */
- OS_EventTaskWait(pevent); //挂起本任务
- OS_EXIT_CRITICAL();
- OS_Sched(); //任务调度,当占有资源释放时执行以下内容
- OS_ENTER_CRITICAL();
- switch (OSTCBCur->OSTCBStatPend) { /* See if we timed-out or aborted */
- case OS_STAT_PEND_OK:
- *perr = OS_ERR_NONE;
- break;
- case OS_STAT_PEND_ABORT:
- *perr = OS_ERR_PEND_ABORT; /* Indicate that we aborted getting mutex */
- break;
- case OS_STAT_PEND_TO:
- default:
- OS_EventTaskRemove(OSTCBCur, pevent);
- *perr = OS_ERR_TIMEOUT; /* Indicate that we didn't get mutex within TO */
- break;
- }
- OSTCBCur->OSTCBStat = OS_STAT_RDY; //任务等待资源完成
- OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /* Clear pend status */
- OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* Clear event pointers */
- #if (OS_EVENT_MULTI_EN > 0u)
- OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
- #endif
- OS_EXIT_CRITICAL();
- }
本函数稍稍复杂一点,其实也比较简单,他的功能主要考虑四种情况:
1、不执行优先级提升时,资源不占用。
这种比较简单,也是执行时间最短的及最快的,任务直接抢占资源并返回。
2、不执行优先级提升,资源被占用。
这种也简单,如果是这种情况的话,互斥信号量操作和信号量完全一样。基本是等号。
3、执行提升时资源不占用
这种也是执行最快的,资源直接占用并返回。
4、提升时资源被占用
这个就是核心了,也是互斥信号量最难以理解的地方,他处理的情况也分为2种,
1>让资源被占用,后申请资源的任务优先级高于正在占用任务的优先级,执行优先级提升,因为
这将会导致优先级反转,这也是互斥信号量为解决优先级反转而引入的概念。
2>当其优先级低于正在占用任务的优先级,类型不会被提升,操作如信号量
有的朋友可能会有这样的疑问,执行类型提升后,那么原来的优先级资源如何处理,其实UCOSII对其基本未处理,只是将该任务的Prio赋值到一个较高的水平,而原Prio此时将一直被占用,并同样保存了一个指向该任务TCB的指针。
[cpp] view plain copy
- BOOLEAN OSMutexAccept (OS_EVENT *pevent,
- INT8U *perr)
- {
- INT8U pcp; /* Priority Ceiling Priority (PCP) */
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return (OS_FALSE);
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return (OS_FALSE);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return (OS_FALSE);
- }
- if (OSIntNesting > 0u) { /* Make sure it's not called from an ISR */
- *perr = OS_ERR_PEND_ISR;
- return (OS_FALSE);
- }
- OS_ENTER_CRITICAL(); /* Get value (0 or 1) of Mutex */
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP from mutex */
- if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
- pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Mask off LSByte (Acquire Mutex) */
- pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* Save current task priority in LSByte */
- pevent->OSEventPtr = (void *)OSTCBCur; /* Link TCB of task owning Mutex */
- if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
- (OSTCBCur->OSTCBPrio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
- OS_EXIT_CRITICAL(); /* ... than current task! */
- *perr = OS_ERR_PCP_LOWER;
- } else {
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- }
- return (OS_TRUE);
- } //其实以上的内容和OSMutexPend都是一样的,我们不做即使
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- return (OS_FALSE);
- }
相信看完OSMutexPend()函数的朋友再来理解该函数是不是感觉就太简单了,他们仅有的区别在于,一个执行完,如果资源被占用将被挂起,而另一个会直接返回。
[cpp] view plain copy
- INT8U OSMutexPost (OS_EVENT *pevent)
- {
- INT8U pcp; /* Priority ceiling priority */
- INT8U prio;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- return (OS_ERR_POST_ISR); /* ... can't POST mutex from an ISR */
- }
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- return (OS_ERR_PEVENT_NULL);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- return (OS_ERR_EVENT_TYPE);
- }
- OS_ENTER_CRITICAL();
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); // 获取PCP优先级
- prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); //获取原优先级
- if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) { /* See if posting task owns the MUTEX */
- OS_EXIT_CRITICAL();
- return (OS_ERR_NOT_MUTEX_OWNER);//互斥信号量错误
- }
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- if (OSTCBCur->OSTCBPrio == pcp) { /* Did we have to raise current task's priority? */
- OSMutex_RdyAtPrio(OSTCBCur, prio); //恢复原优先级
- }
- OSTCBPrioTbl[pcp] = OS_TCB_RESERVED; //OS_TCB_RESERVED=1
- }
- if (pevent->OSEventGrp != 0u) { /* Any task waiting for the mutex? */
- /* Yes, Make HPT waiting for mutex ready */
- prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
- pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* Save priority of mutex's new owner */
- pevent->OSEventCnt |= prio;
- pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* Link to new mutex owner's OS_TCB */
- if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
- (prio <= pcp)) { /* PCP 'must' have a SMALLER prio ... */
- OS_EXIT_CRITICAL(); /* ... than current task! */
- OS_Sched(); /* Find highest priority task ready to run */
- return (OS_ERR_PCP_LOWER);
- } else {
- OS_EXIT_CRITICAL();
- OS_Sched(); /* Find highest priority task ready to run */
- return (OS_ERR_NONE);
- }
- }
- pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* No, Mutex is now available */
- pevent->OSEventPtr = (void *)0;
- OS_EXIT_CRITICAL();
- return (OS_ERR_NONE);
- }
- //以上主要是恢复原优先级,并并将占用的资源释放
- OS_EVENT *OSMutexDel (OS_EVENT *pevent,
- INT8U opt,
- INT8U *perr)
- {
- BOOLEAN tasks_waiting;
- OS_EVENT *pevent_return;
- INT8U pcp; /* Priority ceiling priority */
- INT8U prio;
- OS_TCB *ptcb;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- #ifdef OS_SAFETY_CRITICAL
- if (perr == (INT8U *)0) {
- OS_SAFETY_CRITICAL_EXCEPTION();
- return ((OS_EVENT *)0);
- }
- #endif
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- *perr = OS_ERR_PEVENT_NULL;
- return (pevent);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- *perr = OS_ERR_EVENT_TYPE;
- return (pevent);
- }
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- *perr = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
- return (pevent);
- }
- OS_ENTER_CRITICAL();
- if (pevent->OSEventGrp != 0u) { /* See if any tasks waiting on mutex */
- tasks_waiting = OS_TRUE; /* Yes */
- } else {
- tasks_waiting = OS_FALSE; /* No */
- }
- switch (opt) { //opt为删除类型
- case OS_DEL_NO_PEND: //任务没有挂起的时候删除互斥信号 /* DELETE MUTEX ONLY IF NO TASK WAITING --- */
- if (tasks_waiting == OS_FALSE) {
- #if OS_EVENT_NAME_EN > 0u
- pevent->OSEventName = (INT8U *)(void *)"?";
- #endif
- pcp = (INT8U)(pevent->OSEventCnt >> 8u);
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- OSTCBPrioTbl[pcp] = (OS_TCB *)0; //释放占用的PCP提升资源 */
- }
- pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
- pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
- pevent->OSEventCnt = 0u;
- OSEventFreeList = pevent;//重新将互斥量链接到空闲表
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_NONE;
- pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
- } else {
- OS_EXIT_CRITICAL(); //存在将返回错误,此时不能删除
- *perr = OS_ERR_TASK_WAITING;
- pevent_return = pevent;
- }
- break;
- case OS_DEL_ALWAYS: //总是删除互斥量 /* ALWAYS DELETE THE MUTEX ---------------- */
- pcp = (INT8U)(pevent->OSEventCnt >> 8u); /* Get PCP of mutex */
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's orig prio */
- ptcb = (OS_TCB *)pevent->OSEventPtr;
- if (ptcb != (OS_TCB *)0) { /* See if any task owns the mutex */
- if (ptcb->OSTCBPrio == pcp) { /* See if original prio was changed */
- OSMutex_RdyAtPrio(ptcb, prio); /* Yes, Restore the task's original prio */
- }
- }
- }
- //别占用的资源强制释放
- while (pevent->OSEventGrp != 0u) { /* Ready ALL tasks waiting for mutex */
- (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_ABORT);
- }
- #if OS_EVENT_NAME_EN > 0u
- pevent->OSEventName = (INT8U *)(void *)"?";
- #endif
- pcp = (INT8U)(pevent->OSEventCnt >> 8u);
- if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
- OSTCBPrioTbl[pcp] = (OS_TCB *)0; /* Free up the PCP */
- }
- pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
- pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
- pevent->OSEventCnt = 0u;
- OSEventFreeList = pevent; /* Get next free event control block */
- OS_EXIT_CRITICAL();
- if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
- OS_Sched(); //存在就绪任务将开展调度 /* Find highest priority task ready to run */
- }
- *perr = OS_ERR_NONE;
- pevent_return = (OS_EVENT *)0; /* Mutex has been deleted */
- break;
- default:
- OS_EXIT_CRITICAL();
- *perr = OS_ERR_INVALID_OPT; //无效opt输入
- pevent_return = pevent;
- break;
- }
- return (pevent_return); //返回删除的互斥量地址
- }
该任务主要是删除一个互斥量。
1、不占用任务删除类型:互斥量将在没有任务挂起时删除
2、总是删除类型:互斥量将总是删除任务,当存在任务挂起时将强制就绪释放
[cpp] view plain copy
- INT8U OSMutexQuery (OS_EVENT *pevent,
- OS_MUTEX_DATA *p_mutex_data)
- {
- INT8U i;
- OS_PRIO *psrc;
- OS_PRIO *pdest;
- #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */
- OS_CPU_SR cpu_sr = 0u;
- #endif
- if (OSIntNesting > 0u) { /* See if called from ISR ... */
- return (OS_ERR_QUERY_ISR); /* ... can't QUERY mutex from an ISR */
- }
- #if OS_ARG_CHK_EN > 0u
- if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
- return (OS_ERR_PEVENT_NULL);
- }
- if (p_mutex_data == (OS_MUTEX_DATA *)0) { /* Validate 'p_mutex_data' */
- return (OS_ERR_PDATA_NULL);
- }
- #endif
- if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type */
- return (OS_ERR_EVENT_TYPE);
- }
- OS_ENTER_CRITICAL();
- p_mutex_data->OSMutexPCP = (INT8U)(pevent->OSEventCnt >> 8u);
- p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
- if (p_mutex_data->OSOwnerPrio == 0xFFu) {
- p_mutex_data->OSValue = OS_TRUE; //查看资源是否被占用
- } else {
- p_mutex_data->OSValue = OS_FALSE;
- }
- p_mutex_data->OSEventGrp = pevent->OSEventGrp; /* Copy wait list */
- psrc = &pevent->OSEventTbl[0];
- pdest = &p_mutex_data->OSEventTbl[0];
- for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) { //执行数据拷贝
- *pdest++ = *psrc++;
- }
- OS_EXIT_CRITICAL();
- return (OS_ERR_NONE);
- }
- //该函数比较简单,直接拷贝pevent信息到p_mutex_data数据结构中。
- static void OSMutex_RdyAtPrio (OS_TCB *ptcb,
- INT8U prio)
- {
- INT8U y;
- y = ptcb->OSTCBY; /* Remove owner from ready list at 'pcp' */
- OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX; //清除原就绪标志
- if (OSRdyTbl[y] == 0u) {
- OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
- }
- ptcb->OSTCBPrio = prio;
- OSPrioCur = prio; /* The current task is now at this priority */
- #if OS_LOWEST_PRIO <= 63u
- ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 3u) & 0x07u);
- ptcb->OSTCBX = (INT8U)(prio & 0x07u);
- #else
- ptcb->OSTCBY = (INT8U)((INT8U)(prio >> 4u) & 0x0Fu);
- ptcb->OSTCBX = (INT8U) (prio & 0x0Fu);
- #endif
- ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY); //在新的优先级上就绪任务
- ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);
- OSRdyGrp |= ptcb->OSTCBBitY; /* Make task ready at original priority */
- OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
- OSTCBPrioTbl[prio] = ptcb;
- }
该函数主要是将一个任务优先级提升到prio层次,并将提升后的任务就绪。
到这里,互斥信号量的源码分析也就结束了,总结一点,互斥信号量和信号量其实大同小异,当然这是考虑信号量在只有一个时(及cnt=1)的情况,二者仅有的区别在于互斥信号量可以有效地防止优先级反转,而这在一些安全相关的系统中将是至关重要的。因此在处理对任务顺序较为敏感的任务的时候,需要使用互斥量来防止反转,增加系统的可预测性。
好了,互斥量就讲到这里
时间:170708
阅读全文
0 0
- UCOSII学习之路3 -任务同步之互斥
- UCOSII学习之路2 任务同步之信号量的使用
- ucosii之任务的同步与通信
- ucosii之任务的同步与通信
- ucosii之任务管理
- UCOSII概述之-任务调度
- UCOSii的学习之路(一)
- C++11多线程同步之互斥变量使用学习
- 线程之路之四:进程同步线程互斥
- 面试之路---进程的互斥和同步
- linux互斥与同步 之 互斥锁
- 6410之同步互斥阻塞
- 操作系统之同步与互斥
- linux驱动程序之同步、互斥、阻塞
- 多线程同步之互斥对象
- 内核机制之互斥与同步
- Linux之线程:同步与互斥
- 多线程同步之互斥对象
- Unit 6
- 欢迎使用CSDN-markdown编辑器
- day02逆置/反转单链表+查找单链表的倒数第k个节点+实现一个Add函数不用四则运算
- 交叉排序
- JLink
- UCOSII学习之路3 -任务同步之互斥
- Unity3D学习记录——碰撞变色2
- 福州大学第十四届程序设计竞赛_重现赛 I
- Javascript模块化编程(一):模块的写法
- 虚拟机(VMware)安装Ubuntu
- 2017中科大信息安全课程总结四
- 开发工具准备
- redis学习笔记——redis集群搭建(linux版)
- unable to install wkhtmltopdf with patched qt in ubuntu 16.04