文獻標識碼: A
DOI:10.16157/j.issn.0258-7998.2017.05.014
中文引用格式: 王繼剛,方芳,張華強. 嵌入式操作系統異常處理框架設計與實現[J].電子技術應用,2017,43(5):60-63,66.
英文引用格式: Wang Jigang,Fang Fang,Zhang Huaqiang. Design and implementation of exception handling framework for embe-
dded operating system[J].Application of Electronic Technique,2017,43(5):60-63,66.
0 引言
隨著后PC時代的到來,嵌入式系統已廣泛應用于航空航天、通信、國防等可靠性要求較高的關鍵領域,其復雜度及功能性日益增強。同時,為了高效使用資源,多應用、多任務并行的軟件設計方法被普遍采用,這也不可避免地導致了系統中各類錯誤和異常增多。當異常出現時,如果不能有效處理,很有可能導致應用程序終止,系統崩潰,甚至引發災難性事故,這是人們不愿看到的。然而,傳統面向硬件的異常處理方法無法適應當前嵌入式軟件的變化,必須引入新的機制,保證系統可靠穩定運行。
通過深入分析嵌入式系統對異常處理的需求,參考現有異常處理機制的設計思想,本文提出一種結構化的異常處理框架模型,將一些新的功能引入其中,并基于自主研發的電信級嵌入式操作系統(Carrier Grade Embedded Linux,CGEL)[1],具體實現了該異常處理框架。
1 嵌入式系統異常處理需求
傳統的嵌入式系統異常處理通常采用中斷響應方式,當異常發生時,系統通過異常向量表跳轉到對應的異常處理函數中。隨著嵌入式系統及應用日益復雜,異常的種類也在不斷增多,出現了許多新的需求。本文通過分析嵌入式應用軟件特征,歸納出以下異常處理新的需求。
(1)異常處理框架。為了滿足日益復雜的異常處理場景,提供具有基本異常處理流程及應用開發接口的框架是必要的。該框架既可使異常從發生到處理都具備完整的處理流程,同時,也為應用開發者提供標準的接口,用于自定義異常處理函數。開發者自定義的內容不會改變整個異常處理的流程,但能夠豐富某個階段的異常處理功能。
(2)狀態機。缺少異常處理會降低系統的可靠性,而有缺陷的異常處理也會導致嚴重的系統故障。研究表明[2],有相當一部分錯誤是由不正確的異常處理造成的。狀態機可以有效避免異常處理過程中出現二次異常的問題,通過定義異常處理過程中的各個狀態及狀態間的跳轉條件,規定了各狀態下可能的動作,從而識別異常處理過程中的二次異常,并予以合理地解決。
(3)嵌套異常處理。現代嵌入式應用往往包含多個任務,存在各種嵌套關系。異常處理不僅需要隨著函數調用的深入形成嵌套關系,還要隨著函數調用的返回逐層解開,并回退嵌套的堆棧[3]。當異常發生時,異常處理框架首先對匹配異常處理函數進行搜索,若異常發生在第10層的函數調用,而異常處理函數在第5層,異常處理框架則需要將當前堆棧從第10層逐層回退到第5層,恢復第5層的運行環境進行異常處理。
(4)自定義鉤子函數。傳統的異常處理機制與處理器架構緊密相關,需要通過匯編語言對寄存器操作,這導致軟件的移植性和健壯性很差。現代操作系統提供了鉤子掛接機制,在應用程序中通過鉤子函數接入自定義的異常處理模塊,當異常發生時,鉤子函數會捕捉到內核發出的異常信號,獲得控制權并予以處理。通過鉤子函數能夠避免對寄存器直接操作,獲取異常信息與處理器無關,有效增強嵌入式軟件的移植性和健壯性。
(5)異常拋出機制。傳統的嵌入式軟件異常處理只能響應系統級異常,無法處理程序邏輯異常。而隨著系統復雜性的增加,程序邏輯上錯誤也會對系統造成嚴重的影響。異常拋出[4]是處理程序邏輯異常的有效機制,但目前大多數嵌入式軟件編程語言并沒有提供這種機制,比如C、匯編等。所以異常處理框架需提供異常拋出機制,開發者通過調用相關函數啟動異常拋出功能,對代碼段進行監控,捕捉異常信息并處理。
面對現代嵌入式系統對異常處理機制提出的需求,國內外研究者進行了深入研究并取得了一系列成果。文獻[5]采用有限狀態機,通過對異常上下文信息進行分析,有效提升了異常處理的效率和準確性。但異常處理策略單一,并沒有解決異常處理過程中二次異常和異常擴散等問題。文獻[6]針對嵌入式系統提出了一種異常定位方法,對系統運行時出現的異常進行分類,但并未給出異常處理的策略。文獻[7]提出了一種分層次多策略的異常處理框架,通過檢查點回滾恢復實現多級異常處理。然而,該框架無法判別異常處理方法本身的缺陷。
針對這些新的需求,本文設計了一個基于結構化模型的異常處理框架,可提供多層面的解決方案,涵蓋嵌入式系統異常處理的絕大多數特性,為系統處理各類異常提供有效支持。同時,異常處理框架還具有豐富的鉤子函數掛載接口,開發者可掛載自定義的異常處理模塊,提高程序運行的健壯性。
2 異常處理框架的設計實現
2.1 異常處理框架模型
異常處理框架定義了對異常的捕獲、處理、保存以及跟蹤等一整套流程。從功能上可分為3個模塊:異常控制、異常捕獲及異常處理。其中,異常控制是一個邏輯概念,它負責維護異常處理狀態機,控制著整個處理流程,防止異常處理過程中出現二次異常;異常捕獲則完成系統及應用在運行時異常的捕獲,并通過直接調用或發送信號等手段啟動異常處理模塊;異常處理模塊接收異常信息,對捕獲到的異常提供基本處理方法,也支持用戶自定義的處理手段。
圖1是異常處理框架在CGEL中的具體實現模型,框架基于標準的信號機制實現。其中異常捕獲對系統及應用在運行過程中出現的異常進行捕獲,通過信號調用異常處理模塊予以處理,整個處理流程由異常控制模塊維護。同時,異常處理框架還可以調用狀態監控等系統服務,進行錯誤信息的存儲和告警操作,對異常進行有效定位。
為了避免應用程序對底層硬件直接操作,異常處理框架為應用開發提供了線程級和進程級兩個層次的回調鉤子函數。應用中每個線程都分配一個異常回調函數鏈表,當出現異常時,框架會從該線程異常回調鏈表尾部開始搜索匹配的異常回調函數,鏈表還可支持程序中多層異常嵌套。而進程級異常回調函數對整個應用有效,該函數只能被掛接一次,當所有線程都無法處理異常時,進程級異常回調函數將被調用。開發者可以根據需要在不同層次的回調鉤子上掛接自定義的異常處理程序。
2.2 異常處理狀態機
通過對異常處理所處狀態的統一管理,狀態機能夠幫助異常處理過程有序地進行,支持各種異常處理方法的協調運行。當系統出現異常,狀態機會了解出現異常的狀態,比如是否進入了循環異常、是否為系統異常等,并決定處理異常的動作,指導異常處理框架的工作,用最優的方式解決異常。為了避免異常重復進入,異常處理模塊的狀態機設計了3種狀態:正常態-Normal、異常處理態-ExcProc、異常升級處理態-ExcEscal。各狀態含義及跳轉條件如表1所示。
圖2是異常處理狀態機的遷移圖。在CGEL中,應用狀態在線程的線程本地存儲(Thread Local Storage,TLS)中保存,如果使用pthread庫時,可使用庫提供的TLS功能,否則需要實現一個簡單的TLS功能來保存每個線程的異常處理狀態。
2.3 多級異常處理流程
異常控制狀態機劃分了異常處理過程的不同狀態,如何利用其進行異常處理,則是異常處理流程的工作。異常處理框架提供了一個開放式的多級處理流程,開發者可根據應用情況掛接不同級別的自定義異常處理函數,逐級完成異常處理功能。異常處理模塊程序流程圖如圖3所示。下面介紹使用框架進行多級異常處理的步驟:
步驟1:在需要使用異常處理功能的應用程序中,對異常處理框架進行初始化,掛接主處理函數Usr_ExcMain();
步驟2:函數Usr_TrdExcHdlReg()和Usr_TrdExcHdlUnReg()用來注冊/注銷線程級異常處理鉤子,每個線程維護一個異常處理鉤子函數鏈表,新注冊的線程級異常處理鉤子以節點形式被掛接在鏈表尾;
步驟3:函數Usr_ProcExcHookReg()和Usr_ProcExc-HookUnReg()用來注冊/注銷進程級異常處理鉤子,進程級異常處理鉤子對整個應用進程有效,只能被注冊一次,后面注冊的鉤子將覆蓋前面注冊的;
步驟4:當有線程出現異常,框架將調用Usr_ExcMain()進入主處理流程,從尾部節點開始遍歷該線程的異常處理函數鏈表,通過節點上有效異常過濾函數,判斷節點能否處理該異常。若能則調用該節點上掛接的異常處理鉤子,否則獲取前一節點;
步驟5:如遍歷完線程異常處理鉤子鏈表仍無法修復,異常處理框架將把該異常升級為進程全局異常,獲取進程級異常處理鉤子函數gpf_UsrExcHook()予以處理;
步驟6:若所有的異常處理都失敗,將根據用戶在函數Usr_SetExcExitAct()中設定的動作退出該應用進程。
上述步驟實現細節被封裝在異常處理框架中,用戶只需調用框架所提供的注冊接口掛接自定義的異常處理函數,從而提高了異常處理機制的可移植性和健壯性。
2.4 異常捕獲
異常捕獲模塊主要完成對各類異常的動態捕捉,對于捕獲到的硬件異常,異常處理框架通過傳統的中斷響應方式處理。對于不同的處理器體系,具體的異常編號和種類會有所不同,但主要有:(1)CPU運行異常,如浮點錯誤、除零錯誤、越權保護錯誤、非法指令等;(2)內存管理異常,如數據寫異常、頁面異常、緩沖區異常等。
除了以上這些硬件異常,應用程序還有可能出現邏輯異常。這就需要異常處理框架能夠對代碼段進行監視,并可啟動異常處理流程。拋出異常是一種處理程序邏輯異常的有效機制,其代碼如下:
TRY_BEGIN
//需要保護的代碼
THROW 異常
TRY_END
CATCH_BEGIN
//異常處理代碼
CATCH_END
通過try-catch-throw語句,可以拋出程序中的異常,轉由正常控制流以外的代碼處理。拋出異常對于分離異常和正常代碼,有效增強異常處理功能非常重要。由于C語言缺乏對拋出異常的支持,需要在異常處理框架中添加類似功能。同時,針對C語言特征對拋出異常機制進行了修改,例如:C語言沒有類的概念,框架弱化了異常類型的概念,用異常號(unsigned int)表示異常類型;C語言無關鍵字try、catch、throw的支持,框架借助宏定義予以實現,如表2所示。
除了設計必要的宏外,為了支持在多線程環境實現嵌套的try塊,異常處理框架還定義了一種處理try塊的棧式結構,該棧式結構在線程初始化階段動態申請空間,其指針保存在TLS中,在線程終止時釋放。
3 相關工作
一些主流的嵌入式操作系統也提供了異常處理機制,下面將分析這些操作系統中異常處理機制的特點,并與本文提出的異常處理框架進行對比。
從異常處理機制完備性和功能性角度而言,Windows CE[8]是比較全面的,它具有結構化的異常處理機制,為開發者提供了有力的處理程序錯誤或異常的武器。但針對C語言的異常拋出功能,Windows CE本身不支持,只能結合編譯器提供語言級的支持。另外,其異常處理流程沒有狀態機控制,無法解決在異常處理過程中出現的錯誤。
VxWorks[9]是業界非常著名的嵌入式實時操作系統,它提供的全局異常鉤子回調函數在嵌入式系統中實用性很強,同時,VxWorks還提供了操作系統缺省異常處理,會對異常發生現場作函數調用鏈分析,并將異常信息通過終端輸出。但是,VxWorks的異常處理機制非常簡單,不支持異常處理狀態機以及異常拋出等高級功能,難以滿足現代嵌入式軟件的需求。
由于具有豐富的系統功能、高度定制性及開放源碼特征,Linux在嵌入式領域得到了越來越廣泛的關注。Linux內核[10]沒有提供統一的異常處理框架,異常處理流程被歸類在與CPU體系相關的代碼中,雖然流程基本一致,但隨著CPU體系不同還是有所差異。應用程序需要采用接受異常信號的方式調用異常處理流程,不支持鉤子回調函數,不支持異常處理狀態機,這些都降低了應用程序異常處理的健壯性及可移植性。
本文的異常處理框架結合了主流嵌入式系統異常處理機制的特點,具有完備的動態鏈表模型和狀態機,可以有效處理二次異常,還提供適合于嵌入式系統使用的回調函數,同時對程序可能出現的邏輯異常提供了異常拋出機制,滿足現代嵌入式軟件對異常處理的需求。表3總結了上述各異常處理機制的特點,并與CGEL進行了功能對比。
4 結束語
異常處理已成為提升嵌入式系統健壯性和可用性的關鍵,本文針對現代嵌入式應用軟件新的異常處理需求,提出了一種結構化的異常處理框架模型,框架包含了3個主要功能模塊:異常捕獲、異常處理、異常控制,涵蓋嵌入式系統異常處理絕大多數特性,多級異常處理流程也為系統處理各類異常提供了多層面支持。
目前,異常處理框架已在電信級嵌入式操作系統CGEL上實現,并成功應用于多款電信設備上,大大增強了系統的可靠性。同時,良好的編程接口縮短了應用軟件的開發周期,提高了開發質量。高性能和分布式是未來嵌入式系統的主要特征,動態改變異常處理程序優先級、分布式的異常拋出及處理都是重要的研究方向,有待進一步研究。
參考文獻
[1] 王繼剛,鄭緯民,鐘衛東,等.基于Linux的混合實時操作系統[J].清華大學學報,2009,49(7):1012-1015.
[2] Herbert Hecht.A systems engineering approach to exception handling[C].Proceeding of the Third International Conference on Systems.Washington DC,USA,2008:190-195.
[3] 朱劍鋒,繆萬勝,康介祥.基于堆棧回溯的異常處理[J].計算機工程與設計,2014,35(12):4176-4180.
[4] Mao Chengying,Lu Yansheng.Study on the analysis and testing of exception handling in C++ programs[J].Mini-Micro Systems,2006,27(3):481-485.
[5] Cabdq Filho,Rmc Andrade,Ls Rocha,et al.ConExT-U:A context-aware exception handling mechanism for task-based ubiquitous systems[C].28th International Conference on Advanced Information Networking and Applications Work-shops.BC,Canada,2014:127-132.
[6] SAWADPONG P,ALLEN E B,WILLIAMS B J.Exception handling defects:an empirical study[C].14th International Symposium on High-Assurance Systems Engineering.Washington DC,USA,2012:90-97.
[7] Lu Zhou,Zhang Kailong,Zhou Xingshe.A software Fault-Tol-erant method based on exception handing in RT/E system[C].10th IEEE International Conference on Trust,Security and Privacy in Computing and Communications,Changsha,China,2011:1283-1287.
[8] 羊建林,周安民.Windows異常處理與軟件安全[J].信息安全與通信保密,2011,9(4):58-60.
[9] Wind River.VxWorks kernel programmers guide 6.9[M].California:Wind River Systems,2011.
[10] Robert Love.Linux kernel development[M].USA:Addison-Wesley Professional,2010.
作者信息:
王繼剛1,方 芳2,張華強1
(1.中興通訊股份有限公司 技術規劃部,江蘇 南京210012;
2.信息產業電子第十一設計研究院科技工程股份有限公司 信息中心,四川 成都610021)