实现原理
相比于二进制信号量的实现,互斥信号量增加了优先级天花板算法和优先级继承算法的支持。
- 请求成功时需要记录使用线程信息和优先级。
- 请求失败时增加了对递归调用的检查和处理。
- 请求失败时根据不同算法尝试提升使用线程的优先级。
- 释放时要还原线程优先级。
- 释放时还要将使用线程信息和优先级改为恢复线程的信息。
实现源码
/*********************************************************************************************************
** 函数名称: API_SemaphoreMCreate
** 功能描述: 互斥信号量建立
** 输 入 :
** pcName 事件名缓冲区
** ucCeilingPriority 如果使用天花板优先级机制,此参数为天花板优先级
** ulOption 事件选项 推荐使用 PRIORITY 队列和 DELELTE SAFE 选项
** pulId 事件ID指针
** 输 出 : 事件句柄
*********************************************************************************************************/
LW_OBJECT_HANDLE API_SemaphoreMCreate (CPCHAR pcName,
UINT8 ucCeilingPriority,
ULONG ulOption,
LW_OBJECT_ID *pulId)
{
REGISTER PLW_CLASS_EVENT pevent;
REGISTER ULONG ulI;
PLW_CLASS_WAITQUEUE pwqTemp[2];
REGISTER ULONG ulIdTemp;
__KERNEL_MODE_PROC(
pevent = _Allocate_Event_Object(); /* 获得一个事件控制块 */
);
if (!pevent) {
return (LW_OBJECT_HANDLE_INVALID);
}
if (pcName) { /* 拷贝名字 */
lib_strcpy(pevent->EVENT_cEventName, pcName);
} else {
pevent->EVENT_cEventName[0] = PX_EOS; /* 清空名字 */
}
/* 开始初始化 */
pevent->EVENT_ucType = LW_TYPE_EVENT_MUTEX;
pevent->EVENT_ulCounter = (ULONG)LW_TRUE; /* 初始化为有效 */
pevent->EVENT_ulMaxCounter = LW_PRIO_LOWEST; /* 被用作保存线程优先级 */
pevent->EVENT_ucCeilingPriority = ucCeilingPriority; /* 天花板优先级 */
pevent->EVENT_ulOption = ulOption;
pevent->EVENT_pvPtr = LW_NULL;
pevent->EVENT_pvTcbOwn = LW_NULL;
pwqTemp[0] = &pevent->EVENT_wqWaitQ[0];
pwqTemp[1] = &pevent->EVENT_wqWaitQ[1];
pwqTemp[0]->WQ_usNum = 0; /* 没有线程 */
pwqTemp[1]->WQ_usNum = 0;
for (ulI = 0; ulI < __EVENT_Q_SIZE; ulI++) {
pwqTemp[0]->WQ_wlQ.WL_pringPrio[ulI] = LW_NULL;
pwqTemp[1]->WQ_wlQ.WL_pringPrio[ulI] = LW_NULL;
}
ulIdTemp = _MakeObjectId(_OBJECT_SEM_M,
LW_CFG_PROCESSOR_NUMBER,
pevent->EVENT_usIndex); /* 构建对象 id */
if (pulId) {
*pulId = ulIdTemp;
}
return (ulIdTemp);
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreMPend
** 功能描述: 等待互斥信号量 由于 mutext post 操作不能在中断中进行,可大大缩短关中断时间
** 输 入 :
** ulId 事件句柄
** ulTimeout 等待时间
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreMPend (LW_OBJECT_HANDLE ulId, ULONG ulTimeout)
{
INTREG iregInterLevel;
PLW_CLASS_TCB ptcbCur;
REGISTER UINT16 usIndex;
REGISTER PLW_CLASS_EVENT pevent;
REGISTER UINT8 ucPriorityIndex;
REGISTER PLW_LIST_RING *ppringList;
ULONG ulTimeSave; /* 系统事件记录 */
INT iSchedRet;
ULONG ulEventOption; /* 事件创建选项 */
usIndex = _ObjectGetIndex(ulId);
LW_TCB_GET_CUR_SAFE(ptcbCur); /* 当前任务控制块 */
pevent = &_K_eventBuffer[usIndex];
__KERNEL_ENTER(); /* 进入内核 */
//获取信号量成功
if (pevent->EVENT_ulCounter) { /* 事件有效 */
pevent->EVENT_ulCounter = LW_FALSE;
pevent->EVENT_ulMaxCounter = (ULONG)ptcbCur->TCB_ucPriority; /* 保存占用资源线程优先级 */
pevent->EVENT_pvTcbOwn = (PVOID)ptcbCur; /* 保存占用资源线程信息 */
LW_THREAD_SAFE_INKERN(ptcbCur);
__KERNEL_EXIT(); /* 退出内核 */
return (ERROR_NONE);
}
//获取信号量失败
//处理递归调用
if (!(pevent->EVENT_ulOption & LW_OPTION_NORMAL)) { /* 需要递归支持或递归检查 */
if (pevent->EVENT_pvTcbOwn == (PVOID)ptcbCur) { /* 是否是自己连续调用 */
if (pevent->EVENT_ulOption & LW_OPTION_ERRORCHECK) {
__KERNEL_EXIT(); /* 退出内核 */
return (EDEADLK);
}
/* 临时计数器++ */
pevent->EVENT_pvPtr = (PVOID)((ULONG)pevent->EVENT_pvPtr + 1);
__KERNEL_EXIT(); /* 退出内核 */
return (ERROR_NONE);
}
}
//是否需要超时
if (ulTimeout == LW_OPTION_NOT_WAIT) { /* 不等待 */
__KERNEL_EXIT(); /* 退出内核 */
return (ERROR_THREAD_WAIT_TIMEOUT);
}
_EventPrioTryBoost(pevent, ptcbCur); /* 尝试提升所属任务优先级 */
iregInterLevel = KN_INT_DISABLE(); /* 关闭中断 */
ptcbCur->TCB_iPendQ = EVENT_SEM_Q;
ptcbCur->TCB_usStatus |= LW_THREAD_STATUS_SEM; /* 写状态位,开始等待 */
ptcbCur->TCB_ucWaitTimeout = LW_WAIT_TIME_CLEAR; /* 清空等待时间 */
if (ulTimeout == LW_OPTION_WAIT_INFINITE) { /* 是否是无穷等待 */
ptcbCur->TCB_ulDelay = 0ul;
} else {
ptcbCur->TCB_ulDelay = ulTimeout; /* 设置超时时间 */
}
__KERNEL_TIME_GET_NO_SPINLOCK(ulTimeSave, ULONG); /* 记录系统时间 */
if (pevent->EVENT_ulOption & LW_OPTION_WAIT_PRIORITY) { /* 按优先级等待 */
_EVENT_INDEX_Q_PRIORITY(ptcbCur->TCB_ucPriority, ucPriorityIndex);
_EVENT_PRIORITY_Q_PTR(EVENT_SEM_Q, ppringList, ucPriorityIndex);
ptcbCur->TCB_ppringPriorityQueue = ppringList; /* 记录等待队列位置 */
_EventWaitPriority(pevent, ppringList); /* 加入优先级等待表 */
} else { /* 按 FIFO 等待 */
_EVENT_FIFO_Q_PTR(EVENT_SEM_Q, ppringList); /* 确定 FIFO 队列的位置 */
_EventWaitFifo(pevent, ppringList); /* 加入 FIFO 等待表 */
}
KN_INT_ENABLE(iregInterLevel); /* 使能中断 */
ulEventOption = pevent->EVENT_ulOption;
__KERNEL_EXIT(); /* 调度器解锁 */
if (ptcbCur->TCB_ucWaitTimeout == LW_WAIT_TIME_OUT) { /* 等待超时 */
return (ERROR_THREAD_WAIT_TIMEOUT);
} else {
if (ptcbCur->TCB_ucIsEventDelete == LW_EVENT_EXIST) { /* 事件是否存在 */
return (ERROR_NONE); /* 释放操作已将此任务设为安全 */
} else {
return (ERROR_EVENT_WAS_DELETED);
}
}
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreMPost
** 功能描述: 释放互斥信号量, 不可在中断中操作
** 输 入 :
** ulId 事件句柄
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreMPost (LW_OBJECT_HANDLE ulId)
{
INTREG iregInterLevel;
PLW_CLASS_TCB ptcbCur;
REGISTER UINT16 usIndex;
REGISTER PLW_CLASS_EVENT pevent;
REGISTER PLW_CLASS_TCB ptcb;
REGISTER PLW_LIST_RING *ppringList; /* 等待队列地址 */
usIndex = _ObjectGetIndex(ulId);
LW_TCB_GET_CUR_SAFE(ptcbCur); /* 当前任务控制块 */
pevent = &_K_eventBuffer[usIndex];
__KERNEL_ENTER(); /* 进入内核 */
if (pevent->EVENT_pvPtr) { /* 检测是否进行了递归调用 */
pevent->EVENT_pvPtr = (PVOID)((ULONG)pevent->EVENT_pvPtr - 1); /* 临时计数器-- */
__KERNEL_EXIT(); /* 退出内核 */
return (ERROR_NONE);
}
iregInterLevel = KN_INT_DISABLE();
if (_EventWaitNum(EVENT_SEM_Q, pevent)) {
if (pevent->EVENT_ulOption & LW_OPTION_WAIT_PRIORITY) { /* 优先级等待队列 */
_EVENT_DEL_Q_PRIORITY(EVENT_SEM_Q, ppringList); /* 激活优先级等待线程 */
ptcb = _EventReadyPriorityLowLevel(pevent, LW_NULL, ppringList);
} else {
_EVENT_DEL_Q_FIFO(EVENT_SEM_Q, ppringList); /* 激活FIFO等待线程 */
ptcb = _EventReadyFifoLowLevel(pevent, LW_NULL, ppringList);
}
KN_INT_ENABLE(iregInterLevel);
_EventPrioTryResume(pevent, ptcbCur); /* 尝试返回之前的优先级 */
pevent->EVENT_ulMaxCounter = (ULONG)ptcb->TCB_ucPriority;
pevent->EVENT_pvTcbOwn = (PVOID)ptcb; /* 保存线程信息 */
_EventReadyHighLevel(ptcb, LW_THREAD_STATUS_SEM); /* 处理 TCB */
if (pevent->EVENT_ulOption & LW_OPTION_DELETE_SAFE) {
LW_THREAD_SAFE_INKERN(ptcb); /* 将激活任务设置为安全 */
}
__KERNEL_EXIT(); /* 退出内核 */
if (pevent->EVENT_ulOption & LW_OPTION_DELETE_SAFE) { /* 本任务退出安全模式 */
LW_THREAD_UNSAFE();
}
return (ERROR_NONE);
} else { /* 没有线程等待 */
KN_INT_ENABLE(iregInterLevel);
if (pevent->EVENT_ulCounter == LW_FALSE) { /* 检查是否还有空间加 */
pevent->EVENT_ulCounter = (ULONG)LW_TRUE;
pevent->EVENT_ulMaxCounter = LW_PRIO_LOWEST; /* 清空保存信息 */
pevent->EVENT_pvTcbOwn = LW_NULL;
__KERNEL_EXIT(); /* 退出内核 */
if (pevent->EVENT_ulOption & LW_OPTION_DELETE_SAFE) { /* 本任务退出安全模式 */
LW_THREAD_UNSAFE();
}
return (ERROR_NONE);
} else { /* 已经满了 */
__KERNEL_EXIT(); /* 退出内核 */
_ErrorHandle(ERROR_EVENT_FULL);
return (ERROR_EVENT_FULL);
}
}
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreMDelete
** 功能描述: 互斥信号量删除, 因为MUTEX的所有操作函数均不能在中断中运行,所以这里不用关中断
** 输 入 :
** pulId 事件句柄指针
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreMDelete (LW_OBJECT_HANDLE *pulId)
{
INTREG iregInterLevel;
REGISTER ULONG ulOptionTemp;
REGISTER UINT16 usIndex;
REGISTER UINT8 ucPriority;
REGISTER PLW_CLASS_EVENT pevent;
REGISTER PLW_CLASS_TCB ptcb;
REGISTER PLW_LIST_RING *ppringList; /* 等待队列地址 */
REGISTER LW_OBJECT_HANDLE ulId;
ulId = *pulId;
usIndex = _ObjectGetIndex(ulId);
pevent = &_K_eventBuffer[usIndex];
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核 */
_ObjectCloseId(pulId); /* 清除句柄 */
pevent->EVENT_ucType = LW_TYPE_EVENT_UNUSED; /* 事件类型为空 */
while (_EventWaitNum(EVENT_SEM_Q, pevent)) { /* 是否存在正在等待的任务 */
if (pevent->EVENT_ulOption & LW_OPTION_WAIT_PRIORITY) { /* 优先级等待队列 */
_EVENT_DEL_Q_PRIORITY(EVENT_SEM_Q, ppringList); /* 激活优先级等待线程 */
ptcb = _EventReadyPriorityLowLevel(pevent, LW_NULL, ppringList);
} else {
_EVENT_DEL_Q_FIFO(EVENT_SEM_Q, ppringList); /* 激活FIFO等待线程 */
ptcb = _EventReadyFifoLowLevel(pevent, LW_NULL, ppringList);
}
KN_INT_ENABLE(iregInterLevel);
ptcb->TCB_ucIsEventDelete = LW_EVENT_DELETE; /* 事件已经被删除 */
_EventReadyHighLevel(ptcb, LW_THREAD_STATUS_SEM); /* 处理 TCB */
iregInterLevel = KN_INT_DISABLE();
}
KN_INT_ENABLE(iregInterLevel); /* 允许当前 CPU 中断 */
ptcb = (PLW_CLASS_TCB)pevent->EVENT_pvTcbOwn; /* 获得拥有者 TCB */
pevent->EVENT_pvTcbOwn = LW_NULL;
if (ptcb) {
ucPriority = (UINT8)pevent->EVENT_ulMaxCounter; /* 获得原线程优先级 */
if (!LW_PRIO_IS_EQU(ucPriority, ptcb->TCB_ucPriority)) { /* 拥有者优先级发生了变化 */
_SchedSetPrio(ptcb, ucPriority); /* 还原 优先级 */
}
}
_Free_Event_Object(pevent); /* 交还控制块 */
ulOptionTemp = pevent->EVENT_ulOption; /* 暂存选项 */
__KERNEL_EXIT(); /* 退出内核 */
if (ptcb) {
if (ulOptionTemp & LW_OPTION_DELETE_SAFE) { /* 退出安全模式 */
LW_THREAD_UNSAFE_EX(ptcb);
}
}
return (ERROR_NONE);
}