摘要:
process_run用于处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件。本文深入原码,详细分析,也包括do_poll和do_event函数。
一、运行process_run
- int main()
-
{
-
dbg_setup_uart();
-
usart_puts("Initialising\n");
-
-
clock_init();
-
process_init();
-
process_start(&etimer_process, NULL);
-
autostart_start(autostart_processes);
-
-
while (1)
-
{
-
/*执行完所有needspoll为1的进程及处理完所有队列*/
-
do
-
{
-
}
-
while (process_run() > 0);
-
}
-
return 0;
-
}
二、process_run剖析
process_run处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件,源代码如下:
- static volatile unsigned char poll_requested; //全局静态变量,标识系统是否有needspoll为1的进程
-
-
int process_run(void)
-
{
-
if (poll_requested) //进程链表有needspoll为1的进程
-
{
-
do_poll(); //见2.1
-
}
-
-
do_event(); //见2.2
-
-
return nevents + poll_requested; //若和为0,则表示处理完系统的所有事件,并且没有needspoll为1的进程
-
}
透过上述的源代码,可以直观看出needspoll标记为1的进程可以优先执行。并且每执行一次process_run,将处理系统所有needspoll标记为1的进程,而只处理事件队列的一个事件。
2.1 do_poll函数
复位全局变量poll_requested,遍历整个进程链表,将needspoll标记为1的进程投入运行,并将相应的needspoll复位。源代码如下:
- static void do_poll(void)
-
{
-
struct process *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);
-
}
-
}
-
}
call_process函数剖析见博文《Contiki学习笔记:启动一个进程process_start 》第三部分。
2.2 do_event函数
do_event处理事件队列的一个事件,有两种事件需特殊处理:PROCESS_BROADCAST和PROCESS_EVENT_INIT。前者是广播事件,需处理所有进程,后者是初始化事件,需将进程状态设为PROCESS_STATE_RUNNING。源代码如下:
- static process_num_events_t nevents; /*事件队列的总事件数 */
-
static process_num_events_t fevent; /*指向下一个要传递的事件的位置*/
-
static struct event_data events[PROCESS_CONF_NUMEVENTS]; /*事件队列,用数组存储,逻辑上是环形队列*/
-
-
static void do_event(void)
-
{
-
/*以下3个变量恰为struct event_data的成员,用于暂存即将处理(fevent事件)的值*/
-
static process_event_t ev;
-
static process_data_t data;
-
static struct process *receiver;
-
-
static struct process *p;
-
-
if (nevents > 0)
-
{
-
/*提取将要处理事件的成员变量*/
-
ev = events[fevent].ev;
-
data = events[fevent].data;
-
receiver = events[fevent].p;
-
-
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); //jelline note: call the receiver process twice??
-
}
-
}
-
else
-
{
-
if (ev == PROCESS_EVENT_INIT) //若事件是初始化,设置进程状态,确保进程状态为PROCESS_STATE_RUNNING
-
{
-
receiver->state = PROCESS_STATE_RUNNING;
-
}
-
call_process(receiver, ev, data);
-
}
-
}
-
}
call_process函数剖析见博文《Contiki学习笔记:启动一个进程process_start 》第三部分。
阅读(514) | 评论(0) | 转发(0) |