process调用protothread机制的相关宏定义——用HelloWorld进程诠释
一、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 } #endifPROCESS_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//取名字 #endifPT_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, "Hello world process", \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, "Hello world process", \ 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機制的宏定義
?
1、PROCESS_BEGIN
#define PROCESS_BEGIN() PT_BEGIN(process_pt)其中process_pt是進程執行主體傳進來的參數 struct pt *process_pt。protothread機制
這個是進程開始的標志。
?
2、PROCESS_END
#define PROCESS_END() PT_END(process_pt)進程結束標志。
注:進程執行主體語句要放在PROCESS_BEGIN和PROCESS_END之間,不然會有不確定的錯誤發生。
?
3、HelloWorld例子展開代碼
(1)GCC c語言拓展實現版
#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((process_pt)->lc != NULL) {goto *(process_pt)->lc;} } while(0)printf("Hello, world\n");PT_YIELD_FLAG = 0;PT_INIT(pt);return PT_ENDED; }}?
(2)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((process_pt)->lc) { case 0:printf("Hello, world\n");}PT_YIELD_FLAG = 0;PT_INIT(pt);return PT_ENDED; }}注:后續以switch語句為例子。
?
4、PROCESS_WAIT_EVENT
#define PROCESS_WAIT_EVENT() PROCESS_YIELD()我們假設在HelloWorld例子進程執行實體函數中插入這條語句:
PROCESS_THREAD(hello_world_process, ev, data) {PROCESS_BEGIN();PROCESS_WAIT_EVENT();printf("Hello, world\n");PROCESS_END(); } 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((process_pt)->lc) { case 0:do { PT_YIELD_FLAG = 0;process_pt->lc = _LINE_;case _LINE:if(PT_YIELD_FLAG == 0) {return PT_YIELDED;}} while(0); printf("Hello, world\n");}PT_YIELD_FLAG = 0;PT_INIT(pt);return PT_ENDED; }}?進程執行實體函數返回PT_YIELD,然后等待任一事件(進程是由事件驅動的)的到來,重新回到進程執行主體函數上次阻塞的位置_LINE_,又繼續執行后續的語句。
注:由protothread機制知,每次執行進程實體函數時,都會運行到PROCESS_BEGIN,然后才跳轉。
注:這里要明確一個概念,進程是由事件驅動的,只有當有事件發生時,進程執行實體函數才會開始執行,也就是說一旦發生阻塞,執行實體函數返回并退出,那么只有事件來了,才會再次進入進程執行實體函數,執行完PROCESS_BEGIN后跳轉到阻塞位置,判斷是否繼續阻塞。
?
5、PROCESS_WAIT_EVENT_UNTIL
#define PROCESS_WAIT_EVENT_UNTIL(c) PROCESS_YIELD_UNTIL(c)等待一個事件,并附加條件c
?
6、PROCESS_YIELD
#define PROCESS_YIELD() PT_YIELD(process_pt)YIELD(放棄執行權)
?
7、PROCESS_YIELD_UNTIL
#define PROCESS_YIELD_UNTIL(c) PT_YIELD_UNTIL(process_pt, c)YIELD直到條件c成立
?
8、PROCESS_WAIT_UNTIL
#define PROCESS_WAIT_UNTIL(c) PT_WAIT_UNTIL(process_pt, c)一直等待,直到條件c
?
9、PROCESS_WAIT_WHILE
#define PROCESS_WAIT_WHILE(c) PT_WAIT_WHILE(process_pt, c)當條件c,等待
?
10、PROCESS_EXIT
#define PROCESS_EXIT() PT_EXIT(process_pt)進程退出
?
11、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)生產一個子進程,并阻塞住,直到子進程執行完畢,再繼續后邊程序的執行。
?
轉載于:https://www.cnblogs.com/songdechiu/p/5801136.html
總結
以上是生活随笔為你收集整理的process调用protothread机制的相关宏定义——用HelloWorld进程诠释的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CentOS7 安装MongoDB 3.
- 下一篇: 组合排列的实现方法