編寫LXRT(RTAI-LXRT)用戶空間程序_第1頁
編寫LXRT(RTAI-LXRT)用戶空間程序_第2頁
編寫LXRT(RTAI-LXRT)用戶空間程序_第3頁
編寫LXRT(RTAI-LXRT)用戶空間程序_第4頁
編寫LXRT(RTAI-LXRT)用戶空間程序_第5頁
已閱讀5頁,還剩1頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、. .編寫LXRTRTAILXRT用戶空間程序Asad Chan 2021-06-28 此文檔僅為那些剛涉獵RTAI Linux的愛好者編寫。在用戶空間下編寫RTAILXRT程序并不是一件困難的事,可以參考"DIAPM RTAI Programming Guide 1.0"和"How to port your C+ GNU/Linux application to RTAI/LXRT"。而這兩個文檔卻沒有一個完整在用戶空間能執(zhí)行的例子,所以往往會造成看了遇到問題不知問題出在哪里。往往有的程序編寫好了,也編譯好了,在控制臺下執(zhí)行卻出現了segmentati

2、on fault字樣。RTAI Linux 調度器請參考RTAI 3.3 User Manual rev0.2 RTAI分別在內核空間和用戶空間提供了兩個對等的任務調度器,一個為rtai_sched,一個為rtai_lxrt,這兩個調度器主要是他們所能調度的可調度任務有所差異,而這兩個調度器都能調度用戶空間和內核空間的任務。rtai_sched能調度Linux下的各種任務,例如process,thread,kthread,而同時它還能調度RTAI 內核空間任務請區(qū)分Linux內核和 RTAI 內核。而rtai_lxrt僅能調度process,thread,kthread,卻不能調度RTAI內核

3、空間任務。 此文檔僅介紹在用戶空間執(zhí)行的實時性任務,而要使用這兩個調度器,需將rtai_hal.ko,rtai_sched.ko,rtai_lxrt.ko三個模塊加載進Linux內核,因為只有將這些模塊加載進內核才能使這兩個調度器運行起來并且能為實時性進程線程提供調度效勞。也即在用戶空間編寫的實時性進程任務需要上述兩個調度器中的一個提供調度效勞才能正常運行?,F在開場吧! 1、建立main.c文件內容如下:#include<stdio.h>#include<stdlib.h>#include<signal.h>#include<rtai_lxrt.h&g

4、t;staticintend=1;voidendHandler(intsig) /信號處理函數end=0; /使靜態(tài)變量為0,這將是主函數的死循環(huán)被breakintmain(void)RT_TASK*task=0; /定義實時任務指針,用于指向被創(chuàng)立的實時性任務intperiod=0; /定義周期變量,用于存儲定時器的周期signal(SIGKILL,endHandler); /連接幾個主要關閉信號的信號處理函數signal(SIGTERM,endHandler); /包括KILL 也即殺死進程信號,TERM關閉信號signal(SIGALRM,endHandler); /這些信號被

