當(dāng)前位置:首頁 > 嵌入式 > 嵌入式硬件
[導(dǎo)讀]摘要:討論一個利用標(biāo)準(zhǔn)C語言setjmp庫函烽實現(xiàn)查詢式協(xié)作多任務(wù)系統(tǒng),給出完整的內(nèi)核和樣例程序并對源代碼進行說明。該系統(tǒng)具有簡單易用的特點,只需要編寫存取堆棧指針的宏

摘要:討論一個利用標(biāo)準(zhǔn)C語言setjmp庫函烽實現(xiàn)查詢式協(xié)作多任務(wù)系統(tǒng),給出完整的內(nèi)核和樣例程序并對源代碼進行說明。該系統(tǒng)具有簡單易用的特點,只需要編寫存取堆棧指針的宏就可方便地移植到新的平臺上。文章詳述了系統(tǒng)的優(yōu)缺點,討論一些性能擴展的方法。該內(nèi)核適用于中小規(guī)模的嵌入式軟件。 關(guān)鍵詞:協(xié)作式多任務(wù) C語言 setjmp 引言 本文介紹的是利用標(biāo)準(zhǔn)C語言setjmp庫函數(shù)實現(xiàn)的具備此特點的協(xié)作式多任務(wù)系統(tǒng)。從本質(zhì)上講,實時多任務(wù)操作系統(tǒng)應(yīng)該具備按照優(yōu)先級搶占調(diào)度的內(nèi)核。然而,在實際應(yīng)用中,搶中式的多任務(wù)某種程序上帶來了用戶程序設(shè)計時數(shù)據(jù)保護的困難,并且,具備搶占功能的多任務(wù)內(nèi)核設(shè)計時困難也比較多,這會增加操作系統(tǒng)自身的代碼,也使它在小資源單片機系統(tǒng)中應(yīng)用較少;而協(xié)作多任務(wù)系統(tǒng)的調(diào)度只在用戶指定的時機發(fā)生,這會大大簡化內(nèi)核和用戶系統(tǒng)的設(shè)計,尤其本文實現(xiàn)的系統(tǒng)通過條件查詢來放棄CPU,既符合傳統(tǒng)單片機程序設(shè)計的思維,又帶來了多任務(wù)、模塊化、可重入的編程便利。 Setjmp是標(biāo)準(zhǔn)C語言庫函數(shù)的組成部分,它可以實現(xiàn)程序執(zhí)行中的遠程轉(zhuǎn)操作。具體來說,它可以在一個函數(shù)中使用setjmp來初始化一個全局標(biāo)號,然后只要該函數(shù)未曾返回,那么在其它任何地方都可以通過longjmp調(diào)用來跳轉(zhuǎn)到setjmp的下一條語句執(zhí)行。實際上,setjmp函數(shù)將發(fā)生調(diào)用處的局部環(huán)境保存在一個jmp_buf的結(jié)構(gòu)當(dāng)中,只要主調(diào)函數(shù)中對應(yīng)的內(nèi)存未曾釋放(函數(shù)返回時局部內(nèi)存就失效了),那么在調(diào)用longjmp的時候就可以根據(jù)已保存的jmp_buf參數(shù)恢復(fù)到setjmp的地方執(zhí)行。我們的系統(tǒng)中就是分析了setjmp標(biāo)準(zhǔn)庫函數(shù)的特點,以簡單的方式實現(xiàn)了協(xié)作式多任務(wù)。 1 演示程序 為了便于理解,首先給出多任務(wù)演示程序的源代碼。這個程序演示了協(xié)作式多任務(wù)切換、任務(wù)的動態(tài)生成、多任務(wù)共用代碼等功能,一共使用了init_coos 初始化根任務(wù)(也就是C語言main函數(shù))、creat_task創(chuàng)建新任務(wù)和WAITFOR查詢條件這3個基本的系統(tǒng)調(diào)用。由于面向嵌入式系統(tǒng),因而程序不會中止并且運行中也沒有進行任何輸出,需要借助適合的調(diào)試工具來理解多任務(wù)系統(tǒng)的運行。 example.c文件清單: #include #include“co-os.h” void tskfunc1(int argc,void *argv); void tskfunc2(int argc,void *argv); void subfunc(void); volatile int cnt,test; int main(void){ int i; init_coos(400); creat_tsk(tskfunc1,12,NULL,400); creat_tsk(tskfunc2,0,NULL,400); i=0; while(1){ WAITFOR(cnt= =8); while(i++argc); test=0x55; /*使用函數(shù)調(diào)用在子程序中測試WAITFOR*/ subfunc(); while(i++15); cnt=0; } } void subfunc(void){ int i; WAITFOR(cnt<5); for(i=0;i<++)test=0x10*i; } 2 內(nèi)核構(gòu)成 內(nèi)核包括一個供外部用戶程序包含的頭文件(co-os.h)和具體實現(xiàn)的源文件(co-os.c),它們提供了演示程序中用到的3個系統(tǒng)調(diào)用。 內(nèi)核的實現(xiàn)代碼假定了CPU堆棧是向下增長的,并且通過宏來直接操作堆棧指針。以下代碼在Microsoft VC6 for x86、Borland C++ Builder 5.5、SDS CrossCode7.0 for 68K和GCC3.2 for AVR四種平臺中測試過,只需在co-os.h頭文件中定義相應(yīng)的平臺類型即可順利編譯。 (1)co-os.h文件清單 #include /*選擇X86_VC6,X86_BC5,AVR_GCC或M68H_SDS.*/ #define X86_VC6 #define MAX_TSK 10 typedef struct { void (*entry)(int argc,void *argv); jmp_buf env; int argc; void *argv; }TVB; extern TCB tcb[MAX_TSK]; extern int task_num,tskid; void init_coos(int mainstk); int creat_tsk(void(*entry)(int argc,void *argv),int argc,void *argv,int stksize); #define WAITFOR(condition)do{ setjmp(tcb[tskid].env); if(!(condition)){ tskid++; if(tskid>=task_num)tskid=0; longijmp(tcb[tskid].env,1); } }while(0) (2)co-os.c文件清單 #include "co-os.h" #if defined(X86_VC6)||defined(X86_BC5) #define SAVE_SP(p) _asm mov p,esp #define RESTORE_SP(p) _asm mov esp,p #elif defined(AVR_GCC) #include #define SAVE_SP(p) p=(int*)SP #define RESTORE_SP(p) SP=(int)p #elif defined(M68K_SDS) #define SAVE_SP(p) asm("MOVE.L A7,{"#p"}") #define RESTORE_SP(p) asm("MOVE.L {"#p"},A7") #endif TCB tcb[MAX_TSK]; Int task_num=1; Int tskid; Static int stktop,oldsp; Void init_coos(int mainstk){ SAVE_SP(stktop); stktop=stktop+sizeof(void(*)(void))/sizeof(int) -(mainstk+sizeof(int)-1)/sizeof(int); } int creat_tsk(void(*entry)(int argc,void *argv), int argc,void *argv,int stksize){ if(task_num>=MAX_TSK)terurn-1; SAVE_SP(oldsp); RESTORE_SP(stktop); If(!setjmp(tcb[task_num].env)){ RESTORE_SP(oldsp); tcb[task_num].entry=entry; tcb[task_num].argc=argc; tcb[task_num].argv=argv; task_num++; stktop-=(stksize+sizeof(int)-1)/sizeof(int); } else tcb[tskid].entry(tcb[tskid].argc,tcb[tskid].argv); return 0; } 3 代碼說明 任務(wù)代碼通過執(zhí)行setjmp設(shè)置本任務(wù)下次查詢時的返回點,然后在等待條件放棄掉CPU跳轉(zhuǎn)到下一任務(wù)的返回點處執(zhí)行。如此周而復(fù)始,讓各任務(wù)都獲得輪轉(zhuǎn)運行的機會,也要求各任務(wù)都需要主動通過等待條件的方式放棄掉CPU。系統(tǒng)中除了中斷服務(wù)程序之外,所有任務(wù)都是平等的,都應(yīng)該遵循同樣的規(guī)則和其它任務(wù)一起協(xié)作運行?;鞠到y(tǒng)中沒有設(shè)計殺死任務(wù)的調(diào)用,這要求各任務(wù)都應(yīng)當(dāng)設(shè)計成某種形式的無限循環(huán)。 任務(wù)中等待的條件可以是任務(wù)復(fù)雜的表達式或都函數(shù)調(diào)用,也可以是中斷服務(wù)程序設(shè)置的全局變量(注意加volatile定義)。一般在任務(wù)執(zhí)行時會讓下次等待的條件不再滿足,避免某個任務(wù)一直霸占CPU將系統(tǒng)餓死。在嵌入式軟件中還經(jīng)常會遇到任務(wù)定時啟動和超時等待在I/O操作上,在我們的系統(tǒng)中可以維護一個時間計數(shù)器,只需在適當(dāng)?shù)牡胤接涗洉r刻,然后在任務(wù)查詢條件中判斷當(dāng)前計數(shù)器和記錄時刻之間的差值就可以了。 內(nèi)核實現(xiàn)的代碼則相當(dāng)簡法。由于主要的保護和恢復(fù)任務(wù)現(xiàn)場的工作都由C語言標(biāo)準(zhǔn)庫setjmp實現(xiàn)了,我們就只需要操縱一下堆棧指針防止不同的任務(wù)使用了重疊的局部環(huán)境,這個工作在初始化和創(chuàng)建任務(wù)的時候通過預(yù)定義的兩個宏來實現(xiàn)。在init_coos函數(shù)中,記錄了主任務(wù)(main函數(shù))保留 mainstk字節(jié)堆棧后的新棧頂位置(stktop),然后在每次creat_task時都根據(jù)要求為每個任務(wù)保留stksize字節(jié)的堆棧并重新計算下一個stktop。在creat_task函數(shù)中利用了setjmp函數(shù)的返回值(直接返回時為0,longjmp跳轉(zhuǎn)返回時非0),使得一方面 creat_task能正?;氐秸{(diào)用者,又讓下次輪轉(zhuǎn)到新任務(wù)時能夠找到創(chuàng)建時的入口。 co-os.h中定義的WAITFOR使用了一個do{…while(0)實現(xiàn)多語句宏的C語言小技巧,這樣能保證在任何情況下WAITFOR都可以如單條語句一樣在源程序中使用,需要擔(dān)心多了或者少了大括弧破壞if/else匹配之類的問題,并且,所有的編譯器都會優(yōu)化掉這個假循環(huán)。 為了盡量使程序簡單并說明問題,以上代碼中沒有考慮中斷相關(guān)的數(shù)據(jù)保護問題。實際運行的系統(tǒng)中,如果首先寫堆棧指針不能一步完成(如AVR這樣的8位機),那么,在寫操作正在進行的時候絕對不能允許中斷;另外,在任務(wù)中查詢的條件如果和中斷有關(guān),那么也必須考慮數(shù)據(jù)的完整性。 4 性能分析 所有的協(xié)作式多任務(wù)系統(tǒng)中任務(wù)切換時間都和用戶代碼(是否長期占用CPU)、就緒時刻有關(guān),比標(biāo)準(zhǔn)系統(tǒng)略差的是,我們的簡單系統(tǒng)中不支持任務(wù)優(yōu)先級,并且完成一輪查詢調(diào)度的時間還和任務(wù)數(shù)目有關(guān)。這也是為了達到簡單和可移植性目標(biāo)而不得已作出的犧牲。在各任務(wù)間切換查詢條件通過C語言標(biāo)準(zhǔn)庫函數(shù) longjmp實現(xiàn),一般來講longjmp函數(shù)要從內(nèi)存中恢復(fù)大部分CPU寄存器,執(zhí)行它也需要若干條指令的時間。 為了面向嵌入式系統(tǒng)應(yīng)用,任務(wù)控制塊(TCB)采用靜態(tài)數(shù)組來實現(xiàn),這樣要求預(yù)先確定系統(tǒng)的最大任務(wù)數(shù)(co-os.h中的MAX_TSK)。如果需要,也可以通過環(huán)波鏈表來動態(tài)管理任務(wù)控制塊(TCB),這時可以簡單實現(xiàn)任務(wù)的動態(tài)創(chuàng)建和刪除,并且通過指針來訪問TCB也要比通過下標(biāo)(tskid)略快一點。 在某些情況下,如果在中斷返回后需要執(zhí)行某關(guān)鍵任務(wù),可以考慮通過設(shè)置“高級中斷”的方法來實現(xiàn)。具體地講,就是在中斷返回前改變返回地址到某函數(shù)入口(“高級中斷服務(wù)程序”),同時保留原返回地址到堆棧中,這樣在“高級中斷服務(wù)程序”完成后執(zhí)行return就又回到了正常的多任務(wù)查詢流程。使用“高級中斷”時要注意現(xiàn)場保護的銜接,并且這種技巧顯然和CPU和體系結(jié)構(gòu)有關(guān)。 5 結(jié)論 setjmp是標(biāo)準(zhǔn)C語言中用于遠程跳轉(zhuǎn)的庫函數(shù),利用它可方便實現(xiàn)一個簡單易移植的協(xié)作式多任務(wù)系統(tǒng)。該系統(tǒng)功能完備、編程簡單、易于學(xué)習(xí),適合一些中小規(guī)模的嵌入式軟件使用;并且,以此為基礎(chǔ),還可以用一些與平臺相關(guān)的編程技巧提高其實時性和靈活性。

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