UCOSII学习之路3 -任务同步之互斥
2017-07-15 10:56
471 查看
上一节我们引入了信号量的概念,这一讲我们将揭晓互斥信号量的奥秘。
互斥信号量和信号量虽然都带了信号量的帽子,但是二者却有着不同的运用场合,互斥信号量相比而言经常用于一些资源的互斥访问,比如打印机、厕所等,这里的厕所指的是单厕,哈哈哈。这样有的人就要问了,那信号量设置起始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);
}
该函数的目的是初始化事件控制块为互斥信号量,其中,当prio输入为OS_PRIO_MUTEX_CEIL_DIS,任务将不进行优先级提升,此时和单一的信号量的作用是相同的。还有一点也是需要特别留意,如果任务的优先级提升了,那么任务在使用完指定资源过后,怎么重新恢复他原有的优先级呢?想必看过源码的都已经了解了,这也是UCOS设计者的另外一个高明之处---变量的复用,通过将提升后的任务优先级放到OSEventCnt的高八位,从而保存该优先级而不需要重新定义变量,节省了系统对RAM的要求。
[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
互斥信号量和信号量虽然都带了信号量的帽子,但是二者却有着不同的运用场合,互斥信号量相比而言经常用于一些资源的互斥访问,比如打印机、厕所等,这里的厕所指的是单厕,哈哈哈。这样有的人就要问了,那信号量设置起始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);
}
该函数的目的是初始化事件控制块为互斥信号量,其中,当prio输入为OS_PRIO_MUTEX_CEIL_DIS,任务将不进行优先级提升,此时和单一的信号量的作用是相同的。还有一点也是需要特别留意,如果任务的优先级提升了,那么任务在使用完指定资源过后,怎么重新恢复他原有的优先级呢?想必看过源码的都已经了解了,这也是UCOS设计者的另外一个高明之处---变量的复用,通过将提升后的任务优先级放到OSEventCnt的高八位,从而保存该优先级而不需要重新定义变量,节省了系统对RAM的要求。
[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
相关文章推荐
- UCOSII学习之路2 任务同步之信号量的使用
- 嵌入式Linux驱动学习之路(十四)按键驱动-同步、互斥、阻塞
- 多任务的同步与互斥
- 阿里云大数据利器Maxcompute学习之--数据同步任务常见日志报错总结
- Linux系统编程——多任务的同步与互斥
- UCOSii(四)——任务的通信与同步
- 操作系统学习笔记(10) 互斥和同步的经典问题
- hadoop生态系统学习之路(八)hbase与hive的数据同步以及hive与impala的数据同步
- java学习之路----同步于死锁
- 【操作系统学习】(二)同步互斥
- ucosii任务间的同步与通信
- iOS学习笔记74-IOS多线程知识总结/队列概念/GCD/主队列/并行队列/全局队列/主队列/串行队列/同步任务/异步任务区别附代码
- 面试之路---进程的互斥和同步
- hadoop学习之路(二)hadoop基本概念原理以及单词统计任务源码分析
- Linux下多任务间通信和同步-互斥锁
- 分布计算系统学习随笔 第五章同步和互斥
- Linux Kernel 学习笔记8:同步与互斥之信号量
- linux 系统编程-学习笔记9--线程的同步互斥锁、读写锁/select/poll
- spring框架学习之路(二)-进阶技能(3)-定时器任务
- C#高级学习第五章线程,任务和同步