process_run用于处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件。本文深入原码,详细分析,也包括do_poll和do_event函数。
在contiki中,有些进程需要紧急处理,比如中断中来了数据,此时,你需要将对应的进程赶快处理掉中断来的数据,否则可能会引起灾难性的后果,此时调用 process_poll(&slip_process); 将中断函数对应的进程 needpool设置为1,这样,此进程将会取得优先运行的特权。不过有个前提是,此进程处于p->state == PROCESS_STATE_RUNNING || p->state == PROCESS_STATE_CALLED) 这两个中状态时才行。当然此时全局变量 poll_requested也会置1。
一、运行process_run
intmain()
{
dbg_setup_uart();
usart_puts("Initialising\n");
clock_init();
process_start(&etimer_process,NULL);
autostart_start(autostart_processes);
while(1)
/*执行完所有needspoll为1的进程及处理完所有队列*/
do
{
}
while(process_run()>0);
return0;
}
二、process_run剖析
process_run处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件,源代码如下:
staticvolatileunsigned charpoll_requested;//全局静态变量,标识系统是否有needspoll为1的进程
intprocess_run(void)
if(poll_requested)//进程链表有needspoll为1的进程
{
do_poll();//见2.1
}
do_event();//见2.2
}
透过上述的源代码,可以直观看出needspoll标记为1的进程可以优先执行。并且每执行一次process_run,将处理系统所有needspoll标记为1的进程,而只处理事件队列的一个事件。
2.1 do_poll函数
复位全局变量poll_requested,遍历整个进程链表,将needspoll标记为1的进程投入运行,并将相应的needspoll复位。源代码如下:
staticvoiddo_poll(void)
{
structprocess*p;
poll_requested =0;//复位全局变量
for(p =process_list;p !=NULL;p =p->next)//处理所有needspoll为1的进程
{
if(p->needspoll)//将needspoll为1的进程投入执行
{
p->state=PROCESS_STATE_RUNNING;
p->needspoll =0;
call_process(p,PROCESS_EVENT_POLL,NULL);
}
}
}
2.2 do_event函数
do_event处理事件队列的一个事件,有两种事件需特殊处理:PROCESS_BROADCAST和PROCESS_EVENT_INIT。前者是广播事件,需处理所有进程,后者是初始化事件,需将进程状态设为PROCESS_STATE_RUNNING。源代码如下:
staticprocess_num_events_t nevents;/*事件队列的总事件数 */
staticprocess_num_events_t fevent;/*指向下一个要传递的事件的位置*/
staticstructevent_data events[PROCESS_CONF_NUMEVENTS];/*事件队列,用数组存储,逻辑上是环形队列*/
staticvoiddo_event(void)
{
/*以下3个变量恰为struct event_data的成员,用于暂存即将处理(fevent事件)的值*/
staticprocess_event_t ev;
staticprocess_data_t data;
staticstructprocess*receiver;
staticstructprocess*p;
if(nevents >0)
{
/*提取将要处理事件的成员变量*/
ev =events[fevent].ev;
data =events[fevent].data;
fevent =(fevent +1)%PROCESS_CONF_NUMEVENTS;//更新fevent(指向下一个待处理的事件,类型于微机的PC)
--nevents;//事件队列被组织成环形队列,所以取余数
if(receiver==PROCESS_BROADCAST)//如果事件是广播事件PROCESS_BROADCAST,则处理所有进程
{
for(p =process_list;p !=NULL;p =p->next)
{
if(poll_requested){
{
do_poll();
}
call_process(p,ev,data);//
}
else
{
if(ev ==PROCESS_EVENT_INIT)//若事件是初始化,设置进程状态,确保进程状态为PROCESS_STATE_RUNNING
{
receiver->state=PROCESS_STATE_RUNNING;
}
call_process(receiver,ev,data);
}
}