Contiki系统关于PROCESS_CONTEXT_BEGIN与PROCESS_CONTEXT_END见解

来源:互联网 发布:电脑连接的常用端口 编辑:程序博客网 时间:2024/06/14 23:35

在阅读socket源码时有PROCESS_CONTEXT_BEGIN与PROCESS_CONTEXT_END的使用。字面意思是切换上下文,但是个人的理解,在其他操作系统切换上下文是指进出栈保存的。很明显contiki是不具备这功能的,因此很很疑惑他的作用。网上搜索了一下也没有关于此系统宏的解析,由此写下这一篇,用于记录。

以下是源码中对于PROCESS_CONTEXT_BEGIN、PROCESS_CONTEXT_END的注释。
/** * Switch context to another process * * This function switch context to the specified process and executes * the code as if run by that process. Typical use of this function is * to switch context in services, called by other processes. Each * PROCESS_CONTEXT_BEGIN() must be followed by the * PROCESS_CONTEXT_END() macro to end the context switch. * * Example: \code PROCESS_CONTEXT_BEGIN(&test_process); etimer_set(&timer, CLOCK_SECOND); PROCESS_CONTEXT_END(&test_process); \endcode * * \param p    The process to use as context * * \sa PROCESS_CONTEXT_END() * \sa PROCESS_CURRENT() */

对注释Example展开可以得到以下源码,作用是保存了当前系统指针,并把需要调用的进程指针指向当前指针,然后执行etimer_set函数。

 PROCESS_CONTEXT_BEGIN(&test_process); etimer_set(&timer, CLOCK_SECOND); PROCESS_CONTEXT_END(&test_process);//展开如下{struct process *tmp_current = PROCESS_CURRENT();process_current = &test_process;etimer_set(&timer, CLOCK_SECOND);process_current = tmp_current;}

注释上写明是调用服务时需要这样做,那么疑问是为什么需要这样做呢?

查看etimer_set源码,发现其调用的add_timer函数会把当前的进程指针PROCESS_CURRENT()存到定时器的结构体中。因此,如果在一个进程中调用其他进程的服务函数将会导致进程指针不对而不起作用,甚至跑飞。

static voidadd_timer(struct etimer *timer){  struct etimer *t;  etimer_request_poll();  if(timer->p != PROCESS_NONE) {    for(t = timerlist; t != NULL; t = t->next) {      if(t == timer) {    /* Timer already on list, bail out. */        timer->p = PROCESS_CURRENT();    update_time();    return;      }    }  }  /* Timer not on list. */  timer->p = PROCESS_CURRENT();  timer->next = timerlist;  timerlist = timer;  update_time();}

下面为ubuntu下仿真的代码,测试了几个方面的系统操作,1、hello_world_process线程的挂起;2、context_process本篇的重点,PROCESS_CONTEXT_BEGIN和PROCESS_CONTEXT_END的使用;3、test_process进程,etimer的使用和对其他进程的触发。

#include "contiki.h"#include <stdio.h> /* For printf() *//*---------------------------------------------------------------------------*/PROCESS(hello_world_process, "Hello world process");/*---------------------------------------------------------------------------*/PROCESS_THREAD(hello_world_process, ev, data){static struct etimer et;    PROCESS_BEGIN();    while(1)    {    printf("Hello, world\n");    PROCESS_WAIT_EVENT();    etimer_set(&et, CLOCK_SECOND*2);      printf("hold 1\n");    PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_POLL || ev == PROCESS_EVENT_TIMER);    printf("hold 2\n");    PROCESS_WAIT_EVENT();    }   PROCESS_END();}static struct etimer het;/*---------------------------------------------------------------------------*/PROCESS(context_process, "contextprocess");/*---------------------------------------------------------------------------*/PROCESS_THREAD(context_process, ev, data){  PROCESS_BEGIN();    while(1)    {        printf("context\n");        PROCESS_WAIT_EVENT_UNTIL( ev == PROCESS_EVENT_TIMER);      }   PROCESS_END();}/*---------------------------------------------------------------------------*//*---------------------------------------------------------------------------*/PROCESS(test_process, "test process");AUTOSTART_PROCESSES(&test_process);/*---------------------------------------------------------------------------*/PROCESS_THREAD(test_process, ev, data){    static struct etimer et;      static int cnt= 0;    PROCESS_BEGIN();    etimer_set(&et, CLOCK_SECOND);      process_start(&hello_world_process,0);    process_start(&context_process,0);    while(1)    {        PROCESS_WAIT_EVENT_UNTIL( ev == PROCESS_EVENT_TIMER);          etimer_set(&et, CLOCK_SECOND);          cnt++;        if(cnt>5)        {            cnt =0;            process_poll(&hello_world_process);        }        else        {            printf("%d:",clock_time());            printf("test, world\n");            PROCESS_CONTEXT_BEGIN(&context_process);            etimer_set(&het, CLOCK_SECOND*1);              PROCESS_CONTEXT_END(&context_process);        }    }   PROCESS_END();}/*---------------------------------------------------------------------------*/

代码运行结果如下:
Contiki 3.x started with IPV6, RPL
Rime started with address 1.2.3.4.5.6.7.8
MAC nullmac RDC nullrdc NETWORK sicslowpan
Tentative link-local IPv6 address fe80:0000:0000:0000:0302:0304:0506:0708
Hello, world
context
1793399050:test, world
context
1793400051:test, world
context
1793401051:test, world
context
1793402052:test, world
context
1793403053:test, world
context
hold 1
1793405054:test, world
1793406054:test, world
1793407054:test, world
context
context
1793408056:test, world

假如对test_process代码进行如下注释:

            //PROCESS_CONTEXT_BEGIN(&context_process);            etimer_set(&het, CLOCK_SECOND*1);              //PROCESS_CONTEXT_END(&context_process);

得到的输出结果如下:

Contiki 3.x started with IPV6, RPL
Rime started with address 1.2.3.4.5.6.7.8
MAC nullmac RDC nullrdc NETWORK sicslowpan
Tentative link-local IPv6 address fe80:0000:0000:0000:0302:0304:0506:0708
Hello, world
context
1793689078:test, world
1793690079:test, world
1793690080:test, world
1793691081:test, world
1793691081:test, world
hold 1
1793692081:test, world
1793693082:test, world
1793693084:test, world
hold 2
1793694084:test, world
1793694085:test, world
Hello, world
1793695085:test, world
1793696085:test, world
1793696085:test, world
1793697085:test, world
1793697085:test, world
hold 1
1793698087:test, world
1793699087:test, world
1793699088:test, world

结果表明,context_process并没有被触发,因为etimer het得到得进程指针并不是context_process指针,系统服务进程etiemr没有post事件给context_process。


PROCESS_CONTEXT_BEGIN和PROCESS_CONTEXT_END的使用场景,应该是在运行一个进程时,想对另外一个进程进行一些系统服务操作,如etimer、ctimer等定时器的操作,改变他的参数。

原创粉丝点击