Contiki內(nèi)核結(jié)構(gòu)
嵌入式系統(tǒng)可以看作是一個(gè)運(yùn)行著死循環(huán)主函數(shù)系統(tǒng),Contiki內(nèi)核是基于事件驅(qū)動(dòng)的椎工,系統(tǒng)運(yùn)行可以視為不斷處理事件的過程。Contiki整個(gè)運(yùn)行是通過事件觸發(fā)完成,一個(gè)事件綁定相應(yīng)的進(jìn)程馋劈。當(dāng)事件被觸發(fā),系統(tǒng)把執(zhí)行權(quán)交給事件所綁定的進(jìn)程晾嘶,contiki系統(tǒng)運(yùn)行原理示意圖如下所示:
contiki系統(tǒng)的process
contiki系統(tǒng)中process的結(jié)構(gòu)體如下所示:
struct process {
struct process *next;
#if PROCESS_CONF_NO_PROCESS_NAMES? /* More CODE space savings by turning off 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; ?
unsigned char state, needspoll; ?
};
next:contiki事件以單鏈表形式存儲(chǔ)妓雾,此處指向當(dāng)前事件的下一個(gè)事件地址,contiki定義了一個(gè)process_list的全局變量來標(biāo)記事件的表頭垒迂;
PROCESS_CONF_NO_PROCESS_NAMES:進(jìn)程名稱械姻,為0時(shí)進(jìn)程名稱為空字符串;
pt:記錄當(dāng)前中斷狀態(tài)机断,其實(shí)是一個(gè)void*的指針楷拳,用來保存被中斷的行數(shù);
state:標(biāo)記進(jìn)程的狀態(tài)吏奸,共有三種狀態(tài)欢揖,分別為:PROCESS_STATE_NONE, PROCESS_STATE_RUNNING奋蔚, PROCESS_STATE_CALLED她混;
needspoll:進(jìn)程優(yōu)先級(jí),取值為0 或者1泊碑,為1表示優(yōu)先級(jí)更高坤按,需要將該進(jìn)程插入到其他普通進(jìn)程前;
PT_THREAD:進(jìn)程處理函數(shù)馒过,此處為一個(gè)函數(shù)的指針臭脓;struct pt *用來標(biāo)記進(jìn)程狀態(tài);process_event_t為進(jìn)程中事件的名稱沉桌,原型為unsigned char谢鹊;process_data_t為進(jìn)程傳遞的參數(shù),原型為void *類型留凭;
進(jìn)程調(diào)度
進(jìn)程創(chuàng)建
創(chuàng)建進(jìn)程實(shí)際上是定義一個(gè)進(jìn)程控制塊和進(jìn)程執(zhí)行體的函數(shù)佃扼;PROCESS宏定義即可用來定義一個(gè)進(jìn)程控制塊和聲明一個(gè)進(jìn)程執(zhí)行體函數(shù),name為進(jìn)程控制塊蔼夜,PROCESS_THREAD為進(jìn)程執(zhí)行體函數(shù)兼耀。
#define PROCESS(name, strname) \
PROCESS_THREAD(name, ev, data); \
struct process name = { NULL, strname, \
process_thread_##name }
需要注意的是,PROCESS宏定義只是對(duì)進(jìn)程的執(zhí)行函數(shù)做了聲明,但是并沒有定義瘤运,所以還需要對(duì)PROCESS_THREAD函數(shù)進(jìn)行定義窍霞;
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
printf("Hello World!\n");
PROCESS_END();
}
進(jìn)程創(chuàng)建完成之后,通過process_start函數(shù)將新創(chuàng)建的進(jìn)程加入到進(jìn)程執(zhí)行鏈表里拯坟,process_start的核心代碼如下所示但金;
/* Put on the procs list.*/
p->next = process_list;//將進(jìn)程添加到進(jìn)程鏈表的頭部
process_list = p;//更新進(jìn)程鏈表頭部
p->state = PROCESS_STATE_RUNNING;
PT_INIT(&p->pt);
PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p));
/* Post a synchronous initialization event to the process. */
process_post_synch(p, PROCESS_EVENT_INIT, data);
process_post_synch為進(jìn)程同步函數(shù),內(nèi)部直接調(diào)用call_process函數(shù)郁季,此處將進(jìn)程狀態(tài)置為PROCESS_STATE_RUNNING冷溃,所以第一次將新創(chuàng)建的進(jìn)程加入到進(jìn)程鏈表的時(shí)候,會(huì)執(zhí)行一遍進(jìn)程的thread函數(shù)梦裂,然后通過exit_process函數(shù)將state置為PROCESS_STATE_NONE似枕,exit_process函數(shù)核心代碼如下所示;
if(process_is_running(p)) {
/* Process was running */
p->state = PROCESS_STATE_NONE;
/*
* Post a synchronous event to all processes to inform them that
* this process is about to exit. This will allow services to
* deallocate state associated with this process.
*/
for(q = process_list; q != NULL; q = q->next) {
if(p != q) { //通知其他進(jìn)程當(dāng)前進(jìn)程已經(jīng)退出年柠,回收相關(guān)系統(tǒng)資源
call_process(q, PROCESS_EVENT_EXITED, (process_data_t)p);
}
}
if(p->thread != NULL && p != fromprocess) {
/* Post the exit event to the process that is about to exit. */
process_current = p;
p->thread(&p->pt, PROCESS_EVENT_EXIT, NULL);
}
}
if(p == process_list) { ?//如果當(dāng)前進(jìn)程p為process_list的頭節(jié)點(diǎn)凿歼,則將process_list指向它的next;
process_list = process_list->next;
} else { ?//如果當(dāng)前進(jìn)程p不為process_list的頭節(jié)點(diǎn)冗恨,則將p的上一個(gè)節(jié)點(diǎn)的next指向p的next答憔,即將p節(jié)點(diǎn)從鏈表中去除掉;
for(q = process_list; q != NULL; q = q->next) {
if(q->next == p) {
q->next = p->next;
break;
...
和process_post_synch對(duì)應(yīng)的為process_post派近,該函數(shù)為進(jìn)程異步函數(shù)攀唯,調(diào)用process_post函數(shù)處理事件時(shí),事件并未立即處理渴丸,而是被加入到事件等待處理隊(duì)列nevents里侯嘀,等待下一次process_run的時(shí)候,通過do_event函數(shù)來執(zhí)行谱轨。
進(jìn)程加入到進(jìn)程執(zhí)行鏈表之后戒幔,通過process_run函數(shù)來進(jìn)行進(jìn)程的輪詢調(diào)用,process_run核心代碼如下所示土童;即先執(zhí)行優(yōu)先級(jí)比較高的進(jìn)程诗茎,再執(zhí)行普通進(jìn)程。
if(poll_requested) {
do_poll();
}
/* Process one event from the queue */
do_event();
進(jìn)程優(yōu)先級(jí)
contiki只有兩種類型的進(jìn)程調(diào)度優(yōu)先級(jí)献汗,用process中的needspoll標(biāo)記敢订,默認(rèn)為0,即普通優(yōu)先級(jí)罢吃;可以在創(chuàng)建該進(jìn)程時(shí)設(shè)置其優(yōu)先級(jí)楚午;在進(jìn)程運(yùn)行時(shí)會(huì)優(yōu)先檢查高優(yōu)先級(jí)的進(jìn)程;process_run函數(shù)原型如下:
int
process_run(void)
{
/* Process poll events. */
if(poll_requested) {
do_poll();
}
/* Process one event from the queue */
do_event();
return nevents + poll_requested;
}
poll_requested:全局變量尿招,是否有高優(yōu)先級(jí)事件的標(biāo)志位矾柜,初始化為0阱驾,在函數(shù)process_poll里進(jìn)行置位;
do_poll:函數(shù)原型如下所示怪蔑,遍歷整個(gè)進(jìn)程鏈表里覆,查看進(jìn)程優(yōu)先級(jí),如果進(jìn)程的needspoll標(biāo)志位為1缆瓣,則優(yōu)先執(zhí)行該進(jìn)程喧枷,將其狀態(tài)標(biāo)記為PROCESS_STATE_RUNNING,然后調(diào)用call_process執(zhí)行該進(jìn)程捆愁;
/* Call the processes that needs to be polled. */
for(p = process_list; p != NULL; p = p->next) {
if(p->needspoll) {
p->state = PROCESS_STATE_RUNNING;
p->needspoll = 0;
call_process(p, PROCESS_EVENT_POLL, NULL);
}
call_process函數(shù)核心代碼如下:
if((p->state & PROCESS_STATE_RUNNING) &&
p->thread != NULL) {//如果當(dāng)前進(jìn)程的狀態(tài)是PROCESS_STATE_RUNNING模式割去,并且thread函數(shù)不為NULL
PRINTF("process: calling process '%s' with event %d\n", PROCESS_NAME_STRING(p), ev);
process_current = p;
p->state = PROCESS_STATE_CALLED;//將進(jìn)程的狀態(tài)置為PROCESS_STATE_CALLED
ret = p->thread(&p->pt, ev, data);//運(yùn)行進(jìn)程函數(shù)thread窟却,返回值為ret
if(ret == PT_EXITED ||
ret == PT_ENDED ||
ev == PROCESS_EVENT_EXIT) {
exit_process(p, p);//如果該進(jìn)程被正常執(zhí)行昼丑,則退出該進(jìn)程
} else {
p->state = PROCESS_STATE_RUNNING;
}
以上即為contiki系統(tǒng)process管理的整個(gè)過程,主要分為進(jìn)程創(chuàng)建和進(jìn)程管理兩大部分內(nèi)容夸赫,進(jìn)程創(chuàng)建其實(shí)就是對(duì)進(jìn)程控制塊和進(jìn)程執(zhí)行函數(shù)進(jìn)行注冊(cè)和聲明菩帝;進(jìn)程管理其實(shí)就是對(duì)進(jìn)程各個(gè)狀態(tài)的維護(hù)和處理。
contiki系統(tǒng)的事件
事件也是contiki系統(tǒng)的重要組成部分茬腿,在contiki系統(tǒng)中呼奢,當(dāng)有事件傳遞給進(jìn)程時(shí),就會(huì)新建一個(gè)事件加入事件隊(duì)列切平,并綁定該進(jìn)程握础;一個(gè)進(jìn)程可以對(duì)應(yīng)多個(gè)事件,一個(gè)事件也可以通知給所有的進(jìn)程悴品;事件的數(shù)據(jù)結(jié)構(gòu)如下所示禀综;
struct event_data {
process_event_t ev; ? //unsigned char
process_data_t data; ?//void *
struct process *p;
};
ev:標(biāo)識(shí)所產(chǎn)生事件ID,0x80-0x8F為系統(tǒng)事件ID苔严,其余的為用戶可自定義的事件ID定枷;
data:保存事件產(chǎn)生時(shí)獲得的相關(guān)信息,即事件產(chǎn)生后可以給進(jìn)程傳遞的數(shù)據(jù)届氢;
p:指向監(jiān)聽該事件的進(jìn)程欠窒;
static struct event_data events[PROCESS_CONF_NUMEVENTS];
通過PROCESS_CONF_NUMEVENTS宏定義來確定事件隊(duì)列的大小退子;將需要執(zhí)行的事件加入到events隊(duì)列中岖妄,在系統(tǒng)調(diào)用process_run的時(shí)候,通過調(diào)用do_event函數(shù)來執(zhí)行events隊(duì)列中的事件寂祥;do_event核心代碼如下所示荐虐;
if(nevents > 0) {
/* There are events that we should deliver. */
ev = events[fevent].ev;
data = events[fevent].data;
receiver = events[fevent].p;
/* Since we have seen the new event, we move pointer upwards
and decrease the number of events. */
fevent = (fevent + 1) % PROCESS_CONF_NUMEVENTS;
--nevents;
/* If this is a broadcast event, we deliver it to all events, in
order of their priority. */
if(receiver == PROCESS_BROADCAST) {
for(p = process_list; p != NULL; p = p->next) {
/* If we have been requested to poll a process, we do this in
between processing the broadcast event. */
if(poll_requested) {
do_poll();
}
call_process(p, ev, data);
}
} else {
/* This is not a broadcast event, so we deliver it to the
specified process. */
/* If the event was an INIT event, we should also update the
state of the process. */
if(ev == PROCESS_EVENT_INIT) {
receiver->state = PROCESS_STATE_RUNNING;
}
/* Make sure that the process actually is running. */
call_process(receiver, ev, data);
}
}
如果事件隊(duì)列里有需要執(zhí)行的事件,則通過call_process函數(shù)將該事件的相關(guān)參數(shù)傳遞給相應(yīng)的process進(jìn)行執(zhí)行壤靶。