您的位置:首页 > 其它

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: