代码下载地址:,工程目录contiki_stm32\platform\stm32test\MDK_5,使用的是MDK5,硬件环境STM32F0
-
#include "app_uart_fifo.h"
-
#include <stdint.h>
-
#include <stdio.h>
-
#include <sys/process.h>
-
#include <sys/procinit.h>
-
#include <etimer.h>
-
#include <sys/autostart.h>
-
#include <clock.h>
-
#include "bsp_imp.h"
-
-
static void CtimerTest_Callback(void *p)
-
{
-
printf("Ctimer Callback running\r\n");
-
}
-
-
-
-
static process_event_t event_data_ready;
-
-
PROCESS(print_hello_process, "Hello");
-
PROCESS(print_world_process, "world");
-
-
AUTOSTART_PROCESSES(&print_hello_process, &print_world_process);
-
-
-
PROCESS_THREAD(print_hello_process, ev, data)
-
{
-
PROCESS_BEGIN();
-
static struct etimer timer;
-
-
etimer_set(&timer, CLOCK_CONF_SECOND*5);
-
printf("***print hello process start***\r\n");
-
-
event_data_ready = process_alloc_event();
-
while (1)
-
{
-
-
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER);
-
-
printf("Hello\r\n");
-
-
process_post(&print_world_process, event_data_ready, NULL);
-
-
etimer_reset(&timer);
-
}
-
-
PROCESS_END();
-
}
-
-
PROCESS_THREAD(print_world_process, ev, data)
-
{
-
PROCESS_BEGIN();
-
-
printf("***print world process start***\r\n");
-
-
-
while (1)
-
{
-
PROCESS_WAIT_EVENT_UNTIL(ev == event_data_ready);
-
printf("world\r\n");
-
}
-
-
PROCESS_END();
-
}
-
-
-
unsigned int idle_count = 0;
-
-
int main()
-
{
-
Bsp_Init();
-
printf("Initialising\r\n");
-
-
clock_init();
-
-
ctimer_init();
-
-
process_init();
-
process_start(&etimer_process, NULL);
-
autostart_start(autostart_processes);
-
printf("Processes running\r\n");
-
-
while(1) {
-
do {
-
-
} while(process_run() > 0);
-
idle_count++;
-
}
-
}
执行流程
程序启动,contiki中定时器运行,定时时间到,执行流程如下:SysTick_Handler() -> etimer_request_poll() .> process_run() -> do_poll() -> etimer_process() -> process_post() ..> do_event() -> print_hello_process(),到此运行打印hello的线程。打印world的线程和上面类似,print_hello_process传递一个事件到world线程,通知其打印world。
进程挂起
上述程序执行到
etimer_process()进程时是如何挂起自己的呢?该进程的源码如下:
-
PROCESS_THREAD(etimer_process, ev, data)
-
{
-
struct etimer *t, *u;
-
-
PROCESS_BEGIN();//进程每次得到CPU使用权均要从这里运行,详见分析
-
-
timerlist = NULL;
-
-
while(1) {
-
PROCESS_YIELD();//使进程挂起,详见下面分析
-
-
if(ev == PROCESS_EVENT_EXITED) {
-
struct process *p = data;
-
-
while(timerlist != NULL && timerlist->p == p) {
-
timerlist = timerlist->next;
-
}
-
-
if(timerlist != NULL) {
-
t = timerlist;
-
while(t->next != NULL) {
-
if(t->next->p == p) {
-
t->next = t->next->next;
-
} else
-
t = t->next;
-
}
-
}
-
continue;
-
} else if(ev != PROCESS_EVENT_POLL) {
-
continue;
-
}
-
-
again:
-
-
u = NULL;
-
-
for(t = timerlist; t != NULL; t = t->next) {
-
if(timer_expired(&t->timer)) {
-
if(process_post(t->p, PROCESS_EVENT_TIMER, t) == PROCESS_ERR_OK) {
-
-
/* Reset the process ID of the event timer, to signal that the
-
etimer has expired. This is later checked in the
-
etimer_expired() function. */
-
t->p = PROCESS_NONE;
-
if(u != NULL) {
-
u->next = t->next;
-
} else {
-
timerlist = t->next;
-
}
-
t->next = NULL;
-
update_time();
-
goto again;
-
} else {
-
etimer_request_poll();
-
}
-
}
-
u = t;
-
}
-
-
}
-
-
PROCESS_END();//进程退出
-
}
重要宏定义
-
PROCESS_BEGIN();
-
-
#define PROCESS_BEGIN() PT_BEGIN(process_pt)
-
-
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; if (PT_YIELD_FLAG) {;} LC_RESUME((pt)->lc)
-
#define LC_RESUME(s) switch(s) { case 0:
PROCESS_BEGIN()线程每次均要从这里启动,并根据(pt)->lc实现跳转,这里类似与操作系统中保护现场,这里如果线程被挂起,也需要保护现场,这里保存本次运行的行数,下次在运行根据上次保存的行数实现跳转。因此该宏定义有两个作用:实现线程启动(该宏将置PT_YIELD_FLAG1,后面会有说明);跳转到上次运行的位置。
-
#define PROCESS_END() PT_END(process_pt)
-
#define PT_END(pt) LC_END((pt)->lc); PT_YIELD_FLAG = 0; \
-
PT_INIT(pt); return PT_ENDED; }
PROCESS_END()结束线程的运行,和PROCESS_BEGIN()成对使用。
-
#define PROCESS_YIELD() PT_YIELD(process_pt)
-
#define PT_YIELD(pt) \
-
do { \
-
PT_YIELD_FLAG = 0; \
-
LC_SET((pt)->lc); \
-
if(PT_YIELD_FLAG == 0) { \
-
return PT_YIELDED; \
-
} \
-
} while(0)
PROCESS_YIELD()这个宏定义实现了进程挂起,并保护了现场。将其与PROCESS_BEGIN()和在一起看看执行流程。
开始执行etimer进程,一直执行到PROCESS_YIELD(),保存现场,并实现进程挂起。第二次运行时,PROCESS_BEGIN将PT_YIELD_FLAG置1(让进程可以运行),并跳转到开始运行保护现场的位置。此时即实现了进程挂起和启动进程的功能。
阅读(554) | 评论(0) | 转发(0) |