实现原理
- 事件集不使用事件控制块,而是使用事件集控制块,因此与信号消息队列有很大的不同。
- 与其他系统资源类似,该系统还通过单向链表定义了事件集控制块数组,并进行分配和回收。
- 事件集是一个32位的集合,有多组匹配模式可供选择。
- 只有在get只有在多个线程中才能阻塞;set时才能唤醒阻塞的线程,set叠加结果与任何地方匹配get唤醒目标。
- 事件集只需要一个阻塞链表。
- 由于线程删除、重启、唤醒等操作也会从相应的事件集中删除线程,但本文不涉及这些操作。
- get如果目标匹配,则直接退出,否则进入阻塞状态,等待set时间遍历阻塞链表,如有匹配,则唤醒。
- set如果有目标匹配,可以选择这个set或清楚所有事件。
实现源码
事件集控制块操作
事件集控制块结构:
typedef struct {
/* 事件集 */ LW_LIST_MONO EVENTSET_monoResrcList; /* 空闲资源表 */ UINT8 EVENTSET_ucType; /* 类型 */ PLW_LIST_LINE EVENTSET_plineWaitList; /* 指向第一个等待线程 */ ULONG EVENTSET_ulEventSets; /* 32 bit 事件位 */ ULONG EVENTSET_ulOption; /* 事件集选项 */ UINT16 EVENTSET_usIndex; /* 数组中的索引 */ CHAR EVENTSET_cEventSetName[LW_CFG_OBJECT_NAME_SIZE]; /* 事件标志组名 */ } LW_CLASS_EVENTSET; typedef LW_CLASS_EVENTSET *PLW_CLASS_EVENTSET;
事件集节点结构:
typedef struct {
/* 事件集节点 */ LW_LIST_LINE EVENTSETNODE_lineManage; /* 事件标志组管理表 */ PVOID EVENTSETNODE_ptcbMe; /* 指向等待任务TCB */ PVOID EVENTSETNODE_pesEventSet; /* 指向标志组 */ ULONG EVENTSETNODE_ulEventSets; /* 标志组开始等待 */ UINT8 EVENTSETNODE_ucWaitType; /* 等待类型 */ } LW_CLASS_EVENTSETNODE; typedef LW_CLASS_EVENTSETNODE *PLW_CLASS_EVENTSETNODE; typedef PLW_CLASS_EVENTSETNODE PLW_EVENTSETNODE;
全局变量定义,事件控制块资源定义
__KERNEL_EXT LW_CLASS_EVENT _K_eventBuffer[LW_CFG_MAX_EVENTS]; /* 事件控制块缓冲区 */ __KERNEL_EXT LW_CLASS_OBJECT_RESRC _K_resrcEvent; /* 管理事件对象的资源 */
事件集控制块资源初始化:
/********************************************************************************************************* ** 函数名称: _EventInit ** 功能描述: 初始化事件缓冲池 ** 输 入 : ** 输 出 : ********************************************************************************************************/
VOID _EventInit (VOID)
{
REGISTER ULONG ulI;
REGISTER PLW_CLASS_EVENT peventTemp1;
REGISTER PLW_LIST_MONO pmonoTemp1;
REGISTER PLW_CLASS_EVENT peventTemp2;
REGISTER PLW_LIST_MONO pmonoTemp2;
_K_resrcEvent.RESRC_pmonoFreeHeader = &_K_eventBuffer[0].EVENT_monoResrcList;
/* 设置资源表头 */
peventTemp1 = &_K_eventBuffer[0]; /* 指向缓冲池首地址 */
peventTemp2 = &_K_eventBuffer[1]; /* 指向缓冲池首地址 */
for (ulI = 0; ulI < ((LW_CFG_MAX_EVENTS) - 1); ulI++) {
pmonoTemp1 = &peventTemp1->EVENT_monoResrcList; /* 获得资源表 */
pmonoTemp2 = &peventTemp2->EVENT_monoResrcList; /* 获得资源表 */
peventTemp1->EVENT_ucType = LW_TYPE_EVENT_UNUSED; /* 事件类型 */
peventTemp1->EVENT_usIndex = (UINT16)ulI; /* 事件缓冲区下标 */
_LIST_MONO_LINK(pmonoTemp1, pmonoTemp2); /* 建立资源连接 */
peventTemp1++;
peventTemp2++;
}
/* 初始化最后一个节点 */
pmonoTemp1 = &peventTemp1->EVENT_monoResrcList; /* 获得资源表 */
peventTemp1->EVENT_ucType = LW_TYPE_EVENT_UNUSED; /* 事件类型 */
peventTemp1->EVENT_usIndex = (UINT16)ulI; /* 事件缓冲区下标 */
_INIT_LIST_MONO_HEAD(pmonoTemp1); /* 初始化最后节点 */
_K_resrcEvent.RESRC_pmonoFreeTail = pmonoTemp1; /* LW_CFG_MAX_EVENTS == 1 */
_K_resrcEvent.RESRC_uiUsed = 0;
_K_resrcEvent.RESRC_uiMaxUsed = 0;
}
事件集控制块分配函数:
/********************************************************************************************************* ** 函数名称: _Allocate_EventSet_Object ** 功能描述: 从空闲EventSet控件池中取出一个空闲EventSet ** 输 入 : ** 输 出 : 获得的Object地址,失败返回 NULL *********************************************************************************************************/
PLW_CLASS_EVENTSET _Allocate_EventSet_Object (VOID)
{
REGISTER PLW_LIST_MONO pmonoFree;
REGISTER PLW_CLASS_EVENTSET pesFree;
if (_LIST_MONO_IS_EMPTY(_K_resrcEventSet.RESRC_pmonoFreeHeader)) {
/* 检查缓冲区是否为空 */
return (LW_NULL);
}
pmonoFree = _list_mono_allocate_seq(&_K_resrcEventSet.RESRC_pmonoFreeHeader,
&_K_resrcEventSet.RESRC_pmonoFreeTail);
/* 获得资源 */
pesFree = _LIST_ENTRY(pmonoFree, LW_CLASS_EVENTSET,
EVENTSET_monoResrcList); /* 获得资源表容器地址 */
_K_resrcEventSet.RESRC_uiUsed++;
if (_K_resrcEventSet.RESRC_uiUsed > _K_resrcEventSet.RESRC_uiMaxUsed) {
_K_resrcEventSet.RESRC_uiMaxUsed = _K_resrcEventSet.RESRC_uiUsed;
}
return (pesFree);
}
事件集控制块回收函数:
/********************************************************************************************************* ** 函数名称: _Free_EventSet_Object ** 功能描述: 将EventSet控制块交还缓冲池 ** 输 入 : ** 输 出 : *********************************************************************************************************/
VOID _Free_EventSet_Object (PLW_CLASS_EVENTSET pesFree)
{
REGISTER PLW_LIST_MONO pmonoFree;
pmonoFree = &pesFree->EVENTSET_monoResrcList;
_list_mono_free_seq(&_K_resrcEventSet.RESRC_pmonoFreeHeader,
&_K_resrcEventSet.RESRC_pmonoFreeTail,
pmonoFree);
_K_resrcEventSet.RESRC_uiUsed--;
}
事件集接口操作
创建事件集对象:
/********************************************************************************************************* ** 函数名称: API_EventSetCreate ** 功能描述: 建立事件集 ** 输 入 : ** pcName 事件集名缓冲区 ** ulInitEvent 初始化事件 ** ulOption 事件集选项 ** pulId 事件集ID指针 ** 输 出 : 事件句柄 *********************************************************************************************************/
LW_OBJECT_HANDLE API_EventSetCreate (CPCHAR pcName,
ULONG ulInitEvent,
ULONG ulOption,
LW_OBJECT_ID *pulId)
{
REGISTER PLW_CLASS_EVENTSET pes;
REGISTER ULONG ulIdTemp;
__KERNEL_MODE_PROC(
pes = _Allocate_EventSet_Object(); /* 获得一个事件控制块 */
);
if (pcName) {
/* 拷贝名字 */
lib_strcpy(pes->EVENTSET_cEventSetName, pcName);
} else {
pes->EVENTSET_cEventSetName[0] = PX_EOS; /* 清空名字 */
}
pes->EVENTSET_ucType = LW_TYPE_EVENT_EVENTSET;
pes->EVENTSET_plineWaitList = LW_NULL;
pes->EVENTSET_ulEventSets = ulInitEvent;
pes->EVENTSET_ulOption = ulOption; /* 记录选项 */
ulIdTemp = _MakeObjectId(_OBJECT_EVENT_SET,
LW_CFG_PROCESSOR_NUMBER,
pes->EVENTSET_usIndex); /* 构建对象 id */
if (pulId) {
*pulId = ulIdTemp;
}
return (ulIdTemp);
}
释放事件集对象:
/********************************************************************************************************* ** 函数名称: API_EventSetDelete ** 功能描述: 删除事件集 ** 输 入 : ** pulId 事件句柄指针 ** 输 出 : ERROR CODE *********************************************************************************************************/
ULONG API_EventSetDelete (LW_OBJECT_HANDLE *pulId)
{
INTREG iregInterLevel;
REGISTER UINT16 usIndex;
REGISTER PLW_CLASS_EVENTSET pes;
REGISTER PLW_CLASS_EVENTSETNODE pesn;
PLW_LIST_LINE plineList;
REGISTER LW_OBJECT_HANDLE ulId;
ulId = *pulId;
usIndex = _ObjectGetIndex(ulId);
pes = &_K_esBuffer[usIndex];
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核 */
_ObjectCloseId(pulId); /* 清除句柄 */
for (plineList = pes->EVENTSET_plineWaitList; /* 表头指针 */
plineList != LW_NULL;
plineList = _list_line_get_next(plineList)) {
/* 释放所有有效线程 */
pesn = _LIST_ENTRY(plineList, LW_CLASS_EVENTSETNODE, EVENTSETNODE_lineManage);
_EventSetDeleteReady(pesn);
}
pes->EVENTSET_ucType = LW_TYPE_EVENT_UNUSED;
pes->EVENTSET_plineWaitList = LW_NULL;
_Free_EventSet_Object(pes); /* 交还缓冲区 */
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
}
将线程插入等待事件集队列:
/********************************************************************************************************* ** 函数名称: _EventSetBlock ** 功能描述: 将线程插入等待事件集队列 (进入内核且关中断状态下被调用) ** 输 入 : pes 事件组控制块 ** pesn 事件组等待节点 ** ulEvents 事件组 ** ucWaitType 等待类型 ** ulWaitTime 等待时间 ** 输 出 : NONE *********************************************************************************************************/
VOID _EventSetBlock (PLW_CLASS_EVENTSET pes,
PLW_CLASS_EVENTSETNODE pesn,
ULONG ulEvents,
UINT8 ucWaitType,
ULONG ulWaitTime)
{
REGISTER PLW_CLASS_PCB ppcb;
PLW_CLASS_TCB ptcbCur;
LW_TCB_GET_CUR(ptcbCur); /* 当前任务控制块 */
ptcbCur->TCB_usStatus |= LW_THREAD_STATUS_EVENTSET;
ptcbCur->TCB_ucWaitTimeout = LW_WAIT_TIME_CLEAR;
ptcbCur->TCB_ucIsEventDelete = LW_EVENT_EXIST;
ptcbCur->TCB_ulDelay = ulWaitTime;
if (ulWaitTime) {
__ADD_TO_WAKEUP_LINE(ptcbCur); /* 加入等待扫描链 */
}
pesn->EVENTSETNODE_pesEventSet = (PVOID)pes;
pesn->EVENTSETNODE_ulEventSets = ulEvents;
pesn->EVENTSETNODE_ucWaitType = ucWaitType;
pesn->EVENTSETNODE_ptcbMe = (PVOID)ptcbCur;
_List_Line_Add_Ahead(&pesn->EVENTSETNODE_lineManage, &pes->EVENTSET_plineWaitList);
ppcb = _GetPcb(ptcbCur);
__DEL_FROM_READY_RING(ptcbCur, ppcb); /* 从就绪环中删除 */
}
将线程从等待事件集队列中解除:
/********************************************************************************************************* ** 函数名称: _EventSetUnQueue ** 功能描述: 将线程从等待事件集队列中解除 ** 输 入 : ** 输 出 : *********************************************************************************************************/
VOID _EventSetUnQueue (PLW_CLASS_EVENTSETNODE pesn)
{
REGISTER PLW_CLASS_EVENTSET pes;
pes = (PLW_CLASS_EVENTSET)pesn->EVENTSETNODE_pesEventSet;
_List_Line_Del(&pesn->EVENTSETNODE_lineManage, &pes->EVENTSET_plineWaitList);
}
由于事件集删除,激活等待事件集队列的线程:
/********************************************************************************************************* ** 函数名称: _EventSetDeleteReady ** 功能描述: 由于事件集删除,激活等待事件集队列的线程 (进入内核并关中断后被调用) ** 输 入 : pesn 事件组控制块 ** 输 出 : 是否调度 *********************************************************************************************************/
BOOL _EventSetDeleteReady (PLW_CLASS_EVENTSETNODE pesn)
{
REGISTER PLW_CLASS_TCB ptcb;
REGISTER PLW_CLASS_PCB ppcb;
REGISTER BOOL bIsSched = LW_FALSE;
ptcb = (PLW_CLASS_TCB)pesn->EVENTSETNODE_ptcbMe;
ptcb->TCB_ucIsEventDelete = LW_EVENT_DELETE; /* 事件被删除了 */
if (ptcb->TCB_usStatus & LW_THREAD_STATUS_DELAY) {
/* 存在于 wake up 表中 */
__DEL_FROM_WAKEUP_LINE(ptcb); /* 从等待链中删除 */
}
ptcb->TCB_ulDelay = 0ul;
ptcb->TCB_ulEventSets = 0ul;
ptcb->TCB_usStatus &= (~LW_THREAD_STATUS_EVENTSET);
if (__LW_THREAD_IS_READY(ptcb)) {
/* 是否就绪 */
ptcb->TCB_ucSchedActivate = LW_SCHED_ACT_INTERRUPT;
ppcb = _GetPcb(ptcb);
__ADD_TO_READY_RING(ptcb, ppcb); /* 加入就绪表 */
bIsSched = LW_TRUE;
}
_EventSetUnQueue(pesn);
return (bIsSched);
}
激活等待事件集队列的线程:
/********************************************************************************************************* ** 函数名称: _EventSetThreadReady ** 功能描述: 激活等待事件集队列的线程 (进入内核并关中断后被调用) ** 输 入 : pesn 事件组控制块 ** ulEventsReady 新的事件标志 ** 输 出 : 是否调度 *********************************************************************************************************/
BOOL _EventSetThreadReady (PLW_CLASS_EVENTSETNODE pesn,
ULONG ulEventsReady)
{
REGISTER PLW_CLASS_TCB ptcb;
REGISTER PLW_CLASS_PCB ppcb;
REGISTER BOOL bIsSched = LW_FALSE;
ptcb = (PLW_CLASS_TCB)pesn->EVENTSETNODE_ptcbMe;
if (ptcb->TCB_usStatus & LW_THREAD_STATUS_DELAY) {
/* 存在于 wake up 表中 */
__DEL_FROM_WAKEUP_LINE(ptcb); /* 从等待链中删除 */
}
ptcb->TCB_ulDelay = 0ul;
ptcb->TCB_ulEventSets = ulEventsReady;
ptcb->TCB_usStatus &= (~LW_THREAD_STATUS_EVENTSET);
if (__LW_THREAD_IS_READY(ptcb)) {
/* 是否就绪 */
ptcb->TCB_ucSchedActivate = LW_SCHED_ACT_INTERRUPT;
ppcb = _GetPcb(ptcb);
__ADD_TO_READY_RING(ptcb, ppcb); /* 加入就绪表 */
bIsSched = LW_TRUE;
}
_EventSetUnQueue(pesn);
return (bIsSched);
}
等待事件集相关事件:
/********************************************************************************************************* MACRO *********************************************************************************************************/
#define __EVENTSET_NOT_READY() do { \ __KERNEL_EXIT_IRQ(iregInterLevel); \ _ErrorHandle(ERROR_THREAD_WAIT_TIMEOUT); \ return (ERROR_THREAD_WAIT_TIMEOUT); \ } while (0)
#define __EVENTSET_SAVE_RET() do { \ if (ulOption & LW_OPTION_EVENTSET_RETURN_ALL) { \ if (pulEvent) { \ *pulEvent = pes->EVENTSET_ulEventSets; \ } \ } else { \ if (pulEvent) { \ *pulEvent = ulEventRdy; \ } \ } \ } while (0)
/********************************************************************************************************* ** 函数名称: API_EventSetGetEx ** 功能描述: 等待事件集相关事件 ** 输 入 : ** ulId 事件集句柄 ** ulEvent 等待事件 ** ulOption 等待方法选项 ** ulTimeout 等待时间 ** pulEvent 接收到的事件 ** 输 出 : 事件句柄 *********************************************************************************************************/
ULONG API_EventSetGetEx (LW_OBJECT_HANDLE ulId,
ULONG ulEvent,
ULONG ulOption,
ULONG ulTimeout,
ULONG *pulEvent)
{
LW_CLASS_EVENTSETNODE esnNode;
INTREG iregInterLevel;
PLW_CLASS_TCB ptcbCur;
REGISTER UINT16 usIndex;
REGISTER PLW_CLASS_EVENTSET pes;
REGISTER UINT8 ucWaitType;
REGISTER ULONG ulEventRdy;
REGISTER ULONG ulWaitTime;
ULONG ulTimeSave; /* 系统事件记录 */
INT iSchedRet;
ULONG ulEventSetOption; /* 事件创建选项 */
usIndex = _ObjectGetIndex(ulId);
LW_TCB_GET_CUR_SAFE(ptcbCur); /* 当前任务控制块 */
ucWaitType = (UINT8)(ulOption & 0x0F); /* 获得等待类型 */
if (ulTimeout == LW_OPTION_WAIT_INFINITE) {
ulWaitTime = 0ul;
} else {
ulWaitTime = ulTimeout;
}
pes = &_K_esBuffer[usIndex];
iregInterLevel = __KERNEL_ENTER_IRQ(); /* 进入内核 */
switch (ucWaitType) {
case LW_OPTION_EVENTSET_WAIT_SET_ALL: /* 全部置位 */
ulEventRdy = (ulEvent & pes->EVENTSET_ulEventSets);
if (ulEvent == ulEventRdy) {
/* 事件都已经存在 */
__EVENTSET_SAVE_RET();
if (ulOption & LW_OPTION_EVENTSET_RESET) {
pes->EVENTSET_ulEventSets &= (~ulEventRdy);
} else if (ulOption & LW_OPTION_EVENTSET_RESET_ALL) {
pes->EVENTSET_ulEventSets = 0ul;
}
ptcbCur->TCB_ulEventSets = ulEventRdy;
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
} else {
if (ulTimeout == LW_OPTION_NOT_WAIT) {
/* 不等待 */
__EVENTSET_NOT_READY();
} /* 阻塞线程 */
__KERNEL_TIME_GET_NO_SPINLOCK(ulTimeSave, ULONG); /* 记录系统时间 */
_EventSetBlock(pes, &esnNode, ulEvent, ucWaitType, ulWaitTime);
}
break;
case LW_OPTION_EVENTSET_WAIT_SET_ANY:
ulEventRdy = (ulEvent & pes->EVENTSET_ulEventSets);
if (ulEventRdy) {
__EVENTSET_SAVE_RET();
if (ulOption & LW_OPTION_EVENTSET_RESET) {
pes->EVENTSET_ulEventSets &= (~ulEventRdy);
} else if (ulOption & LW_OPTION_EVENTSET_RESET_ALL) {
pes->EVENTSET_ulEventSets = 0ul;
}
ptcbCur->TCB_ulEventSets = ulEventRdy;
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
} else {
if (ulTimeout == LW_OPTION_NOT_WAIT) {
/* 不等待 */
__EVENTSET_NOT_READY();
} /* 阻塞线程 */
__KERNEL_TIME_GET_NO_SPINLOCK(ulTimeSave, ULONG); /* 记录系统时间 */
_EventSetBlock(pes, &esnNode, ulEvent, ucWaitType, ulWaitTime);
}
break;
case LW_OPTION_EVENTSET_WAIT_CLR_ALL:
ulEventRdy = (ulEvent & ~pes->EVENTSET_ulEventSets);
if (ulEvent == ulEventRdy) {
__EVENTSET_SAVE_RET();
if (ulOption & LW_OPTION_EVENTSET_RESET) {
pes->EVENTSET_ulEventSets |= ulEventRdy;
} else if (ulOption & LW_OPTION_EVENTSET_RESET_ALL) {
pes->EVENTSET_ulEventSets = __ARCH_ULONG_MAX;
}
ptcbCur->TCB_ulEventSets = ulEventRdy;
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
} else {
if (ulTimeout == LW_OPTION_NOT_WAIT) {
/* 不等待 */
__EVENTSET_NOT_READY();
} /* 阻塞线程 */
__KERNEL_TIME_GET_NO_SPINLOCK(ulTimeSave, ULONG); /* 记录系统时间 */
_EventSetBlock(pes, &esnNode, ulEvent, ucWaitType, ulWaitTime);
}
break;
case LW_OPTION_EVENTSET_WAIT_CLR_ANY:
ulEventRdy = (ulEvent & ~pes->EVENTSET_ulEventSets);
if (ulEventRdy) {
__EVENTSET_SAVE_RET();
if (ulOption & LW_OPTION_EVENTSET_RESET) {
pes->EVENTSET_ulEventSets |= ulEventRdy;
} else if (ulOption & LW_OPTION_EVENTSET_RESET_ALL) {
pes->EVENTSET_ulEventSets = __ARCH_ULONG_MAX;
}
ptcbCur->TCB_ulEventSets = ulEventRdy;
__KERNEL_EXIT_IRQ(iregInterLevel); /* 退出内核 */
return (ERROR_NONE);
} else {
if (ulTimeout == LW_OPTION_NOT_WAIT) {
/* 不等待 */
__EVENTSET_NOT_READY();
} /* 阻塞线程 */
__KERNEL_TIME_GET_NO_SPINLOCK(ulTimeSave, ULONG);