摘要:
本文介绍了Contiki主要数据结构之事件,深入源码分析事件结构体,图示事件队列,并介绍事件处理和新事件加入是如何影响事件队列的。
一、事件
1.1 事件结构体
事件也是Contiki重要的数据结构,其定义如下:
-
struct event_data
-
{
-
process_event_t ev;
-
process_data_t data;
-
struct process *p;
-
};
-
-
typedef unsigned char process_event_t;
-
typedef void * process_data_t;
各成员变量含义如下:
ev-----标识所产生事件
data---保存事件产生时获得的相关信息,即事件产生后可以给进程传递的数据
p------指向监听该事件的进程
1.2 事件分类
事件可以被分为三类:时钟事件(timer events)、外部事件、内部事件。那么,Contiki核心数据结构就只有进程和事件了,把etimer理解成一种特殊的事件。
二、 事件队列
Contiki用环形队列组织所有事件(用数组存储),如下:
-
static struct event_data events[PROCESS_CONF_NUMEVENTS];
图示事件队列如下:
上图源文件,点这里下载 Contiki事件队列图示.rar
三、系统定义的事件
3.1 系统事件
系统定义了10个事件,源码和注释如下:
-
/*配置系统最大事件数*/
-
#ifndef PROCESS_CONF_NUMEVENTS
-
#define PROCESS_CONF_NUMEVENTS 32
-
#endif
-
-
#define PROCESS_EVENT_NONE 0x80 //函数dhcpc_request调用handle_dhcp(PROCESS_EVENT_NONE,NULL)
-
#define PROCESS_EVENT_INIT 0x81 //启动一个进程process_start,通过传递该事件
-
#define PROCESS_EVENT_POLL 0x82 //在PROCESS_THREAD(etimer_process, ev, data)使用到
-
#define PROCESS_EVENT_EXIT 0x83 //进程退出,传递该事件给进程主体函数thread
-
#define PROCESS_EVENT_SERVICE_REMOVED 0x84
-
#define PROCESS_EVENT_CONTINUE 0x85 //PROCESS_PAUSE宏用到这个事件
-
#define PROCESS_EVENT_MSG 0x86
-
#define PROCESS_EVENT_EXITED 0x87 //进程退出,传递该事件给其他进程
-
#define PROCESS_EVENT_TIMER 0x88 //etimer到期时,传递该事件
-
#define PROCESS_EVENT_COM 0x89
-
#define PROCESS_EVENT_MAX 0x8a /*进程初始化时,让lastevent=PROCESS_EVENT_MAX,即新产生的事件从0x8b开始,函数process_alloc_event用于分配一个新的事件*/
注:PROCESS_EVENT_EXIT与PROCESS_EVENT_EXITED区别
事件PROCESS_EVENT_EXIT用于传递给进程的主体函数thread,如在exit_process函数中的p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL)。而PROCESS_EVENT_EXITED用于传递给进程,如call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p)。(助记:EXITED是完成式,发给进程,让整个进程结束。而一般式EXIT,发给进程主体thread,只是使其退出thread) 进程结束和退出thread有何区别?
3.2 一个特殊事件
如果事件结构体event_data的成员变量p指向PROCESS_BROADCAST,则该事件是一个广播事件(为么不用一个特殊事件来标识广播事件,而采用这种费解方式?)。在do_event函数中,若事件的p指向的是PROCESS_BROADCAST,则让进程链表process_list所有进程投入运行。详情见博文《Contiki学习笔记:深入理解process_run函数》2.2,部分源码如下:
-
#define PROCESS_BROADCAST NULL //广播进程
-
-
/*保存待处理事件的成员变量*/
-
ev = events[fevent].ev;
-
data = events[fevent].data;
-
receiver = events[fevent].p;
-
-
if (receiver == PROCESS_BROADCAST)
-
{
-
for (p = process_list; p != NULL; p = p->next)
-
{
-
if (poll_requested)
-
{
-
do_poll();
-
}
-
call_process(p, ev, data);
-
}
-
}