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

说明:本文依然依赖于 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_STATS
12    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     1
17    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  void
2  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      2
10      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        0
17  
18      /*
19       * Post a synchronous event to all processes to inform them that
20       * this process is about to exit. This will allow services to
21       * 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   void
2   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_ENABLE
2     #define AUTOSTART_PROCESSES(...)  struct process * const autostart_processes[] = {__VA_ARGS__, NULL}
3 #else
4     #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  void
2  process_exit(struct process *p)
3  {
4    exit_process(p, PROCESS_CURRENT());
5  }

 

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

 

 

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

 

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

Email:   [email protected]

你可能感兴趣的:(process)