contiki学习笔记03
contiki是基于事件型驱动的操作系统,它传递事件的方式有两种,同步和异步。 process_post_synch
函数是同步,调用它可以马上执行相关的线程;process_post
是异步,调用它会产生一个事件,等待下次在主函数中执行;具体看代码:
void process_post_synch(struct process *p, process_event_t ev,
process_data_t data)
{
/* 定义一个指针变量,用来存储当前线程的指针 */
struct process *caller = process_current;
/* 调用执行线程 */
call_process(p, ev, data);
/* 再赋值回来 */
process_current = caller;
}
这边第一次看的时候有个地方不懂,为什么要保存当前的线程指针,看了call_process
这个函数的实现方式后才懂,这个下面再说;同步传递事件的实现比较简单,就到此结束了。
现在来看下异步同步方式,contiki建了个数组,用来存储待处理的事件,nevents
是还未处理的事件总数,fevent
是下次将要处理的事件下标;
static process_num_events_t nevents, fevent;
static struct event_data events[PROCESS_CONF_NUMEVENTS];
其中event_data
是自定义的事件类型,里面主要有3个成员,1是事件类型,2是数据指针,3是线程指针
struct event_data
{
process_event_t ev; /* typedef unsigned char process_event_t; */
process_data_t data; /* typedef void *process_data_t; */
struct process *p;
};
下面的代码就是异步的同步方式,虽然看起来有很多,但真正发挥作用的只有不到10行代码,它第一步先判断是后已经满了(在20行),如果已经满了则退出;否则就添加到数组里面去
int process_post(struct process *p, process_event_t ev, process_data_t data)
{
/* 临时变量,用来标识当前要传递的事件放在哪里 */
process_num_events_t snum;
/* 当前没有其他线程在运行,换句话说当前传递者不是线程 */
if (PROCESS_CURRENT() == NULL)
{
PRINTF("process_post: NULL process posts event %d to process '%s', nevents %d\r\n",
ev, PROCESS_NAME_STRING(p), nevents);
}
else
{
PRINTF("process_post: Process '%s' posts event %02X to process '%s', nevents %d\r\n",
PROCESS_NAME_STRING(PROCESS_CURRENT()), ev,
p == PROCESS_BROADCAST ? "<broadcast>" : PROCESS_NAME_STRING(p), nevents);
}
/* 还未处理的线程总数已经满了(放不进来),退出 */
if (nevents == PROCESS_CONF_NUMEVENTS)
{
#if DEBUG
if (p == PROCESS_BROADCAST)
{
printf("soft panic: event queue is full when broadcast event %02X was posted from %s\r\n",
ev, PROCESS_NAME_STRING(process_current));
}
else
{
printf("soft panic: event queue is full when event %02X was posted to %s from %s\r\n",
ev, PROCESS_NAME_STRING(p), PROCESS_NAME_STRING(process_current));
}
#endif /* DEBUG */
return PROCESS_ERR_FULL;
}
/* 计算下标,fevent是将要处理的事件下标,nevets是总为处理下标
PROCESS_CONF_NUMEVENTS 是总的能存放为处理的事件总数 */
snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
events[snum].ev = ev;
events[snum].data = data;
events[snum].p = p;
/* 总数+1 */
++nevents;
return PROCESS_ERR_OK;
}
这里面基本都好理解,比较难理解的是第41行了,snum = (process_num_events_t)(fevent + nevents) % PROCESS_CONF_NUMEVENTS;
为什么下标可以这样计算:举个例子,PROCESS_CONF_NUMEVENTS
最大是10,nevents
目前是5,代表有5个未处理的事件,fevent
目前已经处理到了第3个事件,即fevent
目前等于3,这时候要把新的事件存在哪里呢?只能存在8这个位置,因为目前要处理的下标是3,还有5个事件待处理,所以只能存在8这个位置了,这个琢磨一下就能想通的。