(1.電子科技大學 軟件學院, 成都 610054; 2.北京科銀京成技術有限公司 成都研發中心, 成都 610051)
摘 要:
隨著嵌入式系統在安全關鍵領域的廣泛應用,必須采用現代軟件工程的技術進一步提高其可信性,以保證人們的生命安全。基于模型驅動方法,對AADL(體系結構分析設計語言)模型的框架代碼自動生成技術進行了研究,提出了從AADL模型元素到C和Ada的語法元素的映射規則,由此實現了自動代碼生成器generator并集成在開源工具OSATE中。最后通過一個實例,說明將AADL模型自動轉換為框架代碼后與模塊代碼結合的有效性。
關鍵詞:體系結構分析設計語言; 建模工具; 代碼自動生成技術; 映射規則
中圖分類號:TP311 文獻標志碼: A
文章編號:10013695(2008)12363105
Code automatic generation technology of AADL models
LIU Xueqin1,2, GUI Shenglin1,2, LUO Lei1,2 , LUO Huiqiong1
(1.School of Software, University of Electronic Science Technology of China, Chengdu 610054, China;
2.Coretek System Research Development Center, Chengdu 610051, China)
Abstract:
With the wide application of safety critical embedded systems in various fields,some modern software engineering technology must be developed to increase the security of embedded system to insure the safety of people. Based on the modeldriven architecture method, this paper deeply researched the code automatic generation technology of AADL(architecture analysis and design language) models, then proposed the mapping rules between AADL model element and C/Ada language syntax element. Finally worked out a code automatic generation tool named generator, and integrated it into the open source tool OSATE. At the end, it showed the efficiency of the generator through an example.
Key words:architecture analysis and design language; modeling tool; code automatic generation technology; mapping rules
0 引言
現代嵌入式系統被人們廣泛應用于安全關鍵領域,如航空、汽車、航天電子等。隨著嵌入式系統的功能和復雜度的不斷提高,在更高的抽象層次上進行系統級設計和軟硬件協同設計的方法已經成為研究的熱點。設計安全關鍵的嵌入式系統要求充分捕獲設計需求并快速構造以滿足系統功能屬性和非功能屬性。因此形成一種快速建模和驗證的設計方法非常重要。
傳統軟件項目的開發方法需要高昂的開發和維護費用,并且在系統集成時期存在較高的風險,而模型驅動的開發方法能夠規避這些缺點。在基于模型驅動方法(modeldriven architecture)[1]的系統工程中,系統的開發和維護通過模型來進行,并貫穿整個軟件生命周期。在軟件的設計階段能夠對模型進行分析,可以幫助設計人員發現潛在的錯誤。
體系結構分析設計語言(architecture analysis and design language,AADL)[2]是由SAE體系結構描述語言附屬委員會、嵌入式計算系統委員會、航空電子系統公司共同提出的,用于設計和分析安全關鍵的嵌入式實時系統的軟件和硬件體系結構的文本化和圖形化的語言,是一種應用于嵌入式系統領域的體系結構建模語言。這種語言可以詳細描述嵌入式系統性能相關的屬性,如可靠性、有效性、時間性、響應性、吞吐量、安全性。這些描述使系統的設計者能夠完成對組件和系統的分析,如系統的可調度性、粒度、可信性分析。從這些分析中,設計者可以測評體系結構的平衡和改變。AADL的出現切合了安全關鍵的嵌入式實時系統的特殊需要。
AADL的組件主要[3,4]分為軟件和執行平臺兩大類。其中,軟件組件主要包括數據、線程、進程、子程序等;執行平臺組件主要包括處理器、存儲器、總線、外設等。軟件與執行平臺組件組合在一起可以構成系統模型。對于每種組件,均有組件類型聲明和組件實現聲明。
1 AADL模型元素與編程語言之間的映射規則
通過分析工具可以對搭建的AADL模型的可調度性、可靠性、時間性等屬性在模型級進行分析。如果各項非功能屬性指標均滿足需求,則可將AADL模型通過自動代碼生成器轉換為高級語言框架代碼,最后將框架代碼同實現具體功能的模塊代碼相集成,如圖1所示。在本文中,筆者局限于討論AADL模型的C和Ada代碼的自動生成方法,通過對UML[5,6]、Simulink[7]等模型語言到代碼的轉換方法以及MDA代碼生成技術[8,9]的研究制定了AADL到C語言和Ada語言的元素轉換規則。
11 針對C語言的映射規則
AADL主要模型元素與C語言的映射規則如下:在AADL中的每個數據組件、線程組件、進程組件分別對應生成C語言中的一個.h文件和一個.c文件;當上述組件的組件類型和組件實現規約同時存在時,生成的文件命名為〈組件類型名_組件實現名.h〉和〈組件類型名_組件實現名.c〉;當某個組件只存在組件類型規約時,生成的文件命名為〈組件類型名_imp.h〉和〈組件類型名_imp.c〉。
具體各類型的映射規則如下:
a)AADL中數據組件映射為C語言代碼的規則。AADL中的數據組件描述了源文本中的數據類型,這個數據可以被進程和線程共享。 數據組件規約中聲明的數據子程序對應為〈數據類型名_數據實現名.h〉文件中的函數聲明和〈數據類型名_數據實現名.c〉文件中的函數定義。如果數據組件規約中聲明了子數據,則在〈數據類型名_數據實現名.h〉文件中定義的數據類型結構體中加入該子數據類型的變量作為成員變量。
AADL中的線程組件為并發執行單元建模。線程表示一個連續控制流,這個控制流執行源文本生成的二進制鏡像的指令。線程是AADL調度的單元。線程組件規約中可以聲明端口,用來在線程之間傳送數據和控制信息。線程組件中的端口特征聲明映射為一個單獨的〈線程類型名_port.h〉文件,在此文件中定義了線程組件的端口變量。事件端口對應為一個event類型的變量,event類型是一個指向字符串數組的指針。數據端口對應為指向某個特定數據類型的指針;數據事件端口對應為一個結構體類型。其中有兩個變量,即event類型的變量和指向某個特定數據類型的指針變量。端口的方向通過注釋來標志。
線程組件規約中可以聲明數據子組件作為線程的局部變量。線程組件如果聲明了數據子組件,則在〈線程類型名_線程實現名.h〉文件中的“線程類型名_線程實現名”結構體中加入該子數據類型的變量作為成員變量。
每個線程組件均對應生成一個線程操作函數,命名為線程類型名_線程實現名_op()。線程相關的初始化操作和執行操作均在此函數中進行,此函數在〈線程類型名_線程實現名.h〉中聲明,并在〈線程類型名_線程實現名.c〉中定義。
線程組件規約中可以聲明調用序列,這個調用序列表明了線程調用子程序的順序。線程組件的調用序列聲明映射為一個線程調用函數,命名為線程類型名_線程實現名_調用序列名()。此函數將執行子程序調用的操作,此函數在〈線程類型名_線程實現名.h〉中聲明,并在〈線程類型名_線程實現名.c〉中定義。
線程組件規約中可以聲明線程的模式,用來表示線程的動態操作狀態。線程組件的每個模式聲明映射為一個布爾類型的變量,并定義在〈線程類型名_線程實現名.h〉文件中的“線程類型名_線程實現名”結構體中作為成員變量。
線程組件規約中可以聲明模式切換,用來描述不同模式之間的動態模式切換行為。一個線程可以定義在不同的模式之下。線程組件的每個模式切換聲明映射為一個模式切換函數,此函數在〈線程類型名_線程實現名.h〉中聲明,并在〈線程類型名_線程實現名.c〉中定義。
AADL模型中的線程組件規約如下所示:
thread thread_type
features
port_name1: in data port data_type;
port_name2: in event port;
port_name3: in event data port data_type;
end thread_type;
thread implementation thread_type.imp
subcomponents
data_name: data data_type;
calls
callsequence_name1: {
subprogram_name1: subprogram subprogram_type1;
subprogram_name2: subprogram subprogram_type2;
} in modes (mode1);
callsequence_name1: {
subprogram_name2: subprogram subprogram_type2;
} in modes (mode2);
modes
mode1: initial mode;
mode2: mode;
mode1-[port_name2]->mode2;
end thread_type.imp;
對應生成三個文件,即〈thread_type_port.h〉〈thread_type _imp.h〉和〈thread_type_imp.c〉。
〈thread_type_port.h 〉文件如下所示:
/* Begin Spec of thread_type_port */
#ifndef INCLUDE_thread_type_port
#define INCLUDE_thread_type_port
#include \"aadl.h\"
#include \"data_type_imp.h\"
typedef data_type * thread_type_port_name1;
typedef Event thread_type_port_name1;
typedef struct{
data_type *EDP_Data;
Event EDP_Event;
} thread_type_port_name3;
/* End Spec of thread_type_port */
#endif
〈thread_type_imp.h〉文件如下所示:
/* Begin Spec of thread_type_imp */
#ifndef INCLUDE_thread_type_imp
#define INCLUDE_thread_type_imp
#include \"thread_type_port.h\"
#include \"subprogram_type1_imp.h\"
#include \"subprogram_type2_imp.h\"
typedef struct {
data_type data_name;
aadlboolean mode1;
aadlboolean mode2;
}thread_type_imp;
extern void thread_type_imp_op(void);
void thread_type_callsequence_name1(void);
void thread_type_callsequence_name2(void);
void thread_type_subprogram_name1(void);
void thread_type_subprogram_name2(void);
void modetrans(void);
/* End Spec of thread_type_imp */
#endif
〈thread_type_imp.c〉文件如下所示:
/* Begin Body of thread_type_imp */
#include \" thread_type_imp.h\"
void thread_type_imp_op(void)
{/*線程初始化操作*/
/*判斷若處于mode1*/
thread_type_callsequence_name1( );
/*判斷若處于mode2*/
thread_type_callsequence_name2();}
void thread_type_callsequence_name1(void)
{ thread_type_subprogram_name1( );
thread_type_subprogram_name2( ); }
void thread_type_callsequence_name2(void)
{ thread_type_subprogram_name2( );}
void thread_type_subprogram_name1(void);
{subprogram_type1();}
void thread_type_subprogram_name2(void);
{subprogram_type2();}
void modetrans (void)
{/*……模式切換操作……*/}
/* End Body of thread_type_imp */
c)AADL中進程組件映射為C語言代碼的規則。AADL中的進程組件描述了一個虛擬地址空間,它通過包含源代碼程序的虛擬地址空間來給空間建模。每個進程組件均對應生成一個進程操作函數,命名為進程類型名_進程實現名_op()。此函數負責進程初始化、創建線程、調用線程函數以及進程相關的其他執行操作,此函數在〈進程類型名_進程實現名.h〉中聲明,并在〈進程類型名_進程實現名.c〉中定義。
進程組件規約中聲明的線程子組件表示在該進程下的運行的線程。進程組件的線程子組件映射為線程函數,命名為線程名(),此函數調用與此線程名相關的線程類型組件所生成的線程操作函數,線程名()函數在〈進程類型名_進程實現名.h〉中聲明,并在〈進程類型名_進程實現名.c〉中定義。
進程組件規約聲明中的端口特征表示在進程與線程之間的數據和控制的信息。進程組件的端口聲明映射為一個單獨的〈進程類型名_port.h〉文件。具體映射規則與線程組件端口規約的映射規則類似。
進程組件規約中也可以有數據子組件聲明、模式聲明、模式切換聲明。其映射規則與在線程組件中的映射規則類似。
AADL模型中的進程組件規約如下所示:
process process_type
features
port_name: in data port data_type;
end process_type;
process implementation process_type.imp
subcomponents
data_name: data data_type;
thread_name: thread thread_type;
end process_type.imp
對應為三個文件,即〈process_type_port.h〉〈process_type_imp.h〉文件和〈 process_type_imp.c〉文件。
〈 process_type_port.h〉文件如下所示:
/* Begin Spec of process_type_port */
#ifndef INCLUDE_ process_type_port
#define INCLUDE_ process_type_port
#include \"data_type_imp.h\"
typedef data_type *process_type_port_name;
/* End Spec of process_type_port */
#endif
〈 process_type_imp.h〉文件如下所示:
/* Begin Spec of process_type_imp */
#ifndef INCLUDE_ process_type_imp
#define INCLUDE_ process_type_imp
#include \"process_type_port.h\"
#include \"thread_type_imp.h \"
typedef struct {
data_type data_name;
} process_type_imp;
extern void process_type_op(void);
void thread_name(void);
/* End Spec of process_type_imp */
#endif
〈process_type_imp.c〉文件如下所示:
/* Begin Body of process_type_imp */
#include \"thread_type_imp.h\"
main()
{ process_type_op( );}
void process_type_op(void)
{/*進程初始化*/
/*進程操作,調用線程函數*/}
void thread_name(void)
{ thread_type_imp_op( );}
/* End Body of process_type_imp */
12 針對Ada語言的映射規則
Ada語言的設計和產生是為了構建長周期的、高度可靠的軟件系統,它提供了一系列功能來定義相關的數據類型(type)、對象(object)和操作(operation)的程序包(package)。在Ada語言中內建了對并發運算的支持,即任務機制。Ada語言的使用可大大改善軟件系統的清晰性、有效性、可維護性。Ada語言在安全性敏感領域中占有重要地位,它被廣泛應用于交通運輸、航空電子、軍事領域。鑒于Ada語言的重要作用,使OSATE能夠支持Ada源代碼顯得很有必要。
AADL主要模型元素與Ada語言的映射規則如下:AADL中的數據、線程和進程組件在Ada語言中映射為一個單獨的程序包,使得它們可以方便地被其他組件引用。程序包一般分為兩部分,即聲明和執行。聲明部分聲明子程序、變量等實體,通常被稱為資源;而執行部分則是聲明部分中實體的實現。它們的擴展名分別為ads和adb。
1)AADL中數據組件映射為Ada代碼的規則
數據組件中的子數據聲明映射為〈數據類型名_數據實現名.ads〉文件中的變量定義。
數據組件中的子程序聲明映射為Ada過程或函數,它在〈數據類型名_數據實現名.ads〉文件中聲明,并在〈數據類型名_數據實現名.adb〉文件中定義。
AADL模型中的數據組件規約如下所示:
data data_type1
features
subprogram_name: subprogram subprogram_type;
end data_type1;
data implementation data_type1.imp
subcomponents
subdata_name: data data_type2;
end data_type1.imp;
對應為兩個文件,即〈data_type1_imp.ads〉和〈 data_type1_imp.adb〉。
〈data_type1_imp.ads 〉文件如下所示:
with data_type2_imp; use data_type2_imp;
package data_type1_imp is
subdata_name: data_type2;
procedure data_type1_subprogram_name;
end data_type1_imp;
〈data_type1_imp.adb〉文件如下:
with subprogram_type_imp;use subprogram_type_imp;
package body data_type1_imp is
procedure data_type1_subprogram_name is
begin
--子程序定義
end data_type1_subprogram_name;
end data_type1_imp;
2)AADL中線程組件映射為Ada代碼的規則
每個線程組件對應Ada語言中的一個任務,命名為線程類型名_線程實現名_task。此任務進行線程的初始化和執行操作,此任務在〈線程類型名_線程實現名.ads〉文件中聲明,并在〈線程類型名_線程實現名.adb〉文件中定義。
線程組件的端口聲明映射為〈線程類型名_線程實現名.ads〉文件中的端口變量聲明。對于數據端口,則聲明為特定數據類型的變量;對于事件端口,則聲明為字符串類型的變量;對于事件數據端口則聲明兩個變量,即特定數據類型和字符串類型。
線程組件的數據子組件映射為〈線程類型名_線程實現名.ads〉文件中的變量聲明。
線程組件中的調用序列映射為Ada過程或函數,命名為組件類型名_組件實現名_op。它用來實現線程中的子程序調用。它在〈線程類型名_線程實現名.ads〉文件中聲明,并在〈線程類型名_線程實現名.adb〉文件中定義。
AADL模型中的線程組件規約如下所示:
thread thread_type
features
port_name: in event port;
end thread_type;
thread implementation thread_type.imp
subcomponents
data_name: data data_type;
calls
{
subprogram_name1: subprogram subprogram_type1;
subprogram_name2: subprogram subprogram_type2;
}
end thread_type.imp;
對應為兩個文件,即〈thread_type_imp.ads〉和〈thread_type_imp.adb〉。
〈thread_type_imp.ads〉文件如下所示:
with data_type_imp; use data_type_imp;
package thread_type_imp is
thread_type_port_name: string;
data_name: data_type;
task type thread_type_imp_task is
entry Start ;
end thread_type_imp_task;
end thread_type_imp;
〈thread_type_imp.adb〉文件如下所示:
with subprogram_type1_imp;use subprogram_type1_imp;
with subprogram_type2_imp;use subprogram_type2_imp;
package body thread_type_imp is
task body thread_type_imp _task is
procedurethread_type_imp_op is
begin
subprogram_naem1;
subprogram_naem2;
end thread_type_imp_op;
begin
accept Start
--任務初始化
end Start;
end thread_type_imp_task;
end thread_type_imp;
3)AADL進程組件映射為Ada代碼的規則
AADL中的進程組件映射為Ada中的主過程。在這個主過程中進行進程初始化操作和調用線程任務,此過程在〈進程類型名_進程實現名.ads〉文件中聲明,在〈進程類型名_進程實現名.adb〉文件中定義。
進程中的線程子組件映射為在〈進程類型名_進程實現名.adb〉文件中對線程類型名_線程實現名包的引用,即with線程類型名_線程實現名;use線程類型名_線程實現名;語句。
進程組件的端口、數據子組件聲明的映射規則與線程組件中的類似。
AADL模型中的進程組件規約如下所示:
process process_type
features
port_name: in data port data_type;
end process_type;
process implementation process_type.imp
subcomponents
data_name: data data_type;
thread_name: thread thread_type;
end process_type.imp;
對應生成兩個文件,即〈process_type_imp.ads〉和〈process_type_imp.adb〉。
〈process_type_imp.ads〉文件如下所示:
with data_type_imp; use data_type_imp;
package process_type_imp is
data_name: data_type;
process_type_port_name: data_type;
procedure process_type_imp;
end process_type_imp;
〈process_type_imp.adb〉文件如下所示:
with thread_type_imp; use thread_type_imp;
package body process_type_imp is
procedure process_type_imp is
begin
--進程操作
end process_type_imp;
end process_type_imp;
2 實例
本文限于篇幅不一一詳細列舉轉換規則。筆者根據轉換規則基于OSATE已開發完成代碼自動生成器插件generator,能將編寫好的AADL模型代碼導入到代碼生成器中,然后點擊“生成C代碼”或“生成Ada代碼”按鈕自動生成C語言或Ada語言的框架代碼。在模塊開發人員開發好模塊代碼之后,輸入模塊代碼文件路徑,通過點擊“自動集成”按鈕能將框架代碼與模塊代碼合為一體,然后選擇編譯器進行統一編譯和鏈接,形成可執行環境,極大地方便和簡化了程序的開發。
在改進后的OSATE工具環境下建立了哲學家就餐問題AADL模型,如圖2所示。首先設計一個系統組件,系統中有一個進程組件,進程中包含五個線程組件,分別代表五個哲學家,每個進程中又有一個子程序,在子程序中進行每個哲學家的相關操作。進程組件有一個輸入端口和一個輸出端口,每個線程組件中也有一個輸入端口和一個輸出端口。此外,每只筷子設計為一個數據組件,端口用于傳遞數據。
將哲學家就餐問題的AADL模型導入到generator中,生成框架代碼,并與模塊代碼合并后生成了可執行代碼。運行結果如下:
philosopher 2 eat over.
philosopher 2 put down dinnerware.
philosopher 2 is thinking.
philosopher 1 have getten dinnerware and is eatting.
philosopher 5 is hungrying.
philosopher 2 is hungrying.
philosopher 4 eat over.
philosopher 4 put down dinnerware.
philosopher 4 is thinking.
philosopher 3 have getten dinnerware and is eatting.
philosopher 1 eat over.
philosopher 1 put down dinnerware.
philosopher 1 i s th ink i rig.
philosopher 5 have getten dinnerware and is eatting.
philosopher 4 is hungrying.
philosopher 1 is hungrying.
philosopher 3 eat over.
philosopher 3 put down dinnerware.
philosopher 3 is thinking.
philosopher 2 have getten dinnerware and is eatting.
philosopher 5 eat over.
philosopher 5 put down dinnerware.
philosopher 5 is thinking.
philosopher 4 have getten dinnerware and is eatting.
從執行結果可見,五個哲學家可以交替就餐。Generator將哲學家就餐問題的AADL模型自動生成高級語言代碼并與手工編寫的模塊源代碼集成,形成一個完整的開發環境。
3 結束語
a)筆者的下一步工作是將AADL與北京科銀京城技術有限公司的自主嵌入式操作系統Delta OS相結合。將AADL作為Delta OS之上的運行環境,由此需要將Delta OS的函數API集成到AADL的標準接口之下,這樣能夠增加AADL的硬件無關性,進一步簡化開發。
b)由于功能模塊代碼可由人工編寫而成,為了進一步提高自動化,可以考慮使用面向功能的建模工具如Simulink、UML等來設計功能模塊的模型,并自動生成功能模塊的代碼,再與AADL模型相結合,使得Simulink、UML等面向功能的建模工具能與OSATE聯動起來,進一步提高開發效率。
c)進一步改進OSATE開發工具,使得在設計階段能夠對AADL模型進行與系統非功能屬性方面相關的進一步分析和驗證。
參考文獻:
[1]欒靜,顧君忠.模型驅動的嵌入式系統設計與性能優化[J].計算機工程與應用,2006, 42 (14):114117.
[2] SOKOLSKY O, LEE I, CLARKE D. Schedulability analysis of AADL models[C]//Proc of the 20th International Parallel and Distributed Processing Symposium. 2006.
[3] FEILER P H, de NIZ D, RAISTRICK C, et al. From PIMs to PSMs[C]//Proc of the 12th IEEE International Conference on Engineering Complex Computer Systems. Washington DC: IEEE Computer Society, 2007:365370.
[4] KHOLGADE S, WHITE J, REZA H. Comparing the specification of a near realtime commanding system using statecharts and AADL[C]//Proc of the 4th International Conference on Information Technology. Washington DC: IEEE Computer Society, 2007:355360.
[5] 劉然,陳英,趙小林.基于UML的CASE平臺的代碼自動生成[J].北京理工大學學報,2002, 22 (2):196200.
[6] 田麗從,張莉,周伯生.基于UML的集成化軟件開發環境的研究與實現[J].北京航空航天大學學報,2003, 29 (10):935938.
[7] 黃永安,馬路,劉慧敏.MATLAB 7.0/Simulink 6.0建模仿真開發與高級工程應用[M].北京:清華大學出版社,2005.
[8] 常浩浩,譚征.基于EMF和OCL的MDA 軟件工程方法研究[J].計算機科學,2007, 34 (1):268271.
[9] 陳翔,王學斌,吳泉源.代碼生成技術在MDA中的實現[J].計算機應用研究,2006, 23 (1):147150.