Chinaunix首页 | 论坛 | 博客
  • 博客访问: 14884
  • 博文数量: 11
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 22
  • 用 户 组: 普通用户
  • 注册时间: 2015-03-27 11:00
个人简介

不求广,但求深!

文章分类

全部博文(11)

文章存档

2016年(8)

2015年(3)

我的朋友

分类: 嵌入式

2016-03-30 10:13:09

摘要:

    process_run用于处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件。本文深入原码,详细分析,也包括do_poll和do_event函数。


一、运行process_run

  1. int main()
  2. {
  3.   dbg_setup_uart();
  4.   usart_puts("Initialising\n");

  5.   clock_init();
  6.   process_init();
  7.   process_start(&etimer_process, NULL);
  8.   autostart_start(autostart_processes);

  9.   while (1)
  10.   {
  11.     /*执行完所有needspoll为1的进程及处理完所有队列*/
  12.     do
  13.     {
  14.     }
  15.     while (process_run() > 0);
  16.   }
  17.   return 0;
  18. }

二、process_run剖析

process_run处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件,源代码如下:

  1. static volatile unsigned char poll_requested; //全局静态变量,标识系统是否有needspoll为1的进程

  2. int process_run(void)
  3. {
  4.   if (poll_requested) //进程链表有needspoll为1的进程
  5.   {
  6.     do_poll(); //见2.1
  7.   }

  8.   do_event(); //见2.2

  9.   return nevents + poll_requested; //若和为0,则表示处理完系统的所有事件,并且没有needspoll为1的进程
  10. }

    透过上述的源代码,可以直观看出needspoll标记为1的进程可以优先执行。并且每执行一次process_run,将处理系统所有needspoll标记为1的进程,而只处理事件队列的一个事件。

2.1 do_poll函数

    复位全局变量poll_requested,遍历整个进程链表,将needspoll标记为1的进程投入运行,并将相应的needspoll复位。源代码如下:

  1. static void do_poll(void)
  2. {
  3.   struct process *p;
  4.   poll_requested = 0; //复位全局变量

  5.   for (p = process_list; p != NULL; p = p->next) //处理所有needspoll为1的进程
  6.   {
  7.     if (p->needspoll) //将needspoll为1的进程投入执行
  8.     {
  9.       p->state = PROCESS_STATE_RUNNING;
  10.       p->needspoll = 0;
  11.       call_process(p, PROCESS_EVENT_POLL, NULL);
  12.     }
  13.   }
  14. }

    call_process函数剖析见博文《Contiki学习笔记:启动一个进程process_start 》第三部分。

2.2 do_event函数

    do_event处理事件队列的一个事件,有两种事件需特殊处理:PROCESS_BROADCAST和PROCESS_EVENT_INIT。前者是广播事件,需处理所有进程,后者是初始化事件,需将进程状态设为PROCESS_STATE_RUNNING。源代码如下:

  1. static process_num_events_t nevents; /*事件队列的总事件数 */
  2. static process_num_events_t fevent; /*指向下一个要传递的事件的位置*/
  3. static struct event_data events[PROCESS_CONF_NUMEVENTS]; /*事件队列,用数组存储,逻辑上是环形队列*/

  4. static void do_event(void)
  5. {
  6.   /*以下3个变量恰为struct event_data的成员,用于暂存即将处理(fevent事件)的值*/
  7.   static process_event_t ev;
  8.   static process_data_t data;
  9.   static struct process *receiver;

  10.   static struct process *p;

  11.   if (nevents > 0)
  12.   {
  13.     /*提取将要处理事件的成员变量*/
  14.     ev = events[fevent].ev;
  15.     data = events[fevent].data;
  16.     receiver = events[fevent].p;
  17.     
  18.     fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS; //更新fevent(指向下一个待处理的事件,类型于微机的PC)
  19.     --nevents; //事件队列被组织成环形队列,所以取余数

  20.     if (receiver == PROCESS_BROADCAST) //如果事件是广播事件PROCESS_BROADCAST,则处理所有进程
  21.     {
  22.       for (p = process_list; p != NULL; p = p->next)
  23.       {
  24.         if (poll_requested)
  25.         {
  26.           do_poll();
  27.         }
  28.         call_process(p, ev, data); //jelline note: call the receiver process twice??
  29.       }
  30.     }
  31.     else
  32.     {
  33.       if (ev == PROCESS_EVENT_INIT) //若事件是初始化,设置进程状态,确保进程状态为PROCESS_STATE_RUNNING
  34.       {
  35.         receiver->state = PROCESS_STATE_RUNNING;
  36.       }
  37.       call_process(receiver, ev, data);
  38.     }
  39.   }
  40. }

call_process函数剖析见博文《Contiki学习笔记:启动一个进程process_start 》第三部分。

阅读(514) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~