现在的位置: 首页 > 综合 > 正文

contiki任务调度机制分析

2018年03月30日 ⁄ 综合 ⁄ 共 3600字 ⁄ 字号 评论关闭

contiki任务调度机制分析

创建时间:2014-11-20
21:34

 

修改时间:2014-11-25
22:30

 

【目录Index】
  • 事件进程的数据结构
  • 初始化
  • 中断的实现
    • systick的实现
    • 中断服务程序
  • 任务的调度
【博客正文】
     contiki是事件驱动型操作系统,它有一个事件驱动的核心,其主要的进程模式是protothread,这个进程模式使得contiki这个操作系统只使用一个堆栈,节约了本不富裕的嵌入式设备上面的内存。同时,由于在进程切换过程中,系统不会保存当前进程的堆栈,以及寄存器信息,所以contiki也警告说,在protothread模式中编程时,local
variable需要小心使用, 一般都是定义在static 和global variable,防止切换时,变量信息丢失。
关于protothread的内容, 后续在进行学习,此处仅需要明白contiki底层的对于程序的切换,主要是在protothread库的基础上进行封装实现的。

  • 事件进程的数据结构

对于contiki中的每个事件,我们用如下图所示的数据结构进行定义。

process结构体中应该包含六个变量,etime_process结构体变量声明后其内部变量的示意如下:
(1)process结构体指针变量,该变量用于形成单链表
(2)name:char型字符指针常量
(3)thread: char型函数指针变量
          
(4)pt变量
(5)state变量,用于指示process当前的状态
(6)needspoll变量:用于指示process是否需要轮询
(以上对于process结构体的讨论,建立在不存在宏定义PROCESS_CONF_NO_PROCESS_NAMES的情况下。)

  • 初始化
     本段程序的初始化主要包括如下几个方面:
    1. 事件的注册
    2. 上电自启动事件的注册
    3. 外设初始化(略)、时钟初始化在中断部分讲
    4. process_init()
    5. etimer_process的启动
    6. 自启动事件的启动
  1. 事件的注册

          通过宏定义PROCESS(blink_process, "Blink");完成blink_process时间的注册,主要包括:

  • 声明blink_process事件对应的功能函数process_thread_blink_process(struct pt *process_pt, process_event_t ev, process_data_t data)
  • 声明对应的事件结构体变量,同时完成相关结构体内部变量的初始化

     2.  上电自启动事件的注册

  • 通过AUTOSTART_PROCESSES(&blink_process);将blink_process添加到全局的process指针数组autostart_processes中,后续的autostart_start函数会将需要该指针数组中对应的process全部启动。对于autostart_processes数组的宏定义使用了可变参数的方式。
  • 另外需要注意的是如果没有上电自启动的事件的话,依然需要通过AUTOSTART_PROCESSES宏声明空数组,或者去掉后续的autostart_start函数

     4. process_init

  •  contiki对于就绪待执行的事件,是通过循环指针的形式存放在events数组形成的线性队列当中的,对于该队列而言,

    • 变量nevents表示队列中有效事件的数量
    • 变量fevent表示循环队列的头结点
    • 变量lastevent表示循环队列的尾(因为这个变量目前还没有起作用,不太好分析它的作用是什么)
  • 同时初始化将启动的事件构成的单链表process_list初始化为空

     5.  事件启动

  • 通过process_start启动etimer_process
  • 通过autostart_start启动autostart_processes数组中的事件,autostart_processes本身也是调用process_start实现的
  • process_start函数会:
    • 将要start的时间process通过头插法添加到process_list单链表当中
    • 通过函数process_post_synch中的call_process完成对事件功能函数代码的执行,功能函数代码中一般会完成事件定时器et的初始化
       process_start函数的代码实现如下:     
其中,通过局部process结构体指针变量来判断q是否存在于process_list指向的单链表中,如果存在,表示准备start的process已经被start过,所以可以return。否则,通过头插入的方式将准备打开的process插入到process_list单链表中,同时对单链表进行更新。同时将计划打开的process的状态修改RUNNING。
  • 完成初始化后,相关变量的值如下图所示:
  

  • 中断的实现
  • systick的实现
          systick的代码如下:
         上面的代码主要是对几个基本的寄存器的配置,不做赘述。
         systick实现的参数如下:
         
系统时钟
96Mhz
CLOCK_RLD
96000000/CLOCK_SECOND    
中断频率
10ms



  • 中断服务程序

    • 对current_clock进行计数,在contiki中,current_clock能够形成一个基准时基,对任务的执行做时间标准。分析代码觉得current_clock存在溢出后产生bug的可能
    • 通过对current_clock的判断完成对current_second的计数
    • 代码中是通过do_poll函数来完成对etimer_process的功能代码的调用的,从而在功能代码中对timerlist中的节点是否计时到达进行判断,从而对events循环队列进行更新,再完成对应的事件
    • 当时do_poll对etimer_process的功能代码的调用,并不是每个时钟周期都需要进行的,因为只需在最近的时间进行对计时到达与否进行判断即可。所以中断服务程序中,通过判断,调用etimer_request_poll函数,完成对全局变量poll_requested的置为,从而通过do_poll调用etimer_process的功能代码
    • 上条中所谓最近的时间,自然是距离当下最近的一次可能发生计时到达的时间next_expiration,这个值,是通过update_time求取最小值的过程进行更新的,相关代码如下

    • 对于update_time的函数调用关系如下图:可见在发生事件定时器变动之后,都需要更新一次时间


  • 任务调度

    • 在初始化过程中会执行一次事件的功能代码,在执行过程中通过etimer_set函数,建立事件对应的事件定时器,etimer_set函数执行过程中通过add_timer函数将该事件定时器通过头插法将它插入由事件定时器所组成的单链表当中,timerlist是单链表的头指针。
    • 事件定时器是个静态局部变量,存储在静态存储区,千万不能讲事件定时器设置成为局部变量,因为局部变量在函数推出之后对应的地址区域不确定,单链表相应的节点处于严重的不确定状态。
    • 事件定时器和对应的事件的对应关系是在add_timer函数中将进行头插入的时候对应上的,相关代码如下:

    • 因为函数中PROCESS_BEGIN和PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);函数宏的存在,所以blink_process功能函数的执行是switch对于while(1)的执行起点的选择过程
    • 在对应的条件ev == PROCESS_EVENT_TIMER未满足或在初始化的时候,while(1)循环时钟会从PROCESS_WAIT_EVENT_UNTIL宏定义对应的代码片段中返回,led闪烁的代码段始终不能执行
    • 在process_thread_etimer_process功能代码执行过程中发现timerlist对应于blink_process的节点的计时时间到达之后,程序就会通过调用process_post函数将对应的时间blink_process以ev == PROCESS_EVENT_TIMER的状态插入到events循环队列中
    • process_thread_etimer_process是在每次调用do_poll()函数的时候执行的,插入到events循环队列当中的就绪时间是在执行do_event()函数的时候执行的
    • do_event()函数调用执行blink_process功能代码(ev == PROCESS_EVENT_TIMER)后,此时程序执行led闪烁程序后,重新while(1)循环,执行etimer_set重新对et赋值,同时从PROCESS_WAIT_EVENT_UNTIL中挂起退出。
上图所描述的机制是contiki进行任务调度的核心

抱歉!评论已关闭.