• Contiki进程间的交互


    之前都是从各个模块开始看起,从底层开始看起。应该改变一下思路,从高往下看,站得高看得远。

    一、Main函数

    源码:contiki-release-2-7platformstm32testcontiki-main.c

    int
    main()
    {
      dbg_setup_uart();
      printf("Initialising
    ");
      
      clock_init();
      process_init();
      process_start(&etimer_process, NULL);
      autostart_start(autostart_processes);
      printf("Processes running
    ");
      while(1) {
        do {
        } while(process_run() > 0);
        idle_count++;
        /* Idle! */
        /* Stop processor clock */
        /* asm("wfi"::); */ 
      }
      return 0;
    }

    主函数中,关于进程的操作:

    先对进程进行初始化process_init()。

    用process_start(&etimer_process, NULL),启动etimer_process进程。

    用autostart_start(autostart_processes),启动需要自动启动的进程,看自启动进程相关知识。

    最后循环执行进程调度函数process_run。

    二、进程初始化

    void
    process_init(void)
    {
      lastevent = PROCESS_EVENT_MAX;
    
      nevents = fevent = 0;
    #if PROCESS_CONF_STATS
      process_maxevents = 0;
    #endif /* PROCESS_CONF_STATS */
    
      process_current = process_list = NULL;
    }

    初始化最后一个事件标识lastevent为PROCESS_EVENT_MAX

    初始化事件总数nevents和事件队列头指针fevent为0。

    初始化进程链表头process_list和当前进程process_current为NULL。

    三、启动进程

    void
    process_start(struct process *p, const char *arg)
    {
      struct process *q;
    
      //确保要运行的进程没有在进程链表(已经运行了的进程)中
      /* First make sure that we don't try to start a process that is
         already running. */
      for(q = process_list; q != p && q != NULL; q = q->next);
    
      /* If we found the process on the process list, we bail out. */
      if(q == p) {//已在进程链表中,返回
        return;
      }
      /* Put on the procs list.*/
      p->next = process_list;//添加要启动的进程到进程链表中
      process_list = p;
      p->state = PROCESS_STATE_RUNNING;//设置进程状态为准备就绪状态
      PT_INIT(&p->pt);//初始化进程pt(lc)
    
      PRINTF("process: starting '%s'
    ", PROCESS_NAME_STRING(p));
    
      /* Post a synchronous initialization event to the process. */
      process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);//用同步事件启动进程p
    }

    先确保要启动的进程没有在进程链表中。

    再将进程添加到进程链表中。

    设置进程状态为PROCESS_STATE_RUNNING,即就绪状态,并初始化pt

    最后传递同步事件给进程p,其中事件标识为PROCSS_EVENT_INIT,事件携带数据data为NULL

    1、传递同步事件

    void
    process_post_synch(struct process *p, process_event_t ev, process_data_t data)
    {
      struct process *caller = process_current;//先保存当前进程指针
    
      call_process(p, ev, data);//传递给特定进程
      process_current = caller;//恢复当前进程指针
    }

    先保存当前进程变量process_current,然后传递事件给进程,最后恢复process_current变量。

    2、调用进程

    static void
    call_process(struct process *p, process_event_t ev, process_data_t data)
    {
      int ret;//进程执行主体函数返回值
    
    #if DEBUG
      if(p->state == PROCESS_STATE_CALLED) {//再次调用?
        printf("process: process '%s' called again with event %d
    ", PROCESS_NAME_STRING(p), ev);
      }
    #endif /* DEBUG */
      
      if((p->state & PROCESS_STATE_RUNNING) &&
         p->thread != NULL) {//就绪状态并且执行主体函数不为NULL?
        PRINTF("process: calling process '%s' with event %d
    ", PROCESS_NAME_STRING(p), ev);
        process_current = p;//设置当前进程变量
        p->state = PROCESS_STATE_CALLED;//设置进程状体为已被调用
        ret = p->thread(&p->pt, ev, data);//执行进程主体函数
        if(ret == PT_EXITED ||
           ret == PT_ENDED ||
           ev == PROCESS_EVENT_EXIT) {//返回值为PT_EXITED或PT_ENDED或传递进来的事件为PROCESS_EVENT_EXIT
          exit_process(p, p);//执行退出进程函数
        } else {
          p->state = PROCESS_STATE_RUNNING;//重新设置为就绪状态,等待事件的到来
        }
      }
    }

    在进程状态为就绪状态PROCESS_STATE_RUNNING,并且执行主体函数不为NULL的情况下。

    设置当前进程变量为p,并设置状态为已被调用状态PROCESS_STATE_CALLED。

    调用执行主体函数p->thread(&p->pt, ev, data)。

    如果返回值为PT_EXITED或者返回值为PT_ENDED或者这个事件是PROCESS_EVENT_EXIT,则这个进程已经执行完毕了。执行退出进程操作exit_process,做一些善后工作。

    否则重新设置进程状态为就绪状态,继续等待事件的到来。

    注:注意区分PROCESS_EVENT_EXIT事件和PROCESS_EVENT_EXITED事件,PROCESS_EVENT_EXIT是通知要退出的进程p本身,而PROCESS_EVENT_EXITED是通知其他进程,有进程p即将退出。

    退出进程操作有两种情况,一种是自己要退出,即上述情况:返回值为PT_EXITED或者返回值为PT_ENDED或者这个事件是PROCESS_EVENT_EXIT。

    另一种是其他进程要这个进程退出。

    退出进程

    static void
    exit_process(struct process *p, struct process *fromprocess)
    {
      register struct process *q;
      struct process *old_current = process_current;//先保存当前进程变量
    
      PRINTF("process: exit_process '%s'
    ", PROCESS_NAME_STRING(p));
    
      /* Make sure the process is in the process list before we try to
         exit it. */
      for(q = process_list; q != p && q != NULL; q = q->next);
      if(q == NULL) {
        return;
      }//确定要退出的进程在进程链表中,否则返回
    
      if(process_is_running(p)) {//进程状态不是PROCESS_STATE_NONE才进入
        /* Process was running */
        p->state = PROCESS_STATE_NONE;//设置状态为PROCESS_STATE_NONE
    
        /*
         * Post a synchronous event to all processes to inform them that
         * this process is about to exit. This will allow services to
         * deallocate state associated with this process.
         */
        for(q = process_list; q != NULL; q = q->next) {
          if(p != q) {
        call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);
          }
        }//通知其他所有进程,p进程即将退出
    
        if(p->thread != NULL && p != fromprocess) {
          /* Post the exit event to the process that is about to exit. */
          process_current = p;
          p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);
        }
      }//再次执行p进程的执行主体函数(p和fromprocess不同的情况下)
    
      if(p == process_list) {
        process_list = process_list->next;
      } else {
        for(q = process_list; q != NULL; q = q->next) {
          if(q->next == p) {
        q->next = p->next;
        break;
          }
        }
      }//将进程p从进程链表中删除
    
      process_current = old_current;//恢复当前进程变量
    }

    先确定要退出的进程在进程链表中,并且进程状态不是PROCESS_STATE_NONE。

    先给其他所有进程,传递同步事件PROCESS_EVENT_EXITED,通知p这个进程即将退出。

    如果是其他进程要p退出的话,则再次执行p的执行主体函数。

    如果是p要p退出的话,那么执行主体函数都已经执行过了,所以不用再执行。

    最后将进程p从进程链表中删除。

    int
    process_is_running(struct process *p)
    {
      return p->state != PROCESS_STATE_NONE;
    }
    process_is_running

    四、进程调度

    int
    process_run(void)
    {
      /* Process poll events. */
      if(poll_requested) {
        do_poll();
      }
    
      /* Process one event from the queue */
      do_event();
    
      return nevents + poll_requested;
    }

    进程调度函数中先处理抢占式进程,然后再处理协同式进程(非同步事件)

    1、推举抢占式进程

    void
    process_poll(struct process *p)
    {
      if(p != NULL) {
        if(p->state == PROCESS_STATE_RUNNING ||
           p->state == PROCESS_STATE_CALLED) {
          p->needspoll = 1;
          poll_requested = 1;
        }
      }
    }

    最主要的工作时将进程p的needspoll标志设置为1,以及是否有poll请求标志poll_requested设置为1。

    2、抢占式进程处理

    static void
    do_poll(void)
    {
      struct process *p;
    
      poll_requested = 0;//恢复标志
      /* Call the processes that needs to be polled. */
      for(p = process_list; p != NULL; p = p->next) {//遍历进程链表,调用所有需要poll的进程
        if(p->needspoll) {
          p->state = PROCESS_STATE_RUNNING;
          p->needspoll = 0;//恢复标志
          call_process(p, PROCESS_EVENT_POLL, NULL);
        }
      }
    }

    注:从上边我们知道,抢占式进程会全部都执行完之后,再从事件队列中取出一个事件传递给目的进程处理。

    总结

    要先用process_start或者autostart_start先将进程启动。

    后续的进程调度函数process_run时在进程启动后进行的一些调度,准确的说是传递事件。

    进程的状态:

    #define PROCESS_STATE_NONE 0    退出前的一个状态,就差从进程链表中删除。
    #define PROCESS_STATE_RUNNING 1  就绪状态,即已经初始化完毕,等待事件的到来,然后执行进程执行主体函数。
    #define PROCESS_STATE_CALLED 2   进程正在被调用,也就是执行主体函数正在运行中。

     

  • 相关阅读:
    ANT安装
    MAVEN配置教程
    闲笔
    js系列
    微信小程序系列_require
    c++复习系列
    codeblocks系列
    mysql系列
    Google Developer Tools
    数学建模算法(三):神经网络
  • 原文地址:https://www.cnblogs.com/songdechiu/p/5815525.html
Copyright © 2020-2023  润新知