四.Contiki之Protothread机制

来源:互联网 发布:获取局域网mac地址命令 编辑:程序博客网 时间:2024/05/20 12:47

1.main函数分析

1.1 main函数源码

#include <stm32f10x.h>#include <stm32f10x_dma.h>#include <stdint.h>#include <stdio.h>#include <debug-uart.h>#include <sys/process.h>#include <sys/procinit.h>#include <etimer.h>#include <sys/autostart.h>#include <clock.h>int main(){  dbg_setup_uart(); //串口初始化,与硬件相关  usart_puts("Initialising\n"); //向串口打印字符串"Initialising"//详见1.2时钟初始化,与硬件相关  clock_init();//详见1.3进程初始化  process_init();//启动etimer_process(3.5 etimer_process)  process_start(&etimer_process, NULL);//详见1.4启动指针数组autostart_processes[]里的所有进程【autostart_start()函数中包含了process_start(),详见2】  autostart_start(autostart_processes);  while (1)  {//执行完所有needspoll为1的进程及处理完所有队列,详见3    do    {    }    while (process_run() > 0);//4.3 process_run()  }  return 0;}

1.2 时钟初始化clock_init()

void clock_init(){//详见① SysTick_Config函数  SysTick_Config(72000000 / CLOCK_SECOND);}/*CLOCK_SECOND宏定义*/#define CLOCK_CONF_SECOND 10#ifdef CLOCK_CONF_SECOND  #define  CLOCK_SECOND  CLOCK_CONF_SECOND#else  #define  CLOCK_SECOND  (clock_time_t)32#endif//①SysTick_Config函数(与硬件有关)static __INLINE uint32_t SysTick_Config(uint32_t ticks){   if (ticks > SysTick_LOAD_RELOAD_Msk) return (1);/* Reload value impossible */                                                                 SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1;/* set reload register */  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);/* set Priority for Cortex-M0 System Interrupts */  SysTick->VAL = 0;/* Load the SysTick Counter Value */  SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |                    SysTick_CTRL_TICKINT_Msk |                    SysTick_CTRL_ENABLE_Msk;/* Enable SysTick IRQ and SysTick Timer */  return (0);/* Function successful */}

1.3 进程初始化

/****进程初始化****/void process_init(void){  /*初始化事件队列*/  lastevent = PROCESS_EVENT_MAX;  nevents = fevent = 0;//4.3.3中nevents和fevent的定义  #if PROCESS_CONF_STATS    process_maxevents = 0;  #endif  process_current = process_list = NULL;//初始化进程链表}

1.4 autostart_start函数

//autostart_start(autostart_processes); // autostart_processes由宏AUTOSTART_PROCESSES定义【详见博文:http://blog.csdn.net/u012325020/article/details/52832659】void autostart_start(struct process *const processes[]){  int i;  for(i = 0; processes[i] != NULL; ++i)  {    process_start(processes[i], NULL);//进程的启动,见4.2    PRINTF("autostart_start: starting process '%s'\n", processes[i]->name);  }}


2.进程运行过程

进程运行过程大致为:process_start——>process_post_synch——>call_process——>exit_process

2.1 process_start函数

/*******启动一个进程********/void process_start(struct process *p, const char *arg) //可以传递arg给进程p,也可以不传,直接“NULL”{    struct process *q;/*参数验证:确保进程不在进程链表中*/    for(q = process_list; q != p && q != NULL; q = q->next);    if(q == p)    {        return;    }/*把进程加到进程链表首部*/    p->next = process_list;    process_list = p;    p->state = PROCESS_STATE_RUNNING;/*将p->pt->lc设为0,使得进程从case 0开始执行(PT_INIT()包含在PROCESS_END()里面【详见博文:http://blog.csdn.net/u012325020/article/details/52832659】)*/    PT_INIT(&p->pt);     PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));//详见2.2 :给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行    process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);}

2.2 process_post_synch函数

//process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);void process_post_synch(struct process  *p, process_event_t  ev, process_data_t  data) //typedef void * process_data_t{//相当于PUSH,保存现场process_current// struct process *process_current = NULL;   struct process *caller = process_current;   call_process(p, ev, data);//详见2.3//相当于POP,恢复现场process_current   process_current = caller; }//这里先process_current指针保存到caller,call_process()后再复原process_current。这说明在call_process()方法内,process_current指针被改变了。

2.3 call_process函数

//call_process(p, PROCESS_EVENT_INIT, (process_data_t)arg);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\n", PROCESS_NAME_STRING(p), ev);    }#endif /* DEBUG *///process_start()中将process的状态设置为了running,此处确保状态为running并且process所指的函数不为空    if((p->state & PROCESS_STATE_RUNNING) && p->thread != NULL) //thread是函数指针    {        PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);//打印进程名和事件号// process_current指向了当前处理的进程,所以在process_post_synch()调用完call_process()后要将process_current改回原值        process_current = p;         p->state = PROCESS_STATE_CALLED;        ret = p->thread(&p->pt, ev, data); //才真正执行PROCESS_THREAD(name, ev, data)定义的内容        if(ret == PT_EXITED || ret == PT_ENDED || ev == PROCESS_EVENT_EXIT)        {            exit_process(p, p); //如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出        } else         {            p->state = PROCESS_STATE_RUNNING; //进程挂起等待事件        }    }}

2.4 exit_process函数

//struct process *p 指要退出的进程//struct process *fromprocess 指当前的进程 ?//exit_process(p, p)static void exit_process(struct process *p, struct process *fromprocess){    register struct process *q;//把process指针存入寄存器    struct process *old_current = process_current;//先保存current指针,用完再换回来    PRINTF("process: exit_process '%s'\n", PROCESS_NAME_STRING(p));/*参数验证:确保要退出的进程在进程链表中*/    for(q = process_list; q != p && q != NULL; q = q->next);    if(q == NULL)     {        return;    }    if(process_is_running(p)) //return p->state != PROCESS_STATE_NONE;    {        p->state = PROCESS_STATE_NONE;/*向所有进程发一个同步事件PROCESS_EVENT_EXITED,通知他们将要退出,使得与该进程相关的进程进行相应处理*/        for(q = process_list; q != NULL; q = q->next)         {            if(p != q)             {                call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);            }        }        if(p->thread != NULL && p != fromprocess) /*退出的进程不是当前进程*/        {/* Post the exit event to the process that is about to exit. */            process_current = p;//给进程p传递一个PROCESS_EVENT_EXIT事件,通常用于退出死循环(如PROCESS_WAIT_EVENT函数),从而使其从主体函数退出            p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);        }    }/*将进程p从进程链表删除*/    if(p == process_list) //进程p恰好在进程链表首部    {        process_list = process_list->next;    }    else //进程p不在进程链表首部    {        for(q = process_list; q != NULL; q = q->next) //遍历进程链表,寻找进程p,删除之        {            if(q->next == p)             {                q->next = p->next;                break;            }        }    }    process_current = old_current;}

3.进程处理

3.1 process_run函数

/*process_run函数处理系统所有needspoll标记为1的进程及处理事件队列的下一个事件*/static volatile unsigned char poll_requested; //全局静态变量,标识系统是否有needspoll为1的进程int process_run(void){  if (poll_requested) //进程链表有needspoll为1的进程  {    do_poll();//见3.2  }  do_event();//见3.3  return nevents + poll_requested;//若和为0,则表示处理完系统的所有事件,并且没有needspoll为1的进程}

3.2 do_poll函数

/*复位全局变量poll_requested,遍历整个进程链表,将needspoll标记为1的进程投入运行,并将相应的needspoll复位*/static void do_poll(void){  struct process *p;  poll_requested = 0;//复位全局变量  for (p = process_list; p != NULL; p = p->next)//处理所有needspoll为1的进程  {    if (p->needspoll)//将needspoll为1的进程投入执行    {      p->state = PROCESS_STATE_RUNNING;      p->needspoll = 0;      call_process(p, PROCESS_EVENT_POLL, NULL);    }  }}

3.3 do_poll函数

/*do_event处理事件队列的一个事件,有两种事件需特殊处理:PROCESS_BROADCAST和PROCESS_EVENT_INIT。前者是广播事件,需处理所有进程,后者是初始化事件,需将进程状态设为PROCESS_STATE_RUNNING。*/static  process_num_events_t  nevents; /*事件队列的总事件数*/static  process_num_events_t  fevent; /*指向下一个要传递的事件的位置*/static struct event_data events[PROCESS_CONF_NUMEVENTS]; /*事件队列,用数组存储,逻辑上是环形队列*/static void do_event(void){//以下3个变量恰为struct event_data的成员,用于暂存即将处理(fevent事件)的值(2.1event_data的定义)  static process_event_t ev;  static process_data_t data;  static struct process *receiver;  static struct process *p;  if (nevents > 0)  {/*提取将要处理事件的成员变量*/    ev = events[fevent].ev;    data = events[fevent].data;    receiver = events[fevent].p;    fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS; //更新fevent(事件队列被组织成环形队列,所以取余数)    --nevents;    if (receiver == PROCESS_BROADCAST) //如果事件是广播事件PROCESS_BROADCAST,则处理所有进程    {      for (p = process_list; p != NULL; p = p->next)      {        if (poll_requested)        {          do_poll();        }        call_process(p, ev, data);      }    }    else    {      if (ev == PROCESS_EVENT_INIT) //若事件是初始化,设置进程状态,确保进程状态为PROCESS_STATE_RUNNING      {        receiver->state = PROCESS_STATE_RUNNING;      }      call_process(receiver, ev, data);    }  }}




0 0
原创粉丝点击