IOTDEV.NET - 物联网|Contiki 6Lowpan|Zigbee|BLE|WIFI|无线传感器网络开发网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 4893|回复: 0

Contiki 6lowpan开发教程资料之五:启动一个进程process_start

[复制链接]
发表于 2012-7-15 11:42:42 | 显示全部楼层 |阅读模式
本帖最后由 eva 于 2012-7-15 11:44 编辑

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

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

    理解系统最好的方法就是阅读源码,分享Linus的一句话,接下来跟踪代码详细分析Contiki系统是如何启动一个进程的。
    Read the Fucking Source Code --Linus Torvalds
整个调用过程如下:
  1. <b><font color="#0000ff">process_start ——>  process_post_synch ——> call_process  ——> exit_process</font></b>
复制代码
一、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. }
复制代码
参考资料:

QQ|Archiver|手机版|小黑屋|慧讯物联网 ( 粤ICP备17010903号 )

粤公网安备 44011502000093号

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表