Contiki-NG中的應(yīng)用程序通常是使用Process抽象編寫的。 進(jìn)程建立在稱為Protothreads的輕量級(jí)線程庫的頂部。
進(jìn)程定義
首先在源文件的頂部聲明一個(gè)進(jìn)程。 PROCESS()宏帶有兩個(gè)參數(shù):一個(gè)是用于標(biāo)識(shí)進(jìn)程的變量,另一個(gè)是進(jìn)程的名稱。 在第二行中,我們告訴Contiki-NG,該過程應(yīng)在系統(tǒng)啟動(dòng)后立即自動(dòng)啟動(dòng)。 可以在此處指定多個(gè)進(jìn)程,以逗號(hào)分隔。 如果AUTOSTART_PROCESSES()行不包含現(xiàn)有進(jìn)程,則必須使用process_start()函數(shù)手動(dòng)啟動(dòng)該進(jìn)程。
#include "contiki.h" /* Main include file for OS-specific modules. */
#include <stdio.h> /* For printf. */
PROCESS(test_proc, "Test process");
AUTOSTART_PROCESSES(&test_proc);
下面是一個(gè)基本的的進(jìn)程定義
PROCESS_THREAD(test_proc, ev, data)
{
PROCESS_BEGIN();
printf("Hello, world!\n");
PROCESS_END();
}
首先,PROCESS_THREAD()宏采用PROCESS()調(diào)用中指定的進(jìn)程的標(biāo)識(shí)符。 ev和data參數(shù)包含傳入事件的值,以及指向事件參數(shù)對象的可選指針。 PROCESS_BEGIN()標(biāo)記將開始執(zhí)行過程的位置。 在大多數(shù)情況下,除變量定義外,程序員應(yīng)避免將代碼放在PROCESS_THREAD()主體中此語句上方。
對于我們的基本流程實(shí)現(xiàn),我們不必關(guān)心任何事件處理,因?yàn)槲覀冎粓?zhí)行一條語句,然后通過讓其到達(dá)PROCESS_END()調(diào)用隱式退出流程。
事件和調(diào)度
Contiki-NG建立在基于事件的執(zhí)行模型上,在該模型中,進(jìn)程通常在告訴調(diào)度程序它們正在等待事件之前執(zhí)行大量工作,從而暫停執(zhí)行。 此類事件可能是計(jì)時(shí)器到期、傳入的網(wǎng)絡(luò)數(shù)據(jù)包或正在傳遞的串口消息。
contiki采用協(xié)同式進(jìn)程調(diào)度,這意味著每個(gè)進(jìn)程負(fù)責(zé)將控制權(quán)自愿交還給操作系統(tǒng),而不去執(zhí)行太長時(shí)間。 因此,應(yīng)用程序開發(fā)人員必須確保將長時(shí)間運(yùn)行的操作拆分為多個(gè)進(jìn)程調(diào)度,以允許調(diào)度程序在上一次停止的位置恢復(fù)。
等待事件
通過在PROCESS_BEGIN()和PROCESS_END()之間區(qū)域中調(diào)用PROCESS_WAIT_EVENT_UNTIL(),可以將控制權(quán)交給調(diào)度程序,并且僅在事件到達(dá)時(shí)才恢復(fù)執(zhí)行。 給出了一個(gè)條件作為PROCESS_WAIT_EVENT_UNTIL()的參數(shù),必須滿足此條件才能使進(jìn)程在調(diào)用PROCESS_WAIT_EVENT_UNTIL()之后繼續(xù)執(zhí)行。 如果不滿足該條件,則該過程將控制權(quán)交還給OS,直到傳遞新事件為止。
PROCESS_THREAD(test, ev, data)
{
/* An event-timer variable. Note that this variable must be static
in order to preserve the value across yielding. */
static struct etimer et;
PROCESS_BEGIN();
etimer_set(&et, CLOCK_SECOND); /* Trigger a timer after 1 second. */
while(1) {
PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et));
etimer_reset(&et);
}
PROCESS_END();
}
暫停和退讓
要自愿釋放對調(diào)度程序的控制,可以調(diào)用PROCESS_PAUSE(),如下例所示。 然后,調(diào)度程序?qū)鬟f所有排隊(duì)的事件,然后立即調(diào)度已暫停的進(jìn)程。
PROCESS_THREAD(test_proc, ev, data)
{
PROCESS_BEGIN();
while(have_operations_to_do()) {
do_some_operations();
PROCESS_PAUSE();
}
PROCESS_END();
}
相比之下,PROCESS_YIELD()會(huì)將控制權(quán)交還給調(diào)度程序,而不希望此后不久再進(jìn)行調(diào)度。 相反,它將等待傳入事件,類似于PROCESS_WAIT_EVENT_UNTIL(),但沒有必需的條件參數(shù)。 可以通過調(diào)用process_poll()由外部進(jìn)程或模塊輪詢已產(chǎn)生的進(jìn)程。 要輪詢使用變量test_proc聲明的進(jìn)程,可以調(diào)用process_poll(&test_proc);。 輪詢進(jìn)程將立即進(jìn)行調(diào)度,并且將向其發(fā)送PROCESS_EVENT_POLL事件。
停止進(jìn)程
一個(gè)過程可以通過三種方式停止:
- 通過允許到達(dá)并執(zhí)行
PROCESS_END()語句,該過程隱式退出。 - 通過在
PROCESS_THREAD主體中調(diào)用PROCESS_EXIT(),顯式退出該進(jìn)程。 - 另一個(gè)進(jìn)程通過調(diào)用
process_exit()終止該進(jìn)程。
停止進(jìn)程后,可以通過調(diào)用process_start()從頭開始重新啟動(dòng)。
系統(tǒng)定義的事件
Contiki-NG使用基于系統(tǒng)定義的事件進(jìn)行常見操作,如下所示。
| Event | ID | Description |
|---|---|---|
| PROCESS_EVENT_NONE | 0x80 | 無事件 |
| PROCESS_EVENT_INIT | 0x81 | 傳遞給正在開始的進(jìn)程 |
| PROCESS_EVENT_POLL | 0x82 | 傳遞給正在輪詢的進(jìn)程. |
| PROCESS_EVENT_EXIT | 0x83 | 傳遞給正在退出的進(jìn)程。 |
| PROCESS_EVENT_SERVICE_REMOVED | 0x84 | 未使用的. |
| PROCESS_EVENT_CONTINUE | 0x85 | 交付給從暫停中恢復(fù)執(zhí)行時(shí)的進(jìn)程。 |
| PROCESS_EVENT_MSG | 0x86 | 在發(fā)生傳感器事件時(shí)傳遞給進(jìn)程。 |
| PROCESS_EVENT_EXITED | 0x87 | Delivered to all processes about an exited process. |
| PROCESS_EVENT_TIMER | 0x88 | 當(dāng)某個(gè)計(jì)時(shí)器到期時(shí),將其交付給進(jìn)程。 |
| PROCESS_EVENT_COM | 0x89 | Unused. |
| PROCESS_EVENT_MAX | 0x8a | 系統(tǒng)定義的事件的最大數(shù)量。 |
用戶自定義的事件
還可以指定系統(tǒng)定義的事件未涵蓋的新事件。 應(yīng)該在適當(dāng)?shù)姆秶鷥?nèi)定義和聲明事件變量,以便該事件的所有預(yù)期用戶都可以訪問它。 基本情況是僅在單個(gè)模塊中使用它,然后可以在模塊頂部將其定義為靜態(tài)。
static process_event_t my_app_event;
[...]
my_app_event = process_alloc_event();
請注意,不支持取消事件的方法。