嵌入式OS入門筆記——RTX案例分析之進(jìn)程
嵌入式OS入門筆記-以RTX為案例:
1.理論
? ? 進(jìn)程,英文稱呼很多Process, Task 等等,一般通用操作系統(tǒng)稱Process的比較多,各種稱呼涵義稍微有不一樣。一般而言,進(jìn)程是對(duì)一個(gè)運(yùn)行單元的抽象,主要包括內(nèi)存(code,data,heap和stack),CPU狀態(tài)(PC,SP和寄存器值等)與其他OS管理相關(guān)的內(nèi)容。進(jìn)程是一個(gè)運(yùn)行中的程序。在RTX中,一個(gè)task就是一個(gè)進(jìn)程。
一般我們有一個(gè)進(jìn)程控制塊(Process control block,PCB),用于記錄進(jìn)程的相關(guān)信息。在RTX上,這個(gè)控制塊叫做task control block(TCB),是一個(gè)結(jié)構(gòu)體,其中的成員記錄了關(guān)于該task的信息,其定義在rt_TypeDef.h中:
typedef?struct?OS_TCB?{?? ??/*?General?part:?identical?for?all?implementations.????????????????????????*/?? ??U8?????cb_type;?????????????????/*?Control?Block?Type??????????????????????*/?? ??U8?????state;???????????????????/*?Task?state??????????????????????????????*/?? ??U8?????prio;????????????????????/*?Execution?priority??????????????????????*/?? ??U8?????task_id;?????????????????/*?Task?ID?value?for?optimized?TCB?access??*/?? ??struct?OS_TCB?*p_lnk;???????????/*?Link?pointer?for?ready/sem.?wait?list???*/?? ??struct?OS_TCB?*p_rlnk;??????????/*?Link?pointer?for?sem./mbx?lst?backwards?*/?? ??struct?OS_TCB?*p_dlnk;??????????/*?Link?pointer?for?delay?list?????????????*/?? ??struct?OS_TCB?*p_blnk;??????????/*?Link?pointer?for?delay?list?backwards???*/?? ??U16????delta_time;??????????????/*?Time?until?time?out?????????????????????*/?? ??U16????interval_time;???????????/*?Time?interval?for?periodic?waits????????*/?? ??U16????events;??????????????????/*?Event?flags?????????????????????????????*/?? ??U16????waits;???????????????????/*?Wait?flags??????????????????????????????*/?? ??void???**msg;???????????????????/*?Direct?message?passing?when?task?waits??*/?? ??struct?OS_MUCB?*p_mlnk;?????????/*?Link?pointer?for?mutex?owner?list???????*/?? ??U8?????prio_base;???????????????/*?Base?priority???????????????????????????*/?? ??U8?????ret_val;?????????????????/*?Return?value?upon?completion?of?a?wait??*/?? ?? ??/*?Hardware?dependant?part:?specific?for?CM?processor??????????????????????*/?? ??U8?????ret_upd;?????????????????/*?Updated?return?value????????????????????*/?? ??U16????priv_stack;??????????????/*?Private?stack?size,?0=?system?assigned??*/?? ??U32????tsk_stack;???????????????/*?Current?task?Stack?pointer?(R13)????????*/?? ??U32????*stack;??????????????????/*?Pointer?to?Task?Stack?memory?block??????*/?? ?? ??/*?Task?entry?point?used?for?uVision?debugger??????????????????????????????*/?? ??FUNCP??ptask;???????????????????/*?Task?entry?address??????????????????????*/?? }?*P_TCB;
一個(gè)進(jìn)程會(huì)有它自己的周期,會(huì)處在不同的進(jìn)程狀態(tài)(state,見上面的state成員),不同的狀態(tài)有不同的意味,不同的狀態(tài)間可以相互轉(zhuǎn)換。
在RTX中,task的狀態(tài)是在rt_Task.h中定義的,一共有10種:
/*?Values?for?'state'???*/?? #define?INACTIVE????????0?? #define?READY???????????1?? #define?RUNNING?????????2?? #define?WAIT_DLY????????3?? #define?WAIT_ITV????????4?? #define?WAIT_OR?????????5?? #define?WAIT_AND????????6?? #define?WAIT_SEM????????7?? #define?WAIT_MBX????????8?? #define?WAIT_MUT????????9
簡(jiǎn)單說來,可以分為4大類,inactive(進(jìn)程被清理),ready(就緒),running(執(zhí)行)和waiting(等待)。狀態(tài)3至9都可以歸為等待狀態(tài),區(qū)別在于他們等待的東西不同,從等待狀態(tài)觸發(fā)到就緒狀態(tài)的條件不同。
進(jìn)程的創(chuàng)建和消滅都是主要都牽涉到內(nèi)存分配,排程器的安排,TCB的處理等等,需要具體的OS具體的分析,我們這里貼一下RTX進(jìn)程創(chuàng)建的源代碼:
OS_TID?rt_tsk_create?(FUNCP?task,?U32?prio_stksz,?void?*stk,?void?*argv)?{?? ??/*?Start?a?new?task?declared?with?"task".?*/?? ??P_TCB?task_context;?? ??U32?i;?? ?? ??/*?Priority?0?is?reserved?for?idle?task!?*/?? ??if?((prio_stksz?&?0xFF)?==?0)?{?? ????prio_stksz?+=?1;?? ??}?? ??task_context?=?rt_alloc_box?(mp_tcb);?? ??if?(task_context?==?NULL)?{?? ????return?(0);?? ??}?? ??/*?If?"size?!=?0"?use?a?private?user?provided?stack.?*/?? ??task_context->stack??????=?stk;?? ??task_context->priv_stack?=?prio_stksz?>>?8;?? ??/*?Pass?parameter?'argv'?to?'rt_init_context'?*/?? ??task_context->msg?=?argv;?? ??/*?For?'size?==?0'?system?allocates?the?user?stack?from?the?memory?pool.?*/?? ??rt_init_context?(task_context,?prio_stksz?&?0xFF,?task);?? ?? ??/*?Find?a?free?entry?in?'os_active_TCB'?table.?*/?? ??i?=?rt_get_TID?();?? ??os_active_TCB[i-1]?=?task_context;?? ??task_context->task_id?=?i;?? ??DBG_TASK_NOTIFY(task_context,?__TRUE);?? ??rt_dispatch?(task_context);?? ??os_tsk.run->ret_val?=?i;?? ??return?((OS_TID)i);?? }
基本就是填TCB,分配內(nèi)存空間,確定優(yōu)先級(jí)和排程相關(guān)設(shè)置,這里就不深入分析。消滅進(jìn)程的源代碼也是類似的。
2.進(jìn)程相關(guān)的基本操作
進(jìn)程在RTX里的基本形式是:
__task?void?task(void){???? ????for(;;){???? ????????//...?????? ????????}???? }
進(jìn)程相關(guān)操作就是RTX提供的圍繞這樣一個(gè)task的一些基本操作,例如創(chuàng)建,消滅等等。
從應(yīng)用角度來說,了解以下進(jìn)程基本操作就足夠了:
最主要的是這個(gè):
os_tsk_create(task_name,priority);
把函數(shù)名填入,和進(jìn)程的優(yōu)先度,優(yōu)先度后面的筆記會(huì)介紹。
如果留心看源代碼,其實(shí)源代碼的create操作要求一共4個(gè)參數(shù)(FUNCP task, U32 prio_stksz, void *stk, void *argv)。我們最基本的這個(gè)創(chuàng)建函數(shù)并沒有接受后兩個(gè)參數(shù)。如果實(shí)在有需要,有以下另外三個(gè)相關(guān)的操作:
os_tsk_create_ex(task_name,priority,para);
這個(gè)是用于傳遞一個(gè)初始參數(shù)para給相關(guān)進(jìn)程的。例如你有一個(gè)LED_On的進(jìn)程,而你有4個(gè)LED,你只有在創(chuàng)建進(jìn)程時(shí)才能決定,你點(diǎn)亮的是哪個(gè)LED,那么就可以用這個(gè)操作,通過傳遞參數(shù)來決定具體要亮哪個(gè)LED。
os_tsk_create_user(task_name,priority,&stack,sizeof(stack));
這個(gè)是用來給進(jìn)程創(chuàng)建自定義stack的。需要傳遞stack的地址和大小。
os_tsk_create_user_ex(task_name,priority,&stack,sizeof(stack),para);
這個(gè)明顯就是上面兩個(gè)的結(jié)合。
以上這些創(chuàng)建操作,返回類型都是OS_TID,進(jìn)程ID,實(shí)際值從0到255。 所以可以先聲明一個(gè)該類型的值,然后創(chuàng)建進(jìn)程時(shí)讓其返回該值。
2.消滅
os_tsk_delete(taskID);
填入你要消滅的進(jìn)程的進(jìn)程ID,TID。
如果要消滅進(jìn)程本身,用:
os_tsk_delete_self();
注意,RTX的消滅進(jìn)程并不清理互斥鎖或者信號(hào)燈的占有的。所以在消滅一個(gè)進(jìn)程前,確定進(jìn)程釋放了所有資源。內(nèi)存資源會(huì)被這兩個(gè)操作釋放,所以不用擔(dān)心。
3.雜項(xiàng)
如果想要知道當(dāng)前進(jìn)程的ID,使用以下操作:
os_get_TID();
還有一個(gè)非常重要的:
os_sys_init(first_task);
這個(gè)操作初始化整個(gè)RTX,如果不在main中執(zhí)行這一操作,一切都是空談。該操作會(huì)創(chuàng)建第一個(gè)進(jìn)程,也就是first_task。
一般而言,進(jìn)程可以創(chuàng)造別的進(jìn)程,也可以消滅別的進(jìn)程。但進(jìn)程只能夠消滅本身,而不能創(chuàng)造本身。所以就需要有一個(gè)操作去創(chuàng)建第一個(gè)進(jìn)程,然后別的進(jìn)程可由這個(gè)第一個(gè)進(jìn)程去創(chuàng)造。
3.一個(gè)完整的例子
一下是一個(gè)從初始化,到創(chuàng)建第一個(gè)進(jìn)程,到第一個(gè)進(jìn)程創(chuàng)建別的進(jìn)程,最后消滅自己的一個(gè)例子:
OS_TID?taskID1;??? OS_TID?taskID2;??? ?? __task?void?init?(void)?{?? ????//Necessary?Initialization?? ????//...?? ????//Create?a?task?? ????taskID1?=?os_tsk_create(task1,?0);?? ????taskID2?=?os_tsk_create(task2,?0);?? ????????os_tsk_delete_self?();?//?Delete?the?init(self)?task?? }?? ?? int?main(void)?? {?? ????//Necessary?Initialization?? ????//...?? ????????os_sys_init(init);?? ?? }
這個(gè)簡(jiǎn)單的例子足夠應(yīng)付最基本使用RTX的需求了。
關(guān)于RTX的排程,優(yōu)先度,內(nèi)存分配和一些OS原語,在后面的筆記會(huì)記錄。