• 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_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'
    ", 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
    ");
    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!
    ");
     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'
    ", 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
    ");
    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'
    ", 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的切换和销毁,真的就如我上面所说?还是另有途径?

  • 相关阅读:
    spring下配置shiro
    web.xml文件配置说明
    spring中配置缓存—ehcache
    applicationContext.xml配置简介
    spring task定时器的配置使用
    spring配置数据库连接池druid
    Mybatis使用pageHelper步骤
    mybatis-generator和TKmybatis的结合使用
    PHP删除一个目录下的所有文件,不删除文件夹
    nodejs学习
  • 原文地址:https://www.cnblogs.com/chineseboy/p/3859342.html
Copyright © 2020-2023  润新知