首页 > 代码库 > contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>

contiki-main.c 中的process系列函数学习笔记 <contiki学习笔记之六>

说明:本文依然依赖于 contiki/platform/native/contiki-main.c 文件。

-------------------------------------------------------------------------------------------------------------------------------------

      根据上一个笔记里面添加的printf()语句的打印信息提示,hello world 打印是在执行了

1 autostart_start(autostart_processes);

      这行代码后才打印的。而我试着将这行代码注释掉,结果hello-world就不再打印了。那么,根据猜测,这个hello-world的打印可能会与process相关。

当然,这只是猜测,一切都还得从代码里来看看。

-------------------------------------------------------------------------------------------------------------------------------------

先看main(){}里面使用到的几个和process相关的函数:

void
process_init(void);

 contiki/ ./core/sys/process.c 

 1 void 2 process_init(void)                                                                                                                                                                         3  { 4  //./core/sys/process.h:  typedef unsigned char process_event_t; 5   6  lastevent = PROCESS_EVENT_MAX;   //  static process_event_t lastevent;    PROCESS_EVENT_MAX  (0x8a) 7   8  // ./core/sys/process.h:typedef unsigned char process_num_events_t; 9 10  nevents = fevent = 0;        // static process_num_events_t nevents, fevent;11  #if PROCESS_CONF_STATS12    process_maxevents = 0;13  #endif /* PROCESS_CONF_STATS */14  //  ./core/sys/process.c:struct process *process_current = NULL;15  //  ./core/sys/process.c:struct process *process_list = NULL;16    process_current = process_list = NULL;17 }

这里的变量都是静态全局变量。

1、定义事件  lastevent 、nevents、fevent

2、初始化或者说创建一个任务链表。当然指向了NULL。

<ps:  按说,全局变量蛮占空间的,这对于contiki OS强调的节省资源似乎相悖,为什么呢? google关键字: potothread 机制>


void
process_start(struct process *p, const char *arg);

 contiki/ ./core/sys/process.c 

 1  void 2  process_start(struct process *p, const char *arg) 3  { 4    struct process *q; 5   6    /* First make sure that we don‘t try to start a process that is already running. */ 7    for(q = process_list; q != p && q != NULL; q = q->next); 8   9    /* If we found the process on the process list, we bail out. */10    if(q == p) {11      return;12    }13    /* Put on the procs list.*/14    p->next = process_list;15    process_list = p;16    p->state = PROCESS_STATE_RUNNING;    //#define PROCESS_STATE_RUNNING     117    PT_INIT(&p->pt);                        // (&p->pt)->lc = 0;  struce process {...  struct pt {lc_t lc}};18  19    PRINTF("process: starting ‘%s‘\n", PROCESS_NAME_STRING(p));20  21    /* Post a synchronous initialization event to the process. */22    process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);23  }

这是一个启动一个process的函数。我这里直接写成process,而不会写成进程或者任务什么的。假设一个process  A将要启动

1、先遍历整个process链,看要启动的这个process  A是否已经存在于该链表中,若存在,则直接返回。

2、若process  A并不存在于整个process链中,则将该process A添加到这个链表中。

添加方式是:将process A添加到原来的process 链表的头部;并且将process A的地址作为整个process 链表的新地址。

3、将process A置为运行态 running,并初始化A的   lc   值为 0。  这个   lc   的值似乎很重要,在process切换的时候,它可能将产生作用。

4、执行  process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg); 把初始化事件同步到process中去..   <应该是process链表中?>

 

void
process_post_synch(struct process *p, process_event_t ev, process_data_t data);

 contiki/./core/sys/process.c 

1  void2  process_post_synch(struct process *p, process_event_t ev, process_data_t data)                                                                                                            3  {4    struct process *caller = process_current;5  6    call_process(p, ev, data);7    process_current = caller;8  }

process_current 表示运行状态的process

1、将 process_current 中的东西交给 caller保存。

2、call_process() 将唤醒另外一个process <执行另外一个process>

3、将caller里面保存的东西<地址>重新交还给 process_current 。

上面这三行代码,如果我没有理解错的话---------那么它们干了一件事情,那就是从一个process 切换到另外一个process,然后又切换回来。嗯~~ 有可能,因为这代码是在process_start()函数里面,启动这个process,势必就要停用另外一个process。

 

static void
call_process(struct process *p, process_event_t ev, process_data_t data);

 contiki/./core/sys/process.c 

 1  static void 2  call_process(struct process *p, process_event_t ev, process_data_t data) 3  { 4    int ret; 5    // #define PROCESS_STATE_RUNNING     1 6    // 调用 hello_world_process()  返回值为  char  7    if( (p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) { 8      process_current = p; 9      p->state = PROCESS_STATE_CALLED;                 //  process.c:#define PROCESS_STATE_CALLED      210      ret = p->thread(&p->pt, ev, data);11      if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT) {12        exit_process(p, p);13      } else {14        p->state = PROCESS_STATE_RUNNING;15      }16    }17  }

仔细看,就干了一件事情:调用我们工程目录下的那个自己实现的钩子函数。

就拿hello-world.c 里面的钩子函数为例:

1 PROCESS_THREAD(hello_world_process, ev, data)2 {3   PROCESS_BEGIN();4 5   printf("Hello, world\n");6   7   PROCESS_END();8 }

就这个函数,宏展开的话,就是这个:

 1 static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data) 2 { 3     char PT_YIELD_FLAG = 1; 4     if (PT_YIELD_FLAG) {;} 5     switch((process_pt) -> lc) { 6         case 0: 7         printf("Hello world!\n"); 8     }; 9     PT_YIELD_FLAG = 0;10     process_pt->lc = 0;11     return PT_ENDED;12 }

如果是打印"hello world"的话,这里,它就该出现了。而这个钩子函数,在数据结构 struct process{}里面也有体现了。

当然,钩子函数执行完毕,就会退出这个process: 

1 exit_process(p, p);

然后切换到原来的或者别的process上去。

 

static void
exit_process(struct process *p, struct process *fromprocess);

contiki/./core/sys/process.c 

 1  static void 2  exit_process(struct process *p, struct process *fromprocess) 3  { 4    register struct process *q; 5    struct process *old_current = process_current; 6  7    /* Make sure the process is in the process list before we try to 8       exit it. */ 9    for(q = process_list; q != p && q != NULL; q = q->next);10    if(q == NULL) {11      return;12    }13  14    if(process_is_running(p)) {15      /* Process was running */16      p->state = PROCESS_STATE_NONE;            // #define PROCESS_STATE_NONE        017  18      /*19       * Post a synchronous event to all processes to inform them that20       * this process is about to exit. This will allow services to21       * deallocate state associated with this process.22       */23      for(q = process_list; q != NULL; q = q->next) {24        if(p != q) {25         call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);26        }27      }                                                                                                                                                                                     28  29      if(p->thread != NULL && p != fromprocess) {30        /* Post the exit event to the process that is about to exit. */31        process_current = p;32        p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);33      }34    }35  36    if(p == process_list) {37      process_list = process_list->next;38    } else {39      for(q = process_list; q != NULL; q = q->next) {40        if(q->next == p) {41      q->next = p->next;42      break;43        }44      }45    }46  47    process_current = old_current;48  }

退出process的时候,它会做这一些工作:

1、例行工作---先检查要退出的这个process是否是存在于process链表中,如果不是,那证明搞错了。

2、如果该process依然处于running状态,则必须将该process的状态置为停止状态。

3、然后向整个process链表通告,这个process告别大家了,留下的资源神马的,大伙儿该分就分,该拿就拿。<真是如此吗?难道不是如此吗?>

4、彻底表明,该process running状态是过去时了 <process_current = old_current;> ,下一个process该怎么办就怎么办。

总结: 这个process的退出过程,其实就是一个链表结点销毁的过程。就这么简单。

 

接下来,看看文章开头遇到的那个函数: autostart_start()。正是因为它,才有了我们的hello-world的打印,必须看看它是怎么实现的。

void
autostart_start(struct process * const processes[]);

contiki/./core/sys/autostart.c

1   void2   autostart_start(struct process * const processes[])3   {4     int i;5     for(i = 0; processes[i] != NULL; ++i) {6       process_start(processes[i], NULL);7       PRINTF("autostart_start: starting process ‘%s‘\n", processes[i]->name);8     }9   }

干了一件事情:start 一些 process。而这些process被放进了某一个数组。那么这个可能放许多的process的数组又是何许物也? 看看main()里面是怎么使用它的:

int main(){//....  autostart_start(autostart_processes);    //......}

不错,autostart_start() 里的参数是  autostart_processes。 那么这个  autostart_processes又是何方神圣?依据伟大的find命令的查询:

autostart_processes  出现在了 contiki/./core/sys/autostart.h文件中:

  #if AUTOSTART_ENABLE            //  这个可能在Makefile.include 里面以 -D的方式定义了./Makefile.include:    $(Q)$(CC) $(CFLAGS) -DAUTOSTART_ENABLE -c $< -o $@  #define AUTOSTART_PROCESSES(...)                      struct process * const autostart_processes[] = {__VA_ARGS__, NULL}  #else /* AUTOSTART_ENABLE */  #define AUTOSTART_PROCESSES(...)                      extern int _dummy  #endif /* AUTOSTART_ENABLE */

似曾相识? 再整洁点:

1 #if AUTOSTART_ENABLE2     #define AUTOSTART_PROCESSES(...)  struct process * const autostart_processes[] = {__VA_ARGS__, NULL}3 #else4     #define AUTOSTART_PROCESSES(...)    extern int _dummy    5 #endif

嗯哼~   不错,autostart_processes 这个东西和宏AUTOSTART_PROCESSES()有关的,而宏AUTOSTART_PROCESSES()出现在了哪里?

 1 #include "contiki.h" 2  3 #include <stdio.h> /* For printf() */ 4 /*---------------------------------------------------------------------------*/ 5 PROCESS(hello_world_process, "Hello world process"); 6 AUTOSTART_PROCESSES(&hello_world_process); 7 /*---------------------------------------------------------------------------*/ 8 PROCESS_THREAD(hello_world_process, ev, data) 9 {10   PROCESS_BEGIN();11 12   printf("Hello, world\n");13   14   PROCESS_END();15 }16 /*---------------------------------------------------------------------------*/

没错,就是我们自己写的那个 hello-world.c 文件里。

千里一线,说白了,那就是 autostart_start(struct process * const processes[]);这个函数和  AUTOSTART_PROCESSES() 这个宏有关嘛。

AUTOSTART_PROCESSES()这个搞了多少个process,那么autostart_processes 这个数组里就有了多少个process,那么autostart_start()就会挨着start几个process。原来,辛苦半天,它在这里等着。

 

顺便提一下,还有一个  

void
autostart_exit(struct process * const processes[]);

它的实现如下:

 1   void 2   autostart_exit(struct process * const processes[]) 3   { 4     int i; 5      6     for(i = 0; processes[i] != NULL; ++i) { 7       process_exit(processes[i]); 8       PRINTF("autostart_exit: stopping process ‘%s‘\n", processes[i]->name); 9     }10   }

对应着前面的 autostart_start()   start了多少个 process,这里就会exit多少个process。因为前面提到一处exit_procee(),而这里是process_exit(),那它们有什么异同呢?

没错,就是一个封装:

1  void2  process_exit(struct process *p)3  {4    exit_process(p, PROCESS_CURRENT());5  }

 

总结下吧:  就是把A  B  C  D .. 这些process 放到一个链表中去,然后再从链表中按要求删除---这真够无聊的:但目前为止,许多操作系统似乎都是这么无聊的干着...

 

 

好吧,contiki的 process 的皮毛就先学习到这里,后面再继续思考,每个process的切换和销毁,真的就如我上面所说?还是另有途径?

 

有知道的朋友可以告知我一下,谢谢!

Email:   newleaves@126.com