Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1670053
  • 博文数量: 124
  • 博客积分: 4078
  • 博客等级: 中校
  • 技术积分: 3943
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-21 11:28
个人简介

新博客:http://sparkandshine.net/

文章分类

全部博文(124)

分类: 嵌入式

2011-09-22 14:53:41

摘要:

  本文深入源码,详细分析Contiki启动一个进程的过程。先是总结了process_start()都做了些什么事,进而跟踪代码进行详细分析。


引言

    process_start函数用于启动一个进程,将进程加入进程链表(事先验证参数,确保进程不在进程链表中),初始化进程(将进程状态设为运行状态及lc设为0)。给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行(事先参数验证,确保进程已被设为运行态并且进程的函数指针thread不为空),事实上是执行进程结构体中的thread函数指针所指的函数,而这恰恰是PROCESS_THREAD(name, ev, data)函数的实现。判断执行结果,如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出,否则进程被挂起,等待事件。

    理解系统最好的方法就是阅读源码,分享Linus的一句话,接下来跟踪代码详细分析Contiki系统是如何启动一个进程的。

  1. Read the Fucking Source Code --Linus Torvalds

整个调用过程如下:

  1. process_start——>process_post_synch——>call_process——>exit_process

一、process_start函数

    将进程加入进程链表(事先验证参数,确保进程不在进程链表中),初始化进程(将进程状态设为运行状态及lc设为0)。给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行。

  1. /*******启动一个进程********/
  2. void process_start(struct process *p, const char *arg) //可以传递arg给进程p,也可以不传,直接“NULL”
  3. {
  4.     struct process *q;
  5.     /*参数验证:确保进程不在进程链表中*/
  6.     for(q = process_list; q != p && q != NULL; q = q->next);
  7.     if(q == p)
  8.     {
  9.         return;
  10.     }
  11.     /*把进程加到进程链表首部*/
  12.     p->next = process_list;
  13.     process_list = p;

  14.     p->state = PROCESS_STATE_RUNNING;
  15.     PT_INIT(&p->pt); //将p->pt->lc设为0,使得进程从case 0开始执行

  16.     PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));

  17.     //给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行
  18.     process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
  19. }

二、process_post_synch函数

    process_post_synch()直接调用call_process(),期间需要保存process_corrent,这是因为当调用call_process执行这个进程p时,process_current就会指向当前进程p,而进程p可能会退出或者被挂起等待一个事件[1]。

  1. //process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
  2. void process_post_synch(struct process *p, process_event_t ev, process_data_t data) //typedef void * process_data_t;
  3. {
  4.     struct process *caller = process_current; //相当于PUSH,保存现场process_current

  5.     call_process(p, ev, data);

  6.     process_current = caller; //相当于POP,恢复现场process_current
  7. }

三、call_process函数

    如果进程process的状态为PROCESS_STATE_RUNNING,并且进程中的thread函数指针(相当于该进程的主函数)不为空的话,就执行该进程。如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出,否则进程被挂起,等待事件。

  1. //call_process(p, PROCESS_EVENT_INIT, (process_data_t)arg);
  2. static void call_process(struct process *p, process_event_t ev, process_data_t data)
  3. {
  4.     int ret;

  5. #if DEBUG
  6.     if(p->state == PROCESS_STATE_CALLED)
  7.     {
  8.         printf("process: process '%s' called again with event %d\n", PROCESS_NAME_STRING(p), ev);
  9.     }
  10. #endif /* DEBUG */

  11.     if((p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) //thread是函数指针
  12.     {
  13.         PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);
  14.         process_current = p;
  15.         p->state = PROCESS_STATE_CALLED;
  16.         ret = p->thread(&p->pt, ev, data); //才真正执行PROCESS_THREAD(name, ev, data)定义的内容
  17.         if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT)
  18.         {
  19.             exit_process(p, p); //如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出
  20.         } else
  21.         {
  22.             p->state = PROCESS_STATE_RUNNING; //进程挂起等待事件
  23.         }
  24.     }
  25. }

PT四种状态 

  1. #define PT_WAITING 0 /*被阻塞,等待事件发生*/
  2. #define PT_YIELDED 1 /*主动让出*/
  3. #define PT_EXITED  2 /*退出*/
  4. #define PT_ENDED   3 /*结束*/