5、收到時將會break主程序的循環(huán)if(!(task=rt_task_init_schmod(nam2num("TEST"),0,0,0,SCHED_FIFO,0x0f) /初始化本進程 /為實時性任務printf("Can't initial the taskn");exit(1);mlockall(MCL_CURRENT|MCL_FUTURE); /鎖定本進程內存,防止本進程的內存頁被換出 /導致的實時性被破壞period=start_rt_timer(nano2count(10000); /啟動定時器,設置其定時周期/頻率, /根據定時器是否

6、是oneshotrt_make_hard_real_time(); /使本任務為硬hard實時性任務rt_task_make_periodic(task,rt_get_time()+period*10,period*100); /設置本任務的周期while(end) /如果end為1那么一直執(zhí)行,end0,那么說明接收到了kill/term/alrm三個信號 /中的一個,證明此進程被用戶終止或alrm,那么break此循環(huán),完畢此任務printf("Hello World!n"); /打印字符,注意,此為syscall,會導致任務進入非實時性 /狀態(tài),當此調用完畢時將會重新

7、返回到實時性狀態(tài) /* 在實際應用中如果你的任務是周期性執(zhí)行的,請在此處填寫需要執(zhí)行的周期性過程。 如果你的任務是需要等待某個事件、者信號量或者某個消息的到來,請你建立相應 的事件、信號量、消息,并在此處等待相應的量,相應的量到來時執(zhí)行你需要的 操作。 */rt_task_wait_period(); /使當前任務進入休眠,知道下一次執(zhí)行周期到達被喚醒, /如果execution time >= deadline那么此函數不會使 /任務進入休眠狀態(tài)rt_make_soft_real_time(); /是任務進入軟實時狀態(tài)stop_rt_timer(); /停頓定時器rt_task_del

8、ete(task); /刪除實時性任務,此時控制權將交回Linuxprintf("End of the Application!n");return0; /返回0值 2、建立Makefile文件在Makefile文件內如下所寫:CC = gccCFLAGS = -I/usr/realtime/include -oDFLAGS = -L/usr/realtime/lib -llxrt -lpthreadTARGET = mainSOURCE = main.call:$(CC) $(SOURCE) $(CFLAGS) $(TARGET) $(DFLAGS)clean:rm ma

9、in注釋: CFLAGS宏用于設置編譯選項,可以看到“-I/usr/realtime/include這項,此項用于設置包含rtai_lxrt.h的路徑path,其原因在于此路徑不是Linux的標準頭文件路徑,因此需要手動在編譯選項里指定其路徑,其選項為“-I。“-o選項用于告訴編譯器編譯成可執(zhí)行文件。 DFLAGS宏用于設置連接選項,可以看到“-L/usr/realtime/lib這項,這項用于指定靜態(tài)庫“l(fā)iblxrt.a的路徑,因為此文件不在Linux的標準庫路徑下,需要手動設置其路徑,其選項為“-L。需要手動指定其靜態(tài)庫,可見“-llxrt “-lpthread兩項,其中“-llxrt實

10、為liblxrt.a的縮寫,此實為GNU連接器的使用規(guī)那么,由此可知“-lpthread即為libpthread.a的縮寫。 “$()符號用于對定義的宏進展解析,例如“$(CC)在上面的例子中等價為“gcc,“$(SOURCE)等價為“main.c,其他各項亦按此種形式解析。 3、編譯main.c文件 假設你的main.c、Makefile兩個文件放在絕對路徑/usr/root/workspace/main目錄里,那么在控制臺下進入到此目錄,執(zhí)行以下命令即可: make 注:“為回車的意思。 此時控制臺上會顯示“gcc main.c -I/usr/realtime/include -o mai

11、n -L/usr/realtime/lib -llxrt -lpthread,同時在main目錄下會生成可執(zhí)行文件main。 4、執(zhí)行main 此時,在上面步驟下在控制臺下執(zhí)行以下命令: ./main 此時,會返回一個錯誤,類似于“can't open file liblxrt.so.1 .之類的字樣,其原因是文件liblxrt.so.1并不是在Linux系統(tǒng)設定的靜態(tài)庫路徑下,那么要解決這個問題需要將在第2步中設定路徑“/usr/realtime/lib參加到Linux系統(tǒng)能尋找的靜態(tài)庫的路徑中,此可以通過以下命令設定: ldconfig /usr/realtime/lib 注:ld

12、config即為設置靜態(tài)庫查找路徑命令,其參數即為你需要設置的靜態(tài)庫路徑。 此時,你再執(zhí)行: ./main 你又發(fā)現出問題了,其表現為控制臺返回“segmentation fault,也即為段錯誤。還記得在“RTAI Linux 調度器一節(jié)中曾提到過rtai_hal.ko, rtai_sched.ko, rtai_lxrt.ko三個模塊,根據該小節(jié)中的解釋,需要運行main程序,必須要將這三個模塊加載到內核空間,以使其提供調度任務效勞功能。首先要切換到目錄/usr/realtime/modules下,也即如下命令: cd /usr/realtime/modules 繼續(xù)執(zhí)行以下命令: insm

13、od rtai_hal.ko insmod rtai_sched.ko insmod rtai_lxrt.ko 此時,再重新執(zhí)行以下命令: ./main 此時,控制臺上將會不斷打印“Hello World!。 此時可以通過按下“Ctrl + C來終止程序,而更建議在任務管理器下將此進程殺死,因為程序里實現了信號kill的處理函數。疑惑還是存在 疑惑的存在主要是在main函數里的各個步驟還是難以讓人理解。例如singal函數的調用是一件比較難以明白的處理,里面連接了kill信號,在kill的處理句柄里可以看到它將end賦0,而end為0將會導致main函數里的循環(huán)完畢。而在Linux系統(tǒng)里kil

14、l信號是有默認的處理句柄的,那么我們?yōu)槭裁床挥盟哪J處理句柄呢?它同樣可以使應用程序退出并釋放相應的內存。 1、頭文件 首先,既然在用戶空間編寫RTAI-LXRT可運行程序,那么意味著并且實際上是可以調用Linux的系統(tǒng)調用,標準庫等用戶空間能運行的函數,那么可以包含stdio.h, stdlib.h,這兩個標準頭文件,以使程序能調用標準的庫函數,同時需要包含signal.h頭文件,此頭文件主要是提供signal連接關閉程序句柄,而需要使用RTAILXRT提供的實時性功能,那么毫無疑問需要包含rtai_lxrt.h,請記得rtai_lxrt.h在/usr/realtime/include假設

15、是按照RTAI安裝的默認路徑目錄里,因此需要在編譯選項里指定這一路徑,否那么將不能找到此頭文件。頭文件包含如下所示:#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <rtai_lxrt.h>2、RT_TASK指針 可以看到在程序的開頭聲明了指針task,可以知道它為RT_TASK構造體指針,此構造體指針用于指向需要設置為實時性的任務,需要這個指針的原因是當在程序中將一個process本文檔例子中即為main Process/pthread/kthread向RTAI內

16、核注冊后,task將指向此prcess/pthread/kthread,在隨后的過程中還需要設置task指向的任務的一些屬性,比方該任務的周期等屬性,那么需要使用task作為設置該任務設置的口,并且在程序完畢時還要通過它來從RTAI內核中刪除任務。請詳細閱讀代碼。 3、signal函數 在關閉一個進程時,進程將會收到kill信號,在Linux系統(tǒng)里,在收到kill信號后,默認的kill句柄將會執(zhí)行從Linux內核中刪除任務的操作,這個操作包括關閉收到該信號的進程所翻開的所有文件,釋放該進程所占的內存頁,將該進程的PCB從Linux內核中刪除等操作,最終導致該進程的完畢。 根據上述,可以知道,當

17、本文所寫的main函數的while循環(huán)沒有被break,而收到的kill信號,也即是用戶關閉該進程,而同時沒有連接上述所寫的endHandler句柄,那么將會直接執(zhí)行Linux的默認kill信號句柄,此時將導致程序在while循環(huán)里被完畢,而沒有執(zhí)行到while循環(huán)以下的過程,比方rt_make_soft_real_time(),stop_rt_timer(),rt_task_delete(task),而最終會導致這個已經在RTAI內核注冊過的任務沒有從里面刪除,而同時它已經不存在了。 基于上述原因,需要重新kill,term等信號的處理句柄,而不使程序在while過程里被關閉,使程序最終能退

18、出while,可以調用rt_task_delete(task)過程,使得任務從RTAI內核中刪除的目的。 4、向RTAI內核注冊main進程可以看到main函數里的task=rt_task_init_schmod(nam2num("TEST"),0,0,0,SCHED_FIFO,0x0f)。此過程將main進程注冊進RTAI內核,并成為軟實時任務。 第一個參數為任務號,我們看到nam2num(“TEST),此調用的目的是向RTAI申請一個名為“TEST的任務號,其返回值即為該任務號。 第二個參數為該任務的優(yōu)先級,這里設置為0,即為最高優(yōu)先級。 第三個參數為任務的棧大小,如果

19、給0,將會使用默認的512單位未知。 第四個參數為任務的消息緩沖大小,如果為0,那么默認大小為256單位未知。 第五個參數為Linux任務的優(yōu)先級設置。下文會有解釋 第六個參數為處理器掩碼,類如為0x01時選用處理器0,為0x02時選用處理器1,為0x03時為處理器0和1。 rt_task_init_schmod函數實際可以使用以下過程分解: struct sched_param mysched; mysched.sched_priority = sched_get_priority_max(SCHED_FIFO) 1; sched_setscheduler(0,SCHED_FIFO,&

20、;mysched); rt_task_init(nam2num(“TEST),0,0,0); /注冊和初始化本進程為軟實時任務 sched_param為一個調度參數構造體,里面有進程的任務調度屬性字段,在這里需要修改main進程的調度策略。在Linux系統(tǒng)里有兩種調度策略,一種是SCHED_OTHER,一種是SCHED_FIFO,一般情況下Linux用戶進程使用的是SCHED_OTHER,SCHED_OTHER為Linux的經典調度算法實現的,而SCHED_FIFO為一種軟實時調度機制,它的優(yōu)先級有從199,而SCHED_OTHER代表的是0,數值越大,那么優(yōu)先級越大。在SCHED_FIFO調

21、度策略里每一個優(yōu)先級形成一個FIFO先進先出隊列,高優(yōu)先級的任務FIFO隊列里只要有進程為就緒狀態(tài)將會搶占低優(yōu)先級FIFO隊列里正在運行的進程,只有當高優(yōu)先級FIFO隊列里的進程都被阻塞時,低優(yōu)先級的進程才能得到CPU執(zhí)行下去。而在每一個優(yōu)先級的隊列里,當前進程運行被阻塞,它將會被插入到FIFO隊列尾部,而同時如果沒有更高優(yōu)先級的任務就緒,那么將會調度本優(yōu)先級里FIFO隊列頭的進程。 LXRT要改善Linux進程的軟實時性,那么需要將Linux進程轉換為SCHED_FIFO調度策略。 sched_setscheduler函數即為設置該屬性的接口。第一個參數為選擇運行的CPU,0即為選擇CPU0

22、,第二個參數為調度策略,第三個即為需要設置進程的FIFO進程調度策略下的優(yōu)先級。 rt_task_init即為想RTAI內核注冊main進程使其成為RTAI的任務,其參數同rt_task_init_schmod函數的前面幾個參數一樣的含義。 “TEST任務名項主要是方便于任務之間的通信與同步。 5、鎖定main進程所用的內存 Linux使用了分頁管理內存和虛擬內存的機制,此機制即形成了Linux進程的第二級調度,進程的所占用的內存隨時都會被Linux的內存管理單元將其換出。而在實時性系統(tǒng)中,當內存被換出時,會使得進程無法得到及時調度,因此將會破壞進程的實時性,因此需要將實時進程任務的內存鎖定,使得其內存在任何時候都不會被換出,而不會影響到該進程的實時性能,如下所示: mlockall(MCL_CURRENT | MCL_FUTURE); /MCL_CURRENT 和MCL_FUTURE宏說明 /將鎖定當前分配的內存和以后所申請 /的內存 6、啟動定時器 start_rt_timer(nano2count(1000),此函數啟動RT的定時器,也即實時任務的tick中斷時鐘。nano2count(1000)也即使用1000ns的周期,將其轉換為timer可以承受的數

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論