os_mutex.c(全)
- 无等待地获取互斥型信号量 OSMutexAccept (OS_EVENT *pevent,INT8U *perr):
- 创建互斥型信号量OS_EVENT *OSMutexCreate (INT8U prio,INT8U *perr)
- 删除信号量OS_EVENT *OSMutexDel (OS_EVENT *pevent,INT8U opt,INT8U *perr)
- 等待互斥型信号量void OSMutexPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr)
- 释放一个互斥型信号量 OSMutexPost (OS_EVENT *pevent)
- 查询互斥量OSMutexQuery (OS_EVENT *pevent,OS_MUTEX_DATA *p_mutex_data)
OSMutexAccept (OS_EVENT *pevent,INT8U *perr):
/*$PAGE*/
/*2018/2/19
*********************************************************************************************************
* ACCEPT MUTUAL EXCLUSION SEMAPHORE
* 无等待地获取互斥型信号量
* Description: This function checks the mutual exclusion semaphore to see if a resource is available.
* Unlike OSMutexPend(), OSMutexAccept() does not suspend the calling task if the resource is
* not available or the event did not occur.
*描述: 检查互斥型信号量,以判断某资源是否可以使用,与 OSMutexPend()不同的是,若资源不能使用,则调用 OSMutexAccept()函数的任务并不被挂起, OSMutexAccept()仅查询状态。
* Arguments : pevent is a pointer to the event control block
*参数: pevent:指向事件控制块的指针
* perr is a pointer to an error code which will be returned to your application:
* OS_ERR_NONE if the call was successful.
* OS_ERR_EVENT_TYPE if 'pevent' is not a pointer to a mutex
* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
* OS_ERR_PEND_ISR if you called this function from an ISR
* OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is
* HIGHER (i.e. a lower number) than the PIP. This error
* indicates that you did not set the PIP higher (lower
* number) than ALL the tasks that compete for the Mutex.
* Unfortunately, this is something that could not be
* detected when the Mutex is created because we don't know
* what tasks will be using the Mutex.
* perr: 指向错误码的指针。可以有以下几种选择:OS_ERR_NONE:无错误OS_ERR_EVENT_TYPE:pevent不是指向mutex类型的指针OS_ERR_PEVENT_NULL:pevent为空指针OS_ERR_PEND_ISR:在中断服务子程序中调用OS_ERR_PIP_LOWER:正在使用mutex的任务优先级高于PIP。
* Returns : == OS_TRUE if the resource is available, the mutual exclusion semaphore is acquired
* == OS_FALSE a) if the resource is not available
* b) you didn't pass a pointer to a mutual exclusion semaphore
* c) you called this function from an ISR
*返回值: ==OS_TRUE:资源可以获得,互斥型信号量可以获得==OS_FALSE:a)无法获得资源b)没有指向互斥型信号量的指针c)从中断服务子程序中调用该功能
* Warning(s) : This function CANNOT be called from an ISR because mutual exclusion semaphores are
* intended to be used by tasks only.
警告:该功能不能从中断中调用,因为互斥型信号量只能被任务调用。
*********************************************************************************************************
*/#if OS_MUTEX_ACCEPT_EN > 0u
BOOLEAN OSMutexAccept (OS_EVENT *pevent,INT8U *perr)
{INT8U pip; /* Priority Inheritance Priority (PIP)优先级继承优先级*/#if OS_CRITICAL_METHOD == 3u /*中断类型被设置为类型3*/OS_CPU_SR cpu_sr = 0u;#endif#ifdef OS_SAFETY_CRITICAL /*安全中断*/if (perr == (INT8U *)0) {OS_SAFETY_CRITICAL_EXCEPTION();}#endif#if OS_ARG_CHK_EN > 0u /*参数检查*/if (pevent == (OS_EVENT *)0) { *perr = OS_ERR_PEVENT_NULL;return (OS_FALSE);}#endifif (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)/*有效化事件控制块类型*/{ *perr = OS_ERR_EVENT_TYPE;return (OS_FALSE);}if (OSIntNesting > 0u) /*判断是否从中断服务子程序中调用*/{ *perr = OS_ERR_PEND_ISR;return (OS_FALSE);}OS_ENTER_CRITICAL(); /*进入中断*/pip = (INT8U)(pevent->OSEventCnt >> 8u); /* 从mutex中获得PIP,pip存放在OSEventCnt的高八位中*/if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)/*/获得Mutex的值(0或1),OSEventCnt相与0x00ff后判断。OSEventCnt低8为0xff*/{pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /*如果Mutex(高8位PIP)有效,将PIP保存到OSEventCnt的高8位(相与0xffoo)*/pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /*把该任务的优先级写到OSEventCnt的低8位(相或OSTCBPrio)*/pevent->OSEventPtr = (void *)OSTCBCur; /*将Mutex的事件控制块ECB链接到该任务的任务控制块*/if (OSTCBCur->OSTCBPrio <= pip) /*如果当前TCB的优先级数值不大于pip,即优先级高*/{ OS_EXIT_CRITICAL(); /*退出中断*/*perr = OS_ERR_PIP_LOWER; /*将错误类型设置为OS_ERR_PIP_LOWER,无法执行该任务*/} else /*如果当前TCB的优先级小于pip*/{ OS_EXIT_CRITICAL(); /*退出中断*/*perr = OS_ERR_NONE;/*成功调用该函数*/}return (OS_TRUE);/*检查状态,可以获得互斥型信号量*/}OS_EXIT_CRITICAL();/*退出中断*/*perr = OS_ERR_NONE;/*将错误类型设置为无错误*/return (OS_FALSE); /*检查状态后确认不可以获得互斥型信号量*/
}
#
要注意该函数返回的是一个布尔值,表示能否获得互斥量。
在这个函数中,需要对下面几行进行解释:
pip = (INT8U)(pevent->OSEventCnt >> 8u); /* 从mutex中获得PIP,pip存放在OSEventCnt的高八位中*/
if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)
pip是priority inheritance priority,优先级继承优先级。对于互斥型信号量,可能存在很多任务争夺一个的情况,此时,可能发生优先级反转现象(可以参考之前文章OS_CORE.C(6),点击打开链接)。pip就是为了防止优先级反转设置的。简单来说,如果当前任务优先级比继承优先级低,不会反转,不需要pip。如果比继承优先级高,会反转,那么将当前任务优先级设置为pip,这样就不会发生反转了。
OSEventCnt的低8位存放的是OS_MUTEX_AVAILABLE,如果if判断后检查结果仍为OS_MUTEX_AVAILABLE,则说明互斥锁没有被占用,这时候就要保存当前运行任务的优先级到OSEventCnt的低8位中,语句为:
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
然后比较一下当前任务的优先级是否比创建时的继承优先级低(优先级值大),如果当前任务的优先级比继承优先级高(数值小),则返回错误,语句为:
if (OSTCBCur->OSTCBPrio <= pip) /*如果当前TCB的优先级数值不大于pip,即优先级高*/{ OS_EXIT_CRITICAL(); /*退出中断*/*perr = OS_ERR_PIP_LOWER;/*将错误类型设置为OS_ERR_PIP_LOWER,无法执行该任务*/}
因为继承优先级是为了防止优先级翻转而设定,如果当前任务优先级比继承优先级低则不需要担心优先级反转,则返回正确值。
创建互斥型信号量OS_EVENT *OSMutexCreate(INT8U prio,INT8U *perr):
/*$PAGE*/
/*2018/2/19
*********************************************************************************************************
* CREATE A MUTUAL EXCLUSION SEMAPHORE
* 创建互斥型信号量
* Description: This function creates a mutual exclusion semaphore.
*描述:该功能用来新建互斥型信号量。
* Arguments : prio is the priority to use when accessing the mutual exclusion semaphore. In
* other words, when the semaphore is acquired and a higher priority task
* attempts to obtain the semaphore then the priority of the task owning the
* semaphore is raised to this priority. It is assumed that you will specify
* a priority that is LOWER in value than ANY of the tasks competing for the
* mutex.
*参数: --prio:获得互斥型信号量的任务的优先级。换句话说,当有任务已经获得了信号量,但是更高优先级任务尝试获得该信号量时,占有信号量的任务将其优先级提高到高优先级。。此时任务的优先级比所有竞争mutex的任务优先级都高。
* perr is a pointer to an error code which will be returned to your application:
* OS_ERR_NONE if the call was successful.
* OS_ERR_CREATE_ISR if you attempted to create a MUTEX from an ISR
* OS_ERR_PRIO_EXIST if a task at the priority inheritance priority
* already exist.
* OS_ERR_PEVENT_NULL No more event control blocks available.
* OS_ERR_PRIO_INVALID if the priority you specify is higher that the
* maximum allowed (i.e. > OS_LOWEST_PRIO)
* --perr:指向错误码的指针,取值如下:OS_ERR_NONE:无错误;OS_ERR_CREATE_ISR:从中断服务子程序中创建mutexOS_ERR_PRIO_EXIST:优先级为PIP的任务已经存在;OS_ERR_PEVENT_NULL:没有可用的事件控制块OS_ERR_PRIO_INVALID:定义的优先级非法,其值大于OS_LOWEST_PRIO.
* Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
* created mutex.
* == (void *)0 if an error is detected.
*返回值: !=0 返回一个指针 ,该指针指向分配给mutex的事件控制块。==0 有错误,返回空指针。
* Note(s) : 1) The LEAST significant 8 bits of '.OSEventCnt' are used to hold the priority number
* of the task owning the mutex or 0xFF if no task owns the mutex.
*
* 2) The MOST significant 8 bits of '.OSEventCnt' are used to hold the priority number
* to use to reduce priority inversion.
注释: 1)OSEventCnt的低八位用来表示拥有互斥量任务的优先级,如果没有任务拥有该互斥量,低八位为0xff2)OSEventCnt的高八位存放的优先级是用来减少优先级反转
*********************************************************************************************************
*/OS_EVENT *OSMutexCreate (INT8U prio,INT8U *perr)
{OS_EVENT *pevent;/*指向事件控制块的指针*/
mutex首先会检查传入优先级的任务的TCB有没有已经被使用,如果传入优先级已经被使用,则创建失败,返回错误,如果参数传入的优先级的TCB没有被占用,则设置为reserved,保证该TCB不会被其他任务使用。语句如下:
OS_ENTER_CRITICAL();/*进入中断*/if (OSTCBPrioTbl[prio] != (OS_TCB *)0) /*检查传入优先级的任务的TCB是否被占用*/{ OS_EXIT_CRITICAL(); *perr = OS_ERR_PRIO_EXIST; return ((OS_EVENT *)0);}OSTCBPrioTbl[prio] = OS_TCB_RESERVED;/*如果没有被占用,则设置为reserved*/
再检查是否有空闲的事件控制块,如果没有返回空指针,如果有,进行相关操作:
pevent = OSEventFreeList;/*得到一个事件控制块 */if (pevent == (OS_EVENT *)0) /*如果没有空闲的事件控制块*/{ OSTCBPrioTbl[prio] = (OS_TCB *)0; /*将优先级表对应的位置清0 */OS_EXIT_CRITICAL();/*退出中断*/*perr = OS_ERR_PEVENT_NULL; /*将错误码设置为OS_ERR_PEVENT_NULL*/return (pevent);/*返回一个空指针*/}/*如果有空闲的事件控制块*/OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /*调整事件空闲列表*/OS_EXIT_CRITICAL();/*退出中断*/pevent->OSEventType = OS_EVENT_TYPE_MUTEX;/*将事件类型设置为mutex*/pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE;pevent->OSEventPtr = (void *)0; /*没有任务使用mutex*/#if OS_EVENT_NAME_EN > 0upevent->OSEventName = (INT8U *)(void *)"?";/*如果事件有名称,设置为未命名*/#endifOS_EventWaitListInit(pevent);/*事件等待列表初始化*/
这几行语句中解释一下:
pevent->OSEventCnt = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE;
prio左移8位,将优先级存放在OSEventCnt中的高八位,再与OS_MUTEX_AVAILABLE进行或运算,即OSEventCnt的低八位00与OS_MUTEX_AVAILABLE进行运算,如果运算结果为全ff,则说明可以获得mutex,否则不可以获得。
删除信号量OS_EVENT *OSMutexDel (OS_EVENT *pevent,INT8U opt,INT8U *perr):(部分代码)
/*$PAGE*/
/*2018/2/19
*********************************************************************************************************
* DELETE A MUTEX
* 删除信号量
* Description: This function deletes a mutual exclusion semaphore and readies all tasks pending on the it.
*描述:该功能用来删除互斥量并且将所有的任务就绪
* Arguments : pevent is a pointer to the event control block associated with the desired mutex.
*参数: --pevent:指向事件控制块的指针
* opt determines delete options as follows:
* opt == OS_DEL_NO_PEND Delete mutex ONLY if no task pending
* opt == OS_DEL_ALWAYS Deletes the mutex even if tasks are waiting.
* In this case, all the tasks pending will be readied.
* --opt:两种删除方式:OS_DEL_NO_PEND:只有没有任务挂起时才能删除该互斥量;OS_DEL_ALWAYS:无论有没有挂起都删除,这种情况下,所有的任务都从挂起状态转化为就绪态。
* perr is a pointer to an error code that can contain one of the following values:
* OS_ERR_NONE The call was successful and the mutex was deleted
* OS_ERR_DEL_ISR If you attempted to delete the MUTEX from an ISR
* OS_ERR_INVALID_OPT An invalid option was specified
* OS_ERR_TASK_WAITING One or more tasks were waiting on the mutex
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
* --perr:指向错误码的指针,可以有以下值:OS_ERR_NONE:无错误;OS_ERR_DEL_ISR:从中断服务子程序删除;OS_ERR_INVALID_OPT:opt为无效值;OS_ERR_TASK_WAITING:一个或者多个任务正在等待mutex;OS_ERR_EVENT_TYPE:没有指向mutex的指针;OS_ERR_PEVENT_NULL:pevent为空指针。
* Returns : pevent upon error
* (OS_EVENT *)0 if the mutex was successfully deleted.
*返回值:如果mutex已经删除,则返回空指针;如果mutex没能删除,则返回pevent
* Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
* the mutex MUST check the return code of OSMutexPend().
*注释: 1)该功能必须小心使用,因为其他任务可能会用到mutex。需要该信号量的任务必须检测OSMutexPend()的返回值。
* 2) This call can potentially disable interrupts for a long time. The interrupt disable
* time is directly proportional to the number of tasks waiting on the mutex.
* 2)调用该函数时不能被中断。中断时间与等待该信号量的任务数量有关。
* 3) Because ALL tasks pending on the mutex will be readied, you MUST be careful because the
* resource(s) will no longer be guarded by the mutex.
* 3)因为在删除信号量之后,所有挂起的任务都自动转为就绪态,所以你必须小心,因为资源此时不再被mutex控制。
* 4) IMPORTANT: In the 'OS_DEL_ALWAYS' case, we assume that the owner of the Mutex (if there
* is one) is ready-to-run and is thus NOT pending on another kernel object or
* has delayed itself. In other words, if a task owns the mutex being deleted,
* that task will be made ready-to-run at its original priority.4)重点:在OS_DEL_ALWAYS情况下,我们任务mutex的拥有者(假设只有一个)已经准备运行,并且不在其他内核对象中等待(挂起)或者自身延迟。换句话说,如果拥有互斥量的任务被删除了,该任务将会以之前原始的优先级存在。
*********************************************************************************************************
*/#if OS_MUTEX_DEL_EN > 0u
OS_EVENT *OSMutexDel (OS_EVENT *pevent,INT8U opt,INT8U *perr)
{BOOLEAN tasks_waiting;/*布尔值看是否有任务正在等待*/OS_EVENT *pevent_return;/*返回值*/INT8U pip; /*继承优先级*/INT8U prio;/*原始优先级*/OS_TCB *ptcb;/*指向TCB的指针*/
先检查是否有任务正在等待信号量。然后选择删除方式,进行删除。
OS_ENTER_CRITICAL();/*进入中断*/if (pevent->OSEventGrp != 0u)/*检查是否有任务正在等待该信号量*/{ tasks_waiting = OS_TRUE; } else{tasks_waiting = OS_FALSE; }switch (opt) /*选择删除方式*/{case OS_DEL_NO_PEND:/*没有等待信号量的任务时才删除*/if (tasks_waiting == OS_FALSE) /*没有任务等待*/{#if OS_EVENT_NAME_EN > 0upevent->OSEventName = (INT8U *)(void *)"?";/*如果有名称,将名称设置为未命名*/#endifpip = (INT8U)(pevent->OSEventCnt >> 8u);/*将OSEventCnt的高八位赋值给pip,获得继承优先级*/OSTCBPrioTbl[pip] = (OS_TCB *)0; /*在优先级表中释放pip所在的tcb */pevent->OSEventType = OS_EVENT_TYPE_UNUSED;/*将事件类型设置为未使用类型*/pevent->OSEventPtr = OSEventFreeList;/*将事件控制块返回给空闲事件列表 */pevent->OSEventCnt = 0u;OSEventFreeList = pevent;/*更新空闲事件列表*/OS_EXIT_CRITICAL();/*退出中断*/*perr = OS_ERR_NONE;pevent_return = (OS_EVENT *)0;/*信号量已经被删除,返回空指针*/} else/*有任务等待*/{OS_EXIT_CRITICAL();/*退出中断*/*perr = OS_ERR_TASK_WAITING;pevent_return = pevent;}break;case OS_DEL_ALWAYS:/*无论怎样都删除*/pip = (INT8U)(pevent->OSEventCnt >> 8u); /*得到继承优先级*/prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/*得到原始的优先级*/ptcb = (OS_TCB *)pevent->OSEventPtr;/*指向TCB的指针*/if (ptcb != (OS_TCB *)0)/*如果有空闲的TCB*/{ /* See if any task owns the mutex */if (ptcb->OSTCBPrio == pip) /*看原始的优先级是否改变了,即是否解决过优先级反转*/{ OSMutex_RdyAtPrio(ptcb, prio); /*原始优先级改变,将其存储。待任务完成后恢复*/}}while (pevent->OSEventGrp != 0u) /*如果有事件组,即有任务在等待该信号量*/{ (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);/*将所有任务转为就绪态*/}#if OS_EVENT_NAME_EN > 0upevent->OSEventName = (INT8U *)(void *)"?";/*将事件名称设置为未命名*/#endifpip = (INT8U)(pevent->OSEventCnt >> 8u);/*获得pip*/OSTCBPrioTbl[pip] = (OS_TCB *)0; pevent->OSEventType = OS_EVENT_TYPE_UNUSED;pevent->OSEventPtr = OSEventFreeList; pevent->OSEventCnt = 0u;OSEventFreeList = pevent; OS_EXIT_CRITICAL();if (tasks_waiting == OS_TRUE) /*如果有任务等待*/{ OS_Sched();/*在就绪任务中找到优先级最高的任务进行调度*/}*perr = OS_ERR_NONE;pevent_return = (OS_EVENT *)0;break;default:/*其他情况*/OS_EXIT_CRITICAL();*perr = OS_ERR_INVALID_OPT;/*选择无效*/pevent_return = pevent;break;}return (pevent_return);
}
#endif
该函数较为简单,不赘述。
等待互斥型信号量void OSMutexPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr):
/*$PAGE*/
/*2018/2/19
*********************************************************************************************************
* PEND ON MUTUAL EXCLUSION SEMAPHORE
* 等待互斥型信号量
* Description: This function waits for a mutual exclusion semaphore.
*描述:该功能用来等待互斥型信号量
* Arguments : pevent is a pointer to the event control block associated with the desired mutex.
*参数: --pevent:指向事件控制块的指针
* timeout is an optional timeout period (in clock ticks). If non-zero, your task will
* wait for the resource up to the amount of time specified by this argument.
* If you specify 0, however, your task will wait forever at the specified
* mutex or, until the resource becomes available.
* --timeout:可选择的时间超时片。如果不为0,任务将等待资源直到时间到了该参数规定的时间。超时后,将不再等待。如果为0,任务将永远处于等待,直到资源可以获得。
* perr is a pointer to where an error message will be deposited. Possible error
* messages are:
* OS_ERR_NONE The call was successful and your task owns the mutex
* OS_ERR_TIMEOUT The mutex was not available within the specified 'timeout'.
* OS_ERR_PEND_ABORT The wait on the mutex was aborted.
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
* OS_ERR_PEND_ISR If you called this function from an ISR and the result
* would lead to a suspension.
* OS_ERR_PIP_LOWER If the priority of the task that owns the Mutex is
* HIGHER (i.e. a lower number) than the PIP. This error
* indicates that you did not set the PIP higher (lower
* number) than ALL the tasks that compete for the Mutex.
* Unfortunately, this is something that could not be
* detected when the Mutex is created because we don't know
* what tasks will be using the Mutex.
* OS_ERR_PEND_LOCKED If you called this function when the scheduler is locked
* --perr:指向错误信息的指针。有可能的错误信息如下:OS_ERR_NONE:无错误;OS_ERR_TIMEOUT:超时错误;OS_ERR_PEND_ABORT:等待信号量的任务被取消;OS_ERR_EVENT_TYPE:没有指向mutex的指针;OS_ERR_PEVENT_NULL:pevent是空指针;OS_ERR_PEND_ISR:从中断服务子程序中调用该功能;OS_ERR_PIP_LOWER:当前任务优先级比pip高。
* Returns : none
*返回值:无
* Note(s) : 1) The task that owns the Mutex MUST NOT pend on any other event while it owns the mutex.
*注释:1)拥有信号量的任务不能再其他事件中处于挂起状态。
* 2) You MUST NOT change the priority of the task that owns the mutex2)不能改变拥有mutex的任务的优先级。
*********************************************************************************************************
*/void OSMutexPend (OS_EVENT *pevent,INT32U timeout,INT8U *perr)
{INT8U pip; /*继承优先级*/INT8U mprio; /*拥有信号量的任务的优先级*/BOOLEAN rdy; /*标志任务是否就绪*/OS_TCB *ptcb;/*指向TCB的指针*/OS_EVENT *pevent2;/*指向事件控制块的指针*/INT8U y;
检测互斥量是否为可获得的。如果可获得,则判断当前任务的优先级和pip优先级高低。如果不可获得,需要判断两次:第一判断拥有互斥量任务的优先级与pip优先级高低;第二判断拥有互斥量任务的优先级与当前任务优先级的高低。
如果检测互斥量是可获得的,表示没有任务使用互斥锁,这时候运行该函数的任务将获得互斥锁并退出。如果不是可获得的,表示一个新的任务在尝试获得互斥锁,并且互斥锁已经被占用时的操作。代码如下:
OS_ENTER_CRITICAL();/*进入中断*/pip = (INT8U)(pevent->OSEventCnt >> 8u);/*获得PIP,继承优先级*//*检测互斥量是否为可获得的*/if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE){pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;/*修改高8位的数据,这个时候高8位数据不变,还是表示继承优先级,低8位清零*/pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;/*将申请任务的优先级保存在低8位之中。低八位不可能全部都为零,所以依旧可以表示信号量是否被占用*/pevent->OSEventPtr = (void *)OSTCBCur; /*OSEventPtr指针指向任务控制块 */if (OSTCBCur->OSTCBPrio <= pip)/*如果当前任务的优先级比pip优先级高*/{ OS_EXIT_CRITICAL(); *perr = OS_ERR_PIP_LOWER;}else /*当前任务优先级低*/{OS_EXIT_CRITICAL();*perr = OS_ERR_NONE;}return;}
上面这一段代码是互斥量为可获得的。
下面这段代码为互斥量不可获得的:
/*如果该互斥量不可获得*/mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /*得到拥有互斥量的任务的优先级*/ptcb = (OS_TCB *)(pevent->OSEventPtr); /* 指针指向拥有互斥量的TCB*/if (ptcb->OSTCBPrio > pip) /*获得互斥量的任务的优先级比pip优先级低*/{ if (mprio > OSTCBCur->OSTCBPrio)/*获得互斥量任务的优先级比当前任务优先级低*/{y = ptcb->OSTCBY;if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) /*看拥有互斥量的任务是否就绪*/{ OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;/*如果就绪,将其从就绪表中移除*/if (OSRdyTbl[y] == 0u){ OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;/*从就绪组中移除*/}rdy = OS_TRUE;/*将就绪标志设置为true*/} else/*拥有互斥量的任务没就绪*/{pevent2 = ptcb->OSTCBEventPtr;/*pevent2指向拥有互斥量的事件*/if (pevent2 != (OS_EVENT *)0) /*如果该事件不为空,将其从事件表中删除*/{ y = ptcb->OSTCBY;pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;if (pevent2->OSEventTbl[y] == 0u) {pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;}}rdy = OS_FALSE; /*将其就绪状态设置为false*/}ptcb->OSTCBPrio = pip; /*将有互斥量的任务的优先级改为pip */#if OS_LOWEST_PRIO <= 63uptcb->OSTCBY = (INT8U)( ptcb->OSTCBPrio >> 3u);ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x07u);#elseptcb->OSTCBY = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);ptcb->OSTCBX = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);#endifptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);if (rdy == OS_TRUE)/*就绪状态为true*/{/*如果该任务处于就绪态,那么这个任务已不是处在它原来优先级上的就绪态*/ OSRdyGrp |= ptcb->OSTCBBitY;OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;} else/*就绪状态为false*/{pevent2 = ptcb->OSTCBEventPtr;if (pevent2 != (OS_EVENT *)0) /*将事件控制块添加到事件等待列表中*/{ pevent2->OSEventGrp |= ptcb->OSTCBBitY;pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;}}OSTCBPrioTbl[pip] = ptcb;/*使占用mutex的任务以PIP优先级进入就绪态*/}}
上述过程如下图所示:
此外还想多说一句:
OSTCBPrioTbl[pip] = ptcb;/*使占用mutex的任务以PIP优先级进入就绪态*/
下面这行语句为什么一定要让任务以pip优先级进入就绪态?
个人理解是:对互斥量的操作中,pip的设置是为了防止优先级反转。在操作时,要时刻保持任务是以最高优先级存在,否则就可能发生反转。
如果互斥量不可获取,进行完上面的判断和操作后,后续的操作为:
OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /*无法获得互斥量,将该任务挂起*/OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK;/*挂起状态设置为OS_STAT_PEND_OK*/OSTCBCur->OSTCBDly = timeout;OS_EventTaskWait(pevent); /*任务处于阻塞状态,知道事件发生或超时*/ OS_EXIT_CRITICAL();/*退出中断*/OS_Sched(); /* 找到就绪的最高优先级任务进行调度*/OS_ENTER_CRITICAL();/*进入中断*/switch (OSTCBCur->OSTCBStatPend)/*看挂起的原因是什么?超时还是任务被取消*/{ case OS_STAT_PEND_OK:*perr = OS_ERR_NONE;break;case OS_STAT_PEND_ABORT:*perr = OS_ERR_PEND_ABORT; break;case OS_STAT_PEND_TO:default:OS_EventTaskRemove(OSTCBCur, pevent);*perr = OS_ERR_TIMEOUT; break;}OSTCBCur->OSTCBStat = OS_STAT_RDY; /*将任务状态设置为就绪态*/OSTCBCur->OSTCBStatPend = OS_STAT_PEND_OK; /*清除挂起状态 */OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0; /* 清除事件指针*/
#if (OS_EVENT_MULTI_EN > 0u)OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endifOS_EXIT_CRITICAL();/*退出中断*/
}
释放一个互斥型信号量OSMutexPost (OS_EVENT *pevent):
/*$PAGE*/
/*2018/2/19
*********************************************************************************************************
* POST TO A MUTUAL EXCLUSION SEMAPHORE
* 释放一个互斥型信号量
* Description: This function signals a mutual exclusion semaphore
*描述:调用OSMutexPost()可以发出mutex
* Arguments : pevent is a pointer to the event control block associated with the desired mutex.
*参数: --pevent:指向有互斥量的事件控制块的指针。
* Returns : OS_ERR_NONE The call was successful and the mutex was signaled.
* OS_ERR_EVENT_TYPE If you didn't pass a pointer to a mutex
* OS_ERR_PEVENT_NULL 'pevent' is a NULL pointer
* OS_ERR_POST_ISR Attempted to post from an ISR (not valid for MUTEXes)
* OS_ERR_NOT_MUTEX_OWNER The task that did the post is NOT the owner of the MUTEX.
* OS_ERR_PIP_LOWER If the priority of the new task that owns the Mutex is
* HIGHER (i.e. a lower number) than the PIP. This error
* indicates that you did not set the PIP higher (lower
* number) than ALL the tasks that compete for the Mutex.
* Unfortunately, this is something that could not be
* detected when the Mutex is created because we don't know
* what tasks will be using the Mutex.返回值:OS_ERR_NONE:调用成功,发出mutex;OS_ERR_EVENT_TYPE:没有指向mutex的指针;OS_ERR_PEVENT_NULL:pevent为空指针;OS_ERR_POST_ISR:从中断服务子程序中调用;OS_ERR_NOT_MUTEX_OWNER:发出信号的任务没有占用互斥量。OS_ERR_PIP_LOWER:拥有互斥量的任务的优先级比pip高。
*********************************************************************************************************
*/INT8U OSMutexPost (OS_EVENT *pevent)
{INT8U pip;/*继承优先级*/INT8U prio;#if OS_CRITICAL_METHOD == 3u OS_CPU_SR cpu_sr = 0u;#endifif (OSIntNesting > 0u){ return (OS_ERR_POST_ISR); }#if OS_ARG_CHK_EN > 0uif (pevent == (OS_EVENT *)0) { return (OS_ERR_PEVENT_NULL);}#endifif (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { return (OS_ERR_EVENT_TYPE);}OS_ENTER_CRITICAL();/*进入中断*/pip = (INT8U)(pevent->OSEventCnt >> 8u); /*获取pip*/prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/*获取拥有互斥量的任务的原始优先级*/if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr)/*当前任务没有占有互斥量*/{ OS_EXIT_CRITICAL();/*退出中断*/return (OS_ERR_NOT_MUTEX_OWNER);//发出mutex的任务实际上并不占用mutex}if (OSTCBCur->OSTCBPrio == pip) /*当前任务优先级是pip,不需要提高优先级*/{ OSMutex_RdyAtPrio(OSTCBCur, prio); /*保存任务原始优先级,任务完成后进行恢复*/}OSTCBPrioTbl[pip] = OS_TCB_RESERVED; /*将pip对应在优先级表上的值设为reserved*/if (pevent->OSEventGrp != 0u) /*如果有任务正在等待互斥量,将最高优先级任务设置为就绪态*/{ prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);/*转为就绪态任务的优先级*/pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /*新占用mutex的任务保存高8位(PIP) */pevent->OSEventCnt |= prio;/*将新任务优先级存放在低八位*/pevent->OSEventPtr = OSTCBPrioTbl[prio];/*指针指向新任务的TCB*/if (prio <= pip) /*当前任务比pip优先级高*/{ OS_EXIT_CRITICAL();/*退出中断*/ OS_Sched();/*找到最高优先级任务进行调度*/return (OS_ERR_PIP_LOWER);/*返回错误值*/} else/*当前任务比pip优先级低*/{OS_EXIT_CRITICAL();/*退出中断*/OS_Sched();/*找到最高优先级任务进行调度*/return (OS_ERR_NONE);/*返回无错*/}}/*如果没有任务等待互斥量*/pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /*互斥量是可获得的 */pevent->OSEventPtr = (void *)0;OS_EXIT_CRITICAL();return (OS_ERR_NONE);
}
该函数实际上是通知是否mutex为空闲的。如果当前的任务没有占用该互斥量,返回OS_ERR_NOT_MUTEX_OWNER,即发出mutex的任务不占用互斥量。如果当前任务占用互斥量,看看是否有任务正在等待这个互斥量。如果有任务等待,那么在当前任务完成之前,将等待列表中的优先级最高的任务转为就绪态。等当前任务完成,该任务就可以执行了。如果没有任务等待该互斥量,就只简单的发出“该互斥量是可获得的”信号即可。
查询互斥量信息OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *p_mutex_data):
/*$PAGE*/
/*2018/2/19
*********************************************************************************************************
* QUERY A MUTUAL EXCLUSION SEMAPHORE
* 查询互斥量
* Description: This function obtains information about a mutex
*描述:该功能获得关于互斥量的信息。
* Arguments : pevent is a pointer to the event control block associated with the desired mutex
*参数: --pevent:指向需要互斥量的事件控制块的指针
* p_mutex_data is a pointer to a structure that will contain information about the mutex
* -- p_mutex_data :指向结构体的指针,该结构体包含互斥量的信息
* Returns : OS_ERR_NONE The call was successful and the message was sent
* OS_ERR_QUERY_ISR If you called this function from an ISR
* OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer
* OS_ERR_PDATA_NULL If 'p_mutex_data' is a NULL pointer
* OS_ERR_EVENT_TYPE If you are attempting to obtain data from a non mutex.返回值:OS_ERR_NONE:调用成功,消息也被发出。OS_ERR_QUERY_ISR:从中断服务子程序中调用该函数;OS_ERR_PEVENT_NULL:pevent为空指针;OS_ERR_PDATA_NULL:p_mutex_data为空指针;OS_ERR_EVENT_TYPE:获得消息对象错误。
*********************************************************************************************************
*/#if OS_MUTEX_QUERY_EN > 0u
INT8U OSMutexQuery (OS_EVENT *pevent,OS_MUTEX_DATA *p_mutex_data)
{INT8U i;OS_PRIO *psrc;OS_PRIO *pdest;
OS_ENTER_CRITICAL();/*进入中断*/p_mutex_data->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8u);/*获取pip*/p_mutex_data->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);/*获取拥有互斥量的任务的优先级*/if (p_mutex_data->OSOwnerPrio == 0xFFu) /*如果占用mutex任务的优先级为255时*/{p_mutex_data->OSValue = OS_TRUE; /*当前mutex的值。1表示可以使用。*/} else{p_mutex_data->OSValue = OS_FALSE;//当前mutex的值。0表示不能使用}/*将事件(互斥型信号量)结构中的等待任务列表复制到pdata数据结构中*/p_mutex_data->OSEventGrp = pevent->OSEventGrp; /*等待事件的任务组中的内容传送到状态数据结构中*/psrc = &pevent->OSEventTbl[0];/*保存pevent->OSEventTbl[0]对应的地址*/pdest = &p_mutex_data->OSEventTbl[0];/*保存pdata->OSEventTbl[0]对应的地址*/for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {*pdest++ = *psrc++;/*地址指针继续下移一个类型地址,获取互斥型信号量的值*/}OS_EXIT_CRITICAL();/*退出中断*/return (OS_ERR_NONE);
}
#endif
该功能是将之前为了防止优先级反转而提高的任务的优先级恢复。
到此,OS_mutex.c文件就看完了。
这个文件重点是介绍信号量的获取、建立、删除、挂起等待、查询和释放(通知)。
os_mutex.c(全)相关推荐
- os_mutex.c
定位到uCOS-II/Source/os_mutex.c,该文件是互斥型信号量的相关操作函数.互斥型信号量也就是互斥锁Mutex,是一个二值(0/1)信号量.在操作共享资源时,使用Mutex可以保 ...
- 2022-2028年中国文化产业园投资分析及前景预测报告(全卷)
[报告类型]产业研究 [报告价格]¥4500起 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了中国文化行业市场行业相关概述.中国文化行业 ...
- 2022-2028年中国滑雪产业投资分析及前景预测报告(全卷)
[报告类型]产业研究 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了滑雪行业相关概述.中国滑雪行业运行环境.分析了中国滑雪行业的现状.中 ...
- 人工智能3d建模算法_打破国外垄断,全国产3D芯片为机器人“点睛”
◎ 科技日报记者 崔爽 传统机器人只有"手",只能在固定好的点位上完成既定操作,而新一轮人工智能技术大大推动了机器和人的协作,这也对机器人的灵活性有了更高要求. 要想像人一样测量. ...
- 2022-2028年中国木门行业投资分析及前景预测报告(全卷)
[报告类型]产业研究 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了木门行业相关概述.中国木门行业运行环境.分析了中国木门行业的现状.中 ...
- 2022-2028年中国新零售行业深度调研及投资前景预测报告(全卷)
[报告类型]产业研究 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了新零售行业相关概述.中国新零售行业运行环境.分析了中国新零售行业的现 ...
- 2022-2028年中国电动牙刷行业深度调研及投资前景预测报告(全卷)
[报告类型]产业研究 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了电动牙刷行业相关概述.中国电动牙刷行业运行环境.分析了中国电动牙刷行 ...
- 2022-2028年中国纺织服装专业市场深度调研及前景预测报告(全卷)
[报告类型]产业研究 [出版时间]即时更新(交付时间约3个工作日) [发布机构]智研瞻产业研究院 [报告格式]PDF版 本报告介绍了纺织服装行业相关概述.中国纺织服装行业运行环境.分析了中国纺织服装行 ...
- NumPy — 创建全零、全1、空、arange 数组,array 对象类型,astype 转换数据类型,数组和标量以及数组之间的运算,NumPy 数组共享内存
NumPy 简介 一个用 python 实现的科学计算包.包括: 1.一个强大的 N 维数组对象 Array : 2.比较成熟的(广播)函数库: 3.用于整合 C/C++ 和 Fortran 代码的工 ...
最新文章
- 1.JSONObject与JSONArray的使用
- Vivado下生成及烧写MCS文件
- 程序员修神之路--做好分库分表其实很难之二
- 网络规划设计师考试说明
- 关于http协议中的服务器状态情况
- Java中包、导包、修饰符和内部类
- 在Gilt使用Scala、Docker和AWS演化微服务
- c语言心算抢答系统,心算抢答系统2.doc
- 企业邮箱怎么换服务器,如何更换企业邮箱
- (思科模拟器)三层交换机dhcp动态获取,ping通不同vlan ,连通外网
- [VB.NET]vb.net如何捕捉摄相头的视频
- ReactOS 代码更新后的编译安装
- svg 动画_30个很棒的SVG动画
- 弓形锯床主传动及工作机构设计
- java parser .java_Stanford Parser使用之 Eclipse+java调用
- 【STM32】 电解电容
- 一个简单的连续变焦红外镜头的从零开始的设计过程(zemax)(一)
- 轨道运营管理专业自荐书_城市轨道交通运营服务与管理求职自荐信 (共3篇).doc...
- 你还记得几个腾讯的开源项目,这十个你用过吗
- 关于排行榜的算法经验谈