contiki--process詳解

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í)行壤靶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缚俏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌忧换,老刑警劉巖恬惯,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異亚茬,居然都是意外死亡拱绑,警方通過查閱死者的電腦和手機(jī)晾浴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盐类,你說我怎么就攤上這事『娲欤” “怎么了恳邀?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)颂砸。 經(jīng)常有香客問我噪奄,道長(zhǎng),這世上最難降的妖魔是什么人乓? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任勤篮,我火速辦了婚禮,結(jié)果婚禮上色罚,老公的妹妹穿的比我還像新娘碰缔。我一直安慰自己,他們只是感情好戳护,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布金抡。 她就那樣靜靜地躺著,像睡著了一般姑尺。 火紅的嫁衣襯著肌膚如雪竟终。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天切蟋,我揣著相機(jī)與錄音统捶,去河邊找鬼。 笑死柄粹,一個(gè)胖子當(dāng)著我的面吹牛喘鸟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驻右,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼什黑,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了堪夭?” 一聲冷哼從身側(cè)響起愕把,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤拣凹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后恨豁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嚣镜,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年橘蜜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菊匿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡计福,死狀恐怖跌捆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情象颖,我是刑警寧澤佩厚,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站力麸,受9級(jí)特大地震影響可款,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜克蚂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筋讨。 院中可真熱鬧埃叭,春花似錦、人聲如沸悉罕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壁袄。三九已至类早,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗜逻,已是汗流浹背涩僻。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栈顷,地道東北人逆日。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像萄凤,于是被迫代替她去往敵國(guó)和親室抽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容