进程状态

  1. #define PROCESS_STATE_NONE 0  /*类似于Linux系统的僵尸状态,进程已退出,只是还没从进程链表删除*/
  2. #define PROCESS_STATE_RUNNING 1  /*进程正在执行*/
  3. #define PROCESS_STATE_CALLED 2  /*被阻塞,运行?*/

四、exit_process函数

    先进行参数验证,确保进程在进程链表中并且不是PROCESS_STATE_NONE状态,向所有进程发一个同步事件PROCESS_EVENT_EXITED,通知他们将要退出,让与该进程相关的进程进行相应处理。

    用[1]中的一个例子:如果一个程序要退出的话,就会给etimer_process进程发送一个PROCESS_EVENT_EXITED事件,那么收到这个事件之后,etimer_process就会查找timerlist看看哪个timer是与这个进程相关的,就把它从timerlist中清除。

  1. //struct process *p 指要退出的进程
  2. //struct process *fromprocess 指当前的进程 ?
  3. //exit_process(p, p)
  4. static void exit_process(struct process *p, struct process *fromprocess)
  5. {
  6.     register struct process *q;
  7.     struct process *old_current = process_current;
  8.     PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p));

  9.     /*参数验证:确保要退出的进程在进程链表中*/
  10.     for(q = process_list; q != p && q != NULL; q = q->next);
  11.     if(q == NULL)
  12.     {
  13.         return;
  14.     }
  15.     if(process_is_running(p)) //return p->state != PROCESS_STATE_NONE;
  16.     {
  17.         p->state = PROCESS_STATE_NONE;

  18.         /*向所有进程发一个同步事件PROCESS_EVENT_EXITED,通知他们将要退出,使得与该进程相关的进程进行相应处理*/
  19.         for(q = process_list; q != NULL; q = q->next)
  20.         {
  21.             if(p != q)
  22.             {
  23.                 call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);
  24.             }
  25.         }

  26.         if(p->thread != NULL && p != fromprocess) /*退出的进程不是当前进程*/
  27.         {
  28.             /* Post the exit event to the process that is about to exit. */
  29.             process_current = p;
  30.             p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL); //给进程p传递一个PROCESS_EVENT_EXIT事件,通常用于退出死循环(如PROCESS_WAIT_EVENT函数),从而使其从主体函数退出
  31.         }
  32.     }

  33.     /*将进程p从进程链表删除*/
  34.     if(p == process_list) //进程p恰好在进程链表首部
  35.     {
  36.         process_list = process_list->next;
  37.     }
  38.     else //进程p不在进程链表首部
  39.     {
  40.         for(q = process_list; q != NULL; q = q->next) //遍历进程链表,寻找进程p,删除之
  41.         {
  42.             if(q->next == p)
  43.             {
  44.                 q->next = p->next;
  45.                 break;
  46.             }
  47.         }
  48.     }
  49.     process_current = old_current;
  50. }


PS:本文系阅读源码、论坛资料、官方资料的个人见解,如有错误的地方,烦请您指出,也欢迎交流Jelline@126.com


参考资料:

[1]贴子《》 



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

Jelline2014-10-09 23:09:26

zwpaper:process_current = p;
然后有
  p->state = PROCESS_STATE_CALLED;
  ret = p->thread(&p->pt, ev, data); //才真正执行PROCESS_THREAD(name, ev, data)定义的内容

那么
#define PROCESS_STATE_RUNNING  1  /*进程正在执行*/
#define PROCESS_STATE_CALLED  2  /*被阻塞,运行?*/

这个位置是否应该是:

#define PROCESS_STATE_RUNNING  1  /*进程需要执行,现在处于阻塞状态*/
#define PROCESS_STATE_CALLED  2  /*进程被调用*/

Hi,谢谢你的指正,你应该是对的。

回复 | 举报

zwpaper2014-10-08 15:41:21

process_current = p;
然后有
  p->state = PROCESS_STATE_CALLED;
  ret = p->thread(&p->pt, ev, data); //才真正执行PROCESS_THREAD(name, ev, data)定义的内容

那么
#define PROCESS_STATE_RUNNING  1  /*进程正在执行*/
#define PROCESS_STATE_CALLED  2  /*被阻塞,运行?*/

这个位置是否应该是:

#define PROCESS_STATE_RUNNING  1  /*进程需要执行,现在处于阻塞状态*/
#define PROCESS_STATE_CALLED  2  /*进程被调用*/