HelloWorld例子
#include "contiki.h" #include <stdio.h> /* For printf() */ /*---------------------------------------------------------------------------*/ PROCESS(hello_world_process, "Hello world process"); AUTOSTART_PROCESSES(&hello_world_process); /*---------------------------------------------------------------------------*/ PROCESS_THREAD(hello_world_process, ev, data) { PROCESS_BEGIN(); printf("Hello, world\n"); PROCESS_END(); }
PROCESS
#if PROCESS_CONF_NO_PROCESS_NAMES//是否字符串名字? #define PROCESS(name, strname) \ PROCESS_THREAD(name, ev, data); \//声明进程执行实体函数 struct process name = { NULL, process_thread_##name }//定义进程结构体变量name #else #define PROCESS(name, strname) \ PROCESS_THREAD(name, ev, data); struct process name = { NULL, strname, process_thread_##name } #endif
PROCESS_THREAD(name, ev, data);一步一步展开之后为:
#define PROCESS_THREAD(name, ev, data) static PT_THREAD(process_thread_##name(struct pt *process_pt, process_event_t ev, process_data_t data))
PT_THREAD看protothread机制
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);
这条语句相当于声明一个函数process_thread_hello_world,而这个函数就是进程执行实体函数。在后续的定义进程结构体可以看出。
进程结构体:
struct process { struct process *next;//指向下个进程结构体,在进程链表中使用 #if PROCESS_CONF_NO_PROCESS_NAMES//配置进程字符串名字? #define PROCESS_NAME_STRING(process) ""//没有,空 #else //有字符串名字 const char *name;//定义进程字符串名字 #define PROCESS_NAME_STRING(process) (process)->name//取名字 #endif PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));//进程执行实体函数 struct pt pt;//pt结构体,存储实体函数阻塞时的位置 unsigned char state, needspoll;//state是进程状态,needspoll标志进程是否需要优先执行 };
struct process hello_world_process = { NULL, strname, \ process_thread_hello_world_process }
后边的的语句定义了一个process变量hello_world_process,并赋初值,为简化这里按有strname来处理。
总之,PROCESS宏定义,有两个功能,声明进程执行实体函数,定义进程结构体变量,如下所示:
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data); struct process hello_world_process = { NULL, strname, \ process_thread_hello_world_process }
注:这里只需要抓住hello_world_process变量,就抓住了整个进程。
AUTOSTART_PROCESSES
全部展开:
AUTOSTART_PROCESSES(&hello_world_process); #if ! CC_NO_VA_ARGS #if AUTOSTART_ENABLE #define AUTOSTART_PROCESSES(...) struct process * const autostart_processes[] = {__VA_ARGS__, NULL} #else /* AUTOSTART_ENABLE */ #define AUTOSTART_PROCESSES(...) extern int _dummy #endif /* AUTOSTART_ENABLE */ #else #error "C compiler must support __VA_ARGS__ macro" #endif
这里用到C99 支持可变参数宏的特性,如:#define debug(…) printf(__VA_ARGS__) ,缺省号代表一个可以变化的参数表,宏展开时,实际的参数就传递给 printf()了。例:debug("Y = %d\n", y); 被替换成printf("Y = %d\n", y)【参考http://blog.chinaunix.net/uid-9112803-id-2898026.html】
为了简洁,我们这里按有AUTOSTART_ENABLE来分析
最终展开为:
struct process * const autostart_processes[] = {&hello_world_process, NULL};
hello_world_process是上边声明的process结构体变量,所以AUTOSTART_PROCESSES(&hello_world_process)就是定义了一个数组,这个数组定义了要自启动的进程的process结构体变量指针。
我们用一个例子来说明,进程是怎么自启动的。
源代码$contiki$\platform\stm32test\contiki-main.c
int main() { dbg_setup_uart(); printf("Initialising\n"); clock_init(); process_init(); process_start(&etimer_process, NULL); autostart_start(autostart_processes); printf("Processes running\n"); while(1) { do { } while(process_run() > 0); idle_count++; /* Idle! */ /* Stop processor clock */ /* asm("wfi"::); */ } return 0; }
可以看到,主函数在进行一系列初始化之后,启动etimer_process进程,然后启动需要自启动的进程。
我们进一步展开autostart_start函数,其中autostart_processes是上边声明定义的一个数组。
void autostart_start(struct process * const processes[]) { int i; for(i = 0; processes[i] != NULL; ++i) { process_start(processes[i], NULL); PRINTF("autostart_start: starting process ‘%s‘\n", processes[i]->name); } }
可以看到依次启动autostart_processes数组中的各个指针所对应的进程,这里的process_start等函数,后续再深究。
PROCESS_THREAD
PROCESS_THREAD(hello_world_process, ev, data) { …… }
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data){ ……}
这里的PROCESS_THREAD是定义进程执行主体函数,跟上边的不一样,上边的是声明这样一个函数。
总之,PROCESS_THREAD有两个作用:声明或者定义进程执行主体函数
使用protothread机制的宏定义
PROCESS_BEGIN
#define PROCESS_BEGIN() PT_BEGIN(process_pt)
其中process_pt是进程执行主体传进来的参数 struct pt *process_pt。protothread机制
这个是进程开始的标志。
PROCESS_END
#define PROCESS_END() PT_END(process_pt)
进程结束标志。
注:进程执行主体语句要放在PROCESS_BEGIN和PROCESS_END之间,不然会有不确定的错误发生。
PROCESS_WAIT_EVENT
#define PROCESS_WAIT_EVENT() PROCESS_YIELD()
进程执行实体函数返回PT_YIELD,然后等待任一事件(进程是由事件驱动的)的到来,重新回到进程执行主体函数上次阻塞的位置,又继续执行后续的语句。
注:由protothread机制知,每次执行进程实体函数时,都会运行到PROCESS_BEGIN,然后才跳转。
PROCESS_WAIT_EVENT_UNTIL
#define PROCESS_WAIT_EVENT_UNTIL(c) PROCESS_YIELD_UNTIL(c)
等待一个事件,并附加条件c
PROCESS_YIELD
#define PROCESS_YIELD() PT_YIELD(process_pt)
YIELD(放弃执行权)
PROCESS_YIELD_UNTIL
#define PROCESS_YIELD_UNTIL(c) PT_YIELD_UNTIL(process_pt, c)
YIELD直到条件c成立
PROCESS_WAIT_UNTIL
#define PROCESS_WAIT_UNTIL(c) PT_WAIT_UNTIL(process_pt, c)
一直等待,直到条件c
PROCESS_WAIT_WHILE
#define PROCESS_WAIT_WHILE(c) PT_WAIT_WHILE(process_pt, c)
当条件c,等待
PROCESS_EXIT
#define PROCESS_EXIT() PT_EXIT(process_pt)
进程退出
PROCESS_PT_SPAWN
#define PROCESS_PT_SPAWN(pt, thread) PT_SPAWN(process_pt, pt, thread)
#define PT_SPAWN(pt, child, thread) do { PT_INIT((child)); PT_WAIT_THREAD((pt), (thread)); } while(0)
生产一个子进程,并阻塞住,直到子进程执行完毕,再继续后边程序的执行。
注:这里要明确一个概念,进程是由事件驱动的,只有当有事件发生时,进程执行实体函数才会开始执行,也就是说一旦发生阻塞,执行实体函数返回并退出,那么只有事件来了,才会再次进入进程执行实体函数,执行完PROCESS_BEGIN后跳转到阻塞位置,判断是否继续阻塞。
HelloWorld例子展开代码
GCCc语言拓展实现版
#include "contiki.h" #include <stdio.h> /* For printf() */ static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data); struct process hello_world_process = { NULL, "Hello world process", process_thread_hello_world_process }; struct process * const autostart_processes[] = {&hello_world_process, NULL}; static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data) { { char PT_YIELD_FLAG = 1; if (PT_YIELD_FLAG) {;} do { if(s != NULL) { goto *s; } } while(0) printf("Hello, world\n"); PT_YIELD_FLAG = 0; PT_INIT(pt); return PT_ENDED; } }
switch语句实现版
#include "contiki.h" #include <stdio.h> /* For printf() */ static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data); struct process hello_world_process = { NULL, "Hello world process", process_thread_hello_world_process }; struct process * const autostart_processes[] = {&hello_world_process, NULL}; static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data) { { char PT_YIELD_FLAG = 1; if (PT_YIELD_FLAG) {;} switch(s) { case 0: printf("Hello, world\n"); } PT_YIELD_FLAG = 0; PT_INIT(pt); return PT_ENDED; } }