進程調度器
進程調度器的作用是調用進程。進程調度器通過調用實現進程線程的函數來調用進程。Contiki中所有的進程被設計為響應傳遞到進程中的事件,或者相應進程請求的輪詢。進程調度器在調度進程的時候會將事件標識符和一個不透明指針傳遞到進程中,該指針由進程調用者提供,可以設置為NULL(該事件不需要傳遞數據)。當進程輪詢時,不會傳遞數據。
開始進程
1 /** 2 * Start a process. 3 * 4 * \param p A pointer to a process structure. 5 * 6 * \param arg An argument pointer that can be passed to the new 7 * process 8 * 9 */ 10 CCIF void process_start(struct process *p, const char *arg);
1 void 2 process_start(struct process *p, const char *arg) 3 { 4 struct process *q; 5 6 /* First make sure that we don't try to start a process that is 7 already running. */ 8 for(q = process_list; q != p && q != NULL; q = q->next); 9 10 /* If we found the process on the process list, we bail out. */ 11 if(q == p) { 12 return; 13 } 14 /* Put on the procs list.*/ 15 p->next = process_list; 16 process_list = p; 17 p->state = PROCESS_STATE_RUNNING; 18 PT_INIT(&p->pt); 19 20 PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p)); 21 22 /* Post a synchronous initialization event to the process. */ 23 process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg); 24 }
process_start()開始一個進程。該函數的目的是設置進程控制塊,將進程加入到內核有效進程鏈表中,然后調用進程線程中的初始化代碼。最后給該進程發送一個同步的初始化事件。process_start()被調用后,該進程就開始運行了。
process_start()函數先做一個明智的檢查,檢查是否該進程已經存在進程鏈表中。如果是,表明該進程已經被運行了,process_start()函數直接返回。在確認該進程沒有開始運行后,內核將該進程加入到鏈表中,並設置進程控制塊。進程的狀態被設置為PROCESS_STATE_RUNNING,進程的線程被PT_INIT()初始化。最后,內核為進程發送給一個同步事件PROCESS_EVENT_INIT,且傳遞一個不透明指針給進程,該指針是由調用process_start()的進程傳入的,用於傳遞給要運行的進程一些信息。不過,這個指針一般都設為NULL。當進程接收到它的第一個事件PROCESS_EVENT_INIT,進程將執行該進程線程的第一部分。通常,這部分包含進程開始時即將運行的初始化代碼。
退出進程和殺死進程
進程退出有兩種方法:進程自動退出和被其它進程殺死。調用函數process_exit()或者當進程線程執行到PROCESS_END()語句時,進程將退出。
進程可以調用函數process_exit()殺死另一個進程。
當一個進程退出(無論是主動退出還是被動退出),Contiki內核會發送給一個事件通知其它進程,這可以讓其它進程釋放退出進程所占有的資源。事件PROCESS_EVENT_EXITED將會被以同步事件的方式發送到其它所有進程。
當一個被另一個金曾殺死時,被殺的進程將會接收到同步事件PROCESS_EVENT_EXIT,該事件通知將要被殺死的進程和能夠釋放已分配資源的進程,或者其它將要退出的進程。
在Contiki內核發送事件通知將要退出的進程后,將從進程鏈表中刪除該進程。
自啟動進程
Contiki提供了一個機制,在系統啟動時,或者包含進程的模塊被加載時,自動運行進程。該機制由自啟動模塊實現。該機制能夠讓模塊開發者告知系統該模塊中包含什么進程。當模塊從內存中移除時,也能讓系統做相應的處理。
自啟動進程保存在一個鏈表中,自啟動模塊利用該鏈表實現自動運行進程。進程啟動的順序與它在鏈表中的順序一致。
自啟動進程有兩種時機:系統啟動時和模塊被加載時。所有需要在系統啟動時自啟動的進程必須被包含在一個單一的系統級的鏈表中。這個自啟動鏈表由用戶提供,且一般在一個用戶模塊中。當這個模塊被用作可加載模塊時,鏈表能夠讓系統知道模塊被加載時需要運行什么進程。
當加載一個模塊時,模塊加載器將查找自啟動進程鏈表,並在模塊被加載到內存后啟動鏈表中的進程。當模塊將要被卸載時,模塊加載器利用該鏈表殺死在模塊加載時啟動的進程。
一個接收事件並打印其數字的進程的例子:
1 #include "contiki.h" 2 3 PROCESS(example_process, "Example process"); 4 AUTOSTART_PROCESSES(&example_process); 5 6 PROCESS_THREAD(example_process, ev, data) 7 { 8 PROCESS_BEGIN(); 9 10 while(1) { 11 PROCESS_WAIT_EVENT(); 12 printf("Got event number %d\n", ev); 13 } 14 15 PROCESS_END(); 16 }
上面的代碼是一個Contiki完整的進程。該進程被申明、定義和自動運行。
第三行,我們定義了進程控制塊。進程控制塊定義了進程控制塊的名字example_process和文本的、用戶可讀的進程名字Example process。在定義了進程控制塊后,我們可以在其它表達式中使用該變量名。
第四行,語句AUTOSTART_PROCESSES()告訴Contiki在系統啟動時自動啟動進程example_process。自啟動鏈表由指向進程控制塊的指針組成,所以需要在變量example_process前加&取地址符。
第六行,我們定義了進程線程。它包含了進程的變量名example_process和傳遞事件的變量ev及數據data。
第八行,我們使用了PROCESS_BEGIN()定義了一個進程的開始。該定義標志進程線程的開始。在進程每次被調度運行的時候,該申明語句上面的代碼都會運行。在大多數情形下,你不需要在PROCESS_BEGIN()之上放任何代碼。
第十行,開始進程的主循環。Contiki進程不能包含永不結束的死循環。但是在上面代碼中,這樣的死循環是安全的,因為進程將會等待時間。當一個Contiki進程在等待事件時,它會將控制器返回給Contiki內核。在該進程等待期間,內核將會為其它進程提供服務。
第十一行,進程等待事件的發生。表達式PROCESS_WAIT_EVENT()將返回控制權給Contiki內核,並等待內核傳遞事件到該進程。當Contiki內核傳遞事件給該進程后,PROCESS_WAIT_EVENT()后面的代碼將被執行。在進程被喚醒后,將執行第十二行的打印語句。這一行的作用是打印進程接收到的事件編號。如果同時傳入 了一個指針,該指針變量就是data(?)。
第十五行,PROCESS_END()標識進程的結束。每個Contiki進程必須包含PROCESS_BEGIN()和PROCESS_END()。當執行到PROCESS_END()時,該進程自動退出,並從內核中的進程鏈表中移除。不過,由於存在死循環,永遠不會執行到PROCESS_END()。只有系統被關掉、或者該進程被process_exit()殺死的時候才會被停止運行。
一個啟動進程並發送事件的函數
1 static char msg[] = "Data"; 2 3 static void 4 example_function(void) 5 { 6 /* Start "Example process", and send it a NULL 7 pointer. */ 8 9 process_start(&example_process, NULL); 10 11 /* Send the PROCESS_EVENT_MSG event synchronously to 12 "Example process", with a pointer to the message in the 13 array 'msg'. */ 14 process_post_synch(&example_process, 15 PROCESS_EVENT_CONTINUE, msg); 16 17 /* Send the PROCESS_EVENT_MSG event asynchronously to 18 "Example process", with a pointer to the message in the 19 array 'msg'. */ 20 process_post(&example_process, 21 PROCESS_EVENT_CONTINUE, msg); 22 23 /* Poll "Example process". */ 24 process_poll(&example_process); 25 }
兩個進程間通過事件完成交互。上面的例子中的函數啟動了一個進程,並向它發送一個同步事件和輪詢請求。
總結
進程通過發送事件實現與其它進程通信。
摘錄自:http://blog.csdn.net/tidyjiang/article/details/51378589