/*
** ver : 2.52
** file : os_mutex.c
** brief : 互斥型信号量相关函数 C 文件
**
** mutex : 互斥型信号量
** PIP : 优先级继承优先级
*/
#ifndef OS_MASTER_FILE
#include "includes.h" /* 包含头文件 */
#endif
/*
******************************************************************************
* 逻辑常量
******************************************************************************
*/
#define OS_MUTEX_KEEP_LOWER_8 0x00FF /* 低八位 : 标注mutex是否有效 */
#define OS_MUTEX_KEEP_UPPER_8 0xFF00 /* 高八位 : 记录优先级继承优先级 */
#define OS_MUTEX_AVAILABLE 0x00FF /* mutex有效 */
#if OS_MUTEX_EN > 0
/*
*******************************************************************************
* 无等待的获取mutex
*
* brief : 该函数用于无等待的请求mutex.
*
* pevent : 指向事件控制块的指针
*
* err : 指向错误代码的指针,可能取值:
* OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 错误的事件类型
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
* OS_ERR_PEND_ISR 不能在中断内请求
*
* Returns : == 1 mutex有效
* == 0 a) mutex无效
* b) 错误的事件控制块指针
* c) 中断内调用
*
**************************************************************************************
*/
#if OS_MUTEX_ACCEPT_EN > 0
INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
if (OSIntNesting > 0) { /* 不允许在中断内调用 */
*err = OS_ERR_PEND_ISR;
return (0);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
*err = OS_ERR_PEVENT_NULL;
return (0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 错误的事件类型 */
*err = OS_ERR_EVENT_TYPE;
return (0);
}
#endif
OS_ENTER_CRITICAL();
if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* 记录优先级 */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;
pevent->OSEventPtr = (void *)OSTCBCur; /* 链接TCB */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (1);
}
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (0);
}
#endif
/*$PAGE*/
/*
**************************************************************************************
* 创建 Mutex
*
* breif : 该函数用于创建mutex.
*
* prio : PIP
*
* err : 指向错误代码的指针,可能取值:
* OS_NO_ERR 成功.
* OS_ERR_CREATE_ISR 不允许在中断中创建mutex
* OS_PRIO_EXIST PIP的任务已经存在
* OS_ERR_PEVENT_NULL 无空余事件控制块
* OS_PRIO_INVALID 无效优先级
*
* Note(s) : 1) '.OSEventCnt' 低八位为0xFF表示mutex有效,否则为占用资源的任务优先级
* 2) '.OSEventCnt' 高八位记录PIP
***************************************************************************************
*/
OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
if (OSIntNesting > 0) { /* 不允许中断创建mutex */
*err = OS_ERR_CREATE_ISR;
return ((OS_EVENT *)0);
}
#if OS_ARG_CHK_EN > 0
if (prio >= OS_LOWEST_PRIO) { /* 无效的优先级 */
*err = OS_PRIO_INVALID;
return ((OS_EVENT *)0);
}
#endif
OS_ENTER_CRITICAL();
if (OSTCBPrioTbl[prio] != (OS_TCB *)0) { /* PIP任务已经存在 */
OS_EXIT_CRITICAL();
*err = OS_PRIO_EXIST;
return ((OS_EVENT *)0);
}
OSTCBPrioTbl[prio] = (OS_TCB *)1; /* 占用 OSTCBPrioTbl[prio] */
pevent = OSEventFreeList; /* 获取事件控制块 */
if (pevent == (OS_EVENT *)0) { /* 无剩余事件控制块可用 */
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* 释放 OSTCBPrioTbl[prio] */
OS_EXIT_CRITICAL();
*err = OS_ERR_PEVENT_NULL;
return (pevent);
}
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;/* 调整ECB链表 */
OS_EXIT_CRITICAL();
pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
pevent->OSEventCnt = (prio << 8) | OS_MUTEX_AVAILABLE;/* PIP|资源有效 */
pevent->OSEventPtr = (void *)0; /* 无任务等待 */
OS_EventWaitListInit(pevent);
*err = OS_NO_ERR;
return (pevent);
}
/*$PAGE*/
/*
**********************************************************************************
* 删除 Mutex
*
* brief : 该函数用删除 mutex
*
* pevent : 指向事件控制块的指针
*
* opt : 删除选项
* opt == OS_DEL_NO_PEND 无任务等待时删除
* opt == OS_DEL_ALWAYS 删除,如有任务等待则置为就绪
*
*
* err : 指向错误代码的指针,可能取值:
* OS_NO_ERR 成功
* OS_ERR_DEL_ISR 不允许中断中删除
* OS_ERR_INVALID_OPT 无效的删除选项
* OS_ERR_TASK_WAITING 有任务等待
* OS_ERR_EVENT_TYPE 错误的事件类型
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
*
**********************************************************************************
*/
#if OS_MUTEX_DEL_EN
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
INT8U pip;
if (OSIntNesting > 0) { /* 中断中不能删除mutex */
*err = OS_ERR_DEL_ISR;
return (pevent);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
*err = OS_ERR_PEVENT_NULL;
return ((OS_EVENT *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 无效的事件类型 */
*err = OS_ERR_EVENT_TYPE;
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00) { /* 是否有任务在等待mutex*/
tasks_waiting = TRUE;
} else {
tasks_waiting = FALSE;
}
switch (opt) {
case OS_DEL_NO_PEND: /* 无任务等待删除mutex*/
if (tasks_waiting == FALSE) {
pip = (INT8U)(pevent->OSEventCnt >> 8);
OSTCBPrioTbl[pip] = (OS_TCB *)0;/* 释放PIP,创建信号量时占用 */
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 返还事件控制块 */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return ((OS_EVENT *)0);
} else { /* 有任务等待 */
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING;
return (pevent);
}
case OS_DEL_ALWAYS: /* 无条件删除 */
while (pevent->OSEventGrp != 0x00) { /* 就绪所有等待任务 */
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
}
pip = (INT8U)(pevent->OSEventCnt >> 8);
OSTCBPrioTbl[pip] = (OS_TCB *)0; /* 释放PIP */
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 返还事件控制块 */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE) {
OS_Sched(); /* 任务调度 */
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0);
default:
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT;
return (pevent);
}
}
#endif
/*$PAGE*/
/*
*******************************************************************************
* 请求mutex
*
* brief : 该函数用来请求mutex
*
* pevent : 指向事件控制块的指针
*
* timeout : 等待超时
*
* err : 指向错误代码的指针,可能取值:
* OS_NO_ERR 成功
* OS_TIMEOUT 超时
* OS_ERR_EVENT_TYPE 错误的事件类型
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
* OS_ERR_PEND_ISR 不允许在中断中请求
*
* Note(s) : 1) 拥有mutex的任务,不能在请求任何其他mutex
* 2) 不一定非要改变任务的优先级
********************************************************************************
*/
void OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U pip; /* 优先级继承优先级(PIP) */
INT8U mprio; /* 当前占用mutex的任务优先级 */
BOOLEAN rdy; /* 任务就绪标志 */
OS_TCB *ptcb;
if (OSIntNesting > 0) { /* 中断内不能请求mutex */
*err = OS_ERR_PEND_ISR;
return;
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
*err = OS_ERR_PEVENT_NULL;
return;
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {/* 无效的事件类型 */
*err = OS_ERR_EVENT_TYPE;
return;
}
#endif
OS_ENTER_CRITICAL();
if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* mutex有效 */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* 记录优先级 */
pevent->OSEventPtr = (void *)OSTCBCur; /* 指向任务控制块 */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return;
}
/* 获取优先级继承优先级 */
pip = (INT8U)(pevent->OSEventCnt >> 8);
/* 获取占用mutex任务的优先级 */
mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
/* 获取占用mutex任务的控制块 */
ptcb = (OS_TCB *)(pevent->OSEventPtr);
/* 是否需要提升占用任务优先级*/
if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) {
if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { /* 查看是否就绪 */
/* 取消就绪 */
if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
OSRdyGrp &= ~ptcb->OSTCBBitY;
}
rdy = TRUE;
} else {
rdy = FALSE;
}
ptcb->OSTCBPrio = pip; /* 修改优先级 */
ptcb->OSTCBY = ptcb->OSTCBPrio >> 3; /* 预计算 */
ptcb->OSTCBBitY = OSMapTbl[ptcb->OSTCBY];
ptcb->OSTCBX = ptcb->OSTCBPrio & 0x07;
ptcb->OSTCBBitX = OSMapTbl[ptcb->OSTCBX];
if (rdy == TRUE) { /* 新优先级就绪 */
OSRdyGrp |= ptcb->OSTCBBitY;
OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
}
OSTCBPrioTbl[pip] = (OS_TCB *)ptcb;
}
OSTCBCur->OSTCBStat |= OS_STAT_MUTEX; /* 等待mutex状态 */
OSTCBCur->OSTCBDly = timeout; /* 记录等到超时 */
OS_EventTaskWait(pevent); /* 任务进入等待 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任务调度 */
OS_ENTER_CRITICAL();
if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) { /* 查看是否超时继续运行 */
OS_EventTO(pevent);
OS_EXIT_CRITICAL();
*err = OS_TIMEOUT; /* 超时进入就绪 */
return;
}
OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
}
/*$PAGE*/
/*
******************************************************************************
* 释放mutex
*
* brief : 该函数用于释放 mutex
*
* pevent : 指向事件控制块的指针
*
* Returns : OS_NO_ERR 成功
* OS_ERR_EVENT_TYPE 错误的事件类型
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
* OS_ERR_POST_ISR 不能自中断中释放mutex
* OS_ERR_NOT_MUTEX_OWNER 释放mutex的任务并没有占用mutex
********************************************************************************
*/
INT8U OSMutexPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U pip; /* 优先级继承优先级 */
INT8U prio;
if (OSIntNesting > 0) { /* 中断内不允许释放mutex */
return (OS_ERR_POST_ISR);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 无效的事件类型 */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pip = (INT8U)(pevent->OSEventCnt >> 8); /* 获取PIP */
/* 获取占用mutex的任务优先级 */
prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
if (OSTCBCur->OSTCBPrio != pip &&
OSTCBCur->OSTCBPrio != prio) {/* 当前任务未占有mutex */
OS_EXIT_CRITICAL();
return (OS_ERR_NOT_MUTEX_OWNER);
}
if (OSTCBCur->OSTCBPrio == pip) { /* 优先级被提升 */
/* 移除PIP的就绪 */
if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBPrio = prio; /* 修改为原来优先级 */
OSTCBCur->OSTCBY = prio >> 3; /* 预运算 */
OSTCBCur->OSTCBBitY = OSMapTbl[OSTCBCur->OSTCBY];
OSTCBCur->OSTCBX = prio & 0x07;
OSTCBCur->OSTCBBitX = OSMapTbl[OSTCBCur->OSTCBX];
OSRdyGrp |= OSTCBCur->OSTCBBitY;/* 置就绪 */
OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
OSTCBPrioTbl[prio] = (OS_TCB *)OSTCBCur;
}
OSTCBPrioTbl[pip] = (OS_TCB *)1; /* 占用OSTCBPrioTbl[pip] 请求mutex时用 */
if (pevent->OSEventGrp != 0x00) { /* 是否有任务在等待mutex */
/* 等待任务进入就绪 */
prio = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* 记录优先级 */
pevent->OSEventCnt |= prio;
pevent->OSEventPtr = OSTCBPrioTbl[prio]; /* 链接任务控制块 */
OS_EXIT_CRITICAL();
OS_Sched(); /* 任务调度 */
return (OS_NO_ERR);
}
pevent->OSEventCnt |= OS_MUTEX_AVAILABLE; /* 使mutex有效 */
pevent->OSEventPtr = (void *)0;
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
/*$PAGE*/
/*
*******************************************************************************
* 查询mutex
*
* brief : 该函数用于查询mutex
*
* pevent : 指向事件控制块的指针
*
* pdata : 保存mutex信息的数据结构指针
*
* Returns : OS_NO_ERR 成功
* OS_ERR_QUERY_ISR 不能再中断中请求
* OS_ERR_PEVENT_NULL 无效的事件控制块指针
* OS_ERR_EVENT_TYPE 错误的事件类型
********************************************************************************
*/
#if OS_MUTEX_QUERY_EN > 0
INT8U OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3
OS_CPU_SR cpu_sr;
#endif
INT8U *psrc;
INT8U *pdest;
if (OSIntNesting > 0) { /* 不允许在中断内调用 */
return (OS_ERR_QUERY_ISR);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0) { /* 无效的事件控制块指针 */
return (OS_ERR_PEVENT_NULL);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {/* 错误的事件类型 */
return (OS_ERR_EVENT_TYPE);
}
#endif
OS_ENTER_CRITICAL();
pdata->OSMutexPIP = (INT8U)(pevent->OSEventCnt >> 8);/* 优先级继承优先级 */
/* 占有mutex的任务优先级,若为0xFF则为被占用mutex有效 */
pdata->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
if (pdata->OSOwnerPrio == 0xFF) {
pdata->OSValue = 1; /* mutex有效 */
} else {
pdata->OSValue = 0; /* mutex无效 */
}
pdata->OSEventGrp = pevent->OSEventGrp; /* 复制等待任务链表 */
psrc = &pevent->OSEventTbl[0];
pdest = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 1
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 2
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 3
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 4
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 5
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 6
*pdest++ = *psrc++;
#endif
#if OS_EVENT_TBL_SIZE > 7
*pdest = *psrc;
#endif
OS_EXIT_CRITICAL();
return (OS_NO_ERR);
}
#endif
#endif
uC/OS-II源码解析(os_mutex.c)
最新推荐文章于 2021-05-27 18:18:15 发布