我们需要了解事件控制块一般是不需要直接使用的,是作为信号量,消息队列等的底层

事件控制块的原理和创建

typedef enum  _tEventType {   
    tEventTypeUnknown   = 0, 				// 未知类型
 }tEventType;
// Event控制结构
typedef struct _tEvent {
    tEventType type;						// Event类型
    tList waitList;							// 任务等待列表
}tEvent;

增加tEvent结构体,目前存放等待列表和Event类型

    // 任务正在等待的事件类型
    struct _tEvent * waitEvent;
    // 等待事件的消息存储位置
    void * eventMsg;
    // 等待事件的结果
    uint32_t waitEventResult;

在tTask加入以上内容,用于保存事件内容状态

void tEventInit (tEvent * event, tEventType type)
{
	event->type = type;
	tListInit(&event->waitList);
}

初始化主要是对类型初始化,以及等待列表

事件等待与通知

这里相比之前,又引入了新的任务状态,也就是等待状态,由事件控制块管理

void tEventWait (tEvent * event, tTask * task, void * msg, uint32_t state, uint32_t timeout)
{
  // 进入临界区
   uint32_t status = tTaskEnterCritical();
  task->state |= state;         // 标记任务处于等待某种事件的状态
  task->waitEvent = event;        // 设置任务等待的事件结构
  task->eventMsg = msg;         // 设置任务等待事件的消息存储位置 
                      // 因有时候需要接受消息,所以需要接受区
  task->waitEventResult = tErrorNoError;  // 清空事件的等待结果
  // 将任务从就绪队列中移除
  tTaskSchedUnRdy(task);
  // 将任务插入到等待队列中
  tListAddLast(&event->waitList, &task->linkNode);
  // 如果发现有设置超时,在同时插入到延时队列中
  // 当时间到达时,由延时处理机制负责将任务从延时列表中移除,同时从事件列表中移除
  if (timeout) 
  {
    tTimeTaskWait(task, timeout);
  }
  // 退出临界区
    tTaskExitCritical(status); 
}
tTask * tEventWakeUp (tEvent * event, void * msg, uint32_t result)
{
    tNode  * node;
    tTask  * task = (tTask * )0;
    // 进入临界区
    uint32_t status = tTaskEnterCritical();
    // 取出等待队列中的第一个结点
    if((node = tListRemoveFirst(&event->waitList)) != (tNode *)0)
    {                        
      // 转换为相应的任务结构                                          
        task = (tTask *)tNodeParent(node, tTask, linkNode);
        // 设置收到的消息、结构,清除相应的等待标志位
        task->waitEvent = (tEvent *)0;
        task->eventMsg = msg;
        task->waitEventResult = result;
        task->state &= ~TINYOS_TASK_WAIT_MASK;
        // 任务申请了超时等待,这里检查下,将其从延时队列中移除
        if (task->delayTicks != 0)
        { 
            tTimeTaskWakeUp(task);
        }
        // 将任务加入就绪队列
        tTaskSchedRdy(task);        
    }  
    // 退出临界区
    tTaskExitCritical(status); 
    return task;         
}
void tEventRemoveTask (tTask * task, void * msg, uint32_t result)
{     
 	  // 进入临界区
    uint32_t status = tTaskEnterCritical();
	 // 将任务从所在的等待队列中移除
	 // 注意,这里没有检查waitEvent是否为空。既然是从事件中移除,那么认为就不可能为空
	 tListRemove(&task->waitEvent->waitList, &task->linkNode);
  	// 设置收到的消息、结构,清除相应的等待标志位
    task->waitEvent = (tEvent *)0;
    task->eventMsg = msg;
   	task->waitEventResult = result;
	 task->state &= ~TINYOS_TASK_WAIT_MASK;
	// 退出临界区
    tTaskExitCritical(status); 
}

分为三个函数,可以通俗的理解为挂起事件控制块,唤醒事件控制块和删除事件

tEventWait主要内容是先设置状态和传给task参数,然后移除就绪队列,添加进入等待队列中,最后再查看是否有超时参数,有则加入延时队列,至于调度,由于这些是用于底层的,所以以上函数并不会出现调度函数,调度处理主要是在更细致的控制块中

tEventWakeUp中,首先取出等待列表中的任务,直接移出延时队列,加入就绪队列

tEventRemoveTask中,删除的是一个任务正在等待的事件,最后再设置标志位等参数

事件控制块的清空和状态查询

事件控制块清空

uint32_t tEventRemoveAll (tEvent * event, void * msg, uint32_t result)
{
    tNode  * node;
    uint32_t count;
    // 进入临界区
    uint32_t status = tTaskEnterCritical();
    // 获取等待中的任务数量
    count = tListCount(&event->waitList);
    // 遍历所有等待中的任务
    while ((node = tListRemoveFirst(&event->waitList)) != (tNode *)0)
    {                                                                   
        // 转换为相应的任务结构                                          
        tTask * task = (tTask *)tNodeParent(node, tTask, linkNode);
        // 设置收到的消息、结构,清除相应的等待标志位
        task->waitEvent = (tEvent *)0;
        task->eventMsg = msg;
        task->waitEventResult = result;
        task->state &= ~TINYOS_TASK_WAIT_MASK;
        // 任务申请了超时等待,这里检查下,将其从延时队列中移除
        if (task->delayTicks != 0)
        { 
            tTimeTaskWakeUp(task);
        }
        // 将任务加入就绪队列
        tTaskSchedRdy(task);        
    }  
    // 退出临界区
    tTaskExitCritical(status); 
    return  count;
}

不难看出,tEventRemoveAll相比tEventRemoveTask多了一个while循环,直到event中等待列表删除干净,也就是tListRemoveFirst返回0即可

事件控制块状态查询

uint32_t tEventWaitCount (tEvent * event)
{  
    uint32_t count = 0;
    // 进入临界区
    uint32_t status = tTaskEnterCritical();
    count = tListCount(&event->waitList);  
    // 退出临界区
    tTaskExitCritical(status);     
    return count;
} 

对于事件控制块所需要的只有等待列表中任务数量,所以只需要查询等待列表中任务数量