计数型信号量只使用事件控制块的第一个等待队列,通过EVENT_SEM_Q(0)来索引,最大计数值在创建时设置,事件类型为LW_TYPE_EVENT_SEMC。
计数型信号量的实现原理和二进制信号量极为相识,主要区别就是计数型信号量可以成功请求多次。
请先详细阅读《SylixOS里的二进制信号量实现原理详解》。
下面是各接口的实现源码,为了容易理解,这里会对源码做一些调整,包括删除一些条件编译和条件执行代码,删除一些重入保护代码,删除一些异常和错误处理,删除一些条件检查,展开一些关键宏操作,这里还去掉了信号唤醒的相关处理,增加更多注释等。
/*********************************************************************************************************
** 函数名称: API_SemaphoreCCreate
** 功能描述: 计数型信号量建立
** 输 入 :
** pcName 事件名缓冲区
** ulInitCounter 初始化计数值
** ulMaxCounter 最大计数值
** ulOption 事件选项
** pulId 事件ID指针
** 输 出 : 事件句柄
*********************************************************************************************************/
LW_OBJECT_HANDLE API_SemaphoreCCreate (CPCHAR pcName,
ULONG ulInitCounter,
ULONG ulMaxCounter,
ULONG ulOption,
LW_OBJECT_ID *pulId)
{
REGISTER PLW_CLASS_EVENT pevent;
REGISTER ULONG ulI;
PLW_CLASS_WAITQUEUE pwqTemp[2];
REGISTER ULONG ulIdTemp;
if (!ulMaxCounter) {
return (LW_OBJECT_HANDLE_INVALID);
}
if (ulInitCounter > ulMaxCounter) {
return (LW_OBJECT_HANDLE_INVALID);
}
__KERNEL_MODE_PROC(
pevent = _Allocate_Event_Object(); /* 获得一个事件控制块 */
);
if (pcName) {
/* 拷贝名字 */
lib_strcpy(pevent->EVENT_cEventName, pcName);
} else {
pevent->EVENT_cEventName[0] = PX_EOS; /* 清空名字 */
}
/* 开始初始化 */
pevent->EVENT_ucType = LW_TYPE_EVENT_SEMC;
pevent->EVENT_ulCounter = ulInitCounter;
pevent->EVENT_ulMaxCounter = ulMaxCounter;
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_C,
LW_CFG_PROCESSOR_NUMBER,
pevent->EVENT_usIndex); /* 构建对象 id */
if (pulId) {
*pulId = ulIdTemp;
}
return (ulIdTemp);
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreCPend
** 功能描述: 等待计数型信号量
** 输 入 :
** ulId 事件句柄
** ulTimeout 等待时间
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreCPend (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];
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核 */
if (pevent->EVENT_ulCounter) {
/* 事件有效 */
pevent->EVENT_ulCounter--;
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
}
if (ulTimeout == LW_OPTION_NOT_WAIT) {
/* 不等待 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_THREAD_WAIT_TIMEOUT);
}
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_SemaphoreCPost
** 功能描述: 释放计数型信号量
** 输 入 :
** ulId 事件句柄
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreCPost (LW_OBJECT_HANDLE ulId)
{
INTREG iregInterLevel;
REGISTER UINT16 usIndex;
REGISTER PLW_CLASS_EVENT pevent;
REGISTER PLW_CLASS_TCB ptcb;
REGISTER PLW_LIST_RING *ppringList; /* 等待队列地址 */
usIndex = _ObjectGetIndex(ulId);
pevent = &_K_eventBuffer[usIndex];
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核 */
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); /* 使能中断 */
_EventReadyHighLevel(ptcb, LW_THREAD_STATUS_SEM); /* 处理 TCB */
__KERNEL_EXIT(); /* 退出内核 */
return (ERROR_NONE);
} else {
/* 没有线程等待 */
if (pevent->EVENT_ulCounter < pevent->EVENT_ulMaxCounter) {
/* 检查是否还有空间加 */
pevent->EVENT_ulCounter++;
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
} else {
/* 已经满了 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_EVENT_FULL);
}
}
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreCFlush
** 功能描述: 释放等待计数型信号量的所有线程
** 输 入 :
** ulId 事件句柄
** pulThreadUnblockNum 被解锁的线程数量 可以为NULL
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreCFlush (LW_OBJECT_HANDLE ulId, ULONG *pulThreadUnblockNum)
{
INTREG iregInterLevel;
REGISTER UINT16 usIndex;
REGISTER PLW_CLASS_EVENT pevent;
REGISTER PLW_CLASS_TCB ptcb;
REGISTER PLW_LIST_RING *ppringList; /* 等待队列地址 */
usIndex = _ObjectGetIndex(ulId);
pevent = &_K_eventBuffer[usIndex];
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核 */
if (pulThreadUnblockNum) {
/* 保存将要解锁的线程数量 */
*pulThreadUnblockNum = _EventWaitNum(EVENT_SEM_Q, pevent);
}
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); /* 打开中断 */
_EventReadyHighLevel(ptcb, LW_THREAD_STATUS_SEM); /* 处理 TCB */
iregInterLevel = KN_INT_DISABLE(); /* 关闭中断 */
}
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
}
/*********************************************************************************************************
** 函数名称: API_SemaphoreCDelete
** 功能描述: 计数型信号量删除
** 输 入 :
** pulId 事件句柄指针
** 输 出 :
*********************************************************************************************************/
ULONG API_SemaphoreCDelete (LW_OBJECT_HANDLE *pulId)
{
INTREG iregInterLevel;
REGISTER UINT16 usIndex;
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(); /* 关闭中断 */
}
pevent->EVENT_pvTcbOwn = LW_NULL;
_Free_Event_Object(pevent); /* 交还控制块 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
}