编写LXRT(RTAI-LXRT)用户空间程序_第1页
编写LXRT(RTAI-LXRT)用户空间程序_第2页
编写LXRT(RTAI-LXRT)用户空间程序_第3页
编写LXRT(RTAI-LXRT)用户空间程序_第4页
编写LXRT(RTAI-LXRT)用户空间程序_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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"。而这两个文档却没有一个完整在用户空间能执行的例子,所以往往会造成看了遇到问题不知问题出在哪里。往往有的程序编写好了,也编译好了,在控制台下执行却出现了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 内核空间任务请区分Linux内核和 RTAI 内核。而rtai_lxrt仅能调度process,thread,kthread,却不能调度RTAI内核

3、空间任务。 此文档仅介绍在用户空间执行的实时性任务,而要使用这两个调度器,需将rtai_hal.ko,rtai_sched.ko,rtai_lxrt.ko三个模块加载进Linux内核,因为只有将这些模块加载进内核才能使这两个调度器运行起来并且能为实时性进程线程提供调度效劳。也即在用户空间编写的实时性进程任务需要上述两个调度器中的一个提供调度效劳才能正常运行。现在开场吧! 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; /使静态变量为0,这将是主函数的死循环被breakintmain(void)RT_TASK*task=0; /定义实时任务指针,用于指向被创立的实时性任务intperiod=0; /定义周期变量,用于存储定时器的周期signal(SIGKILL,endHandler); /连接几个主要关闭信号的信号处理函数signal(SIGTERM,endHandler); /包括KILL 也即杀死进程信号,TERM关闭信号signal(SIGALRM,endHandler); /这些信号被

5、收到时将会break主程序的循环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那么一直执行,end0,那么说明接收到了kill/term/alrm三个信号 /中的一个,证明此进程被用户终止或alrm,那么break此循环,完毕此任务printf("Hello World!n"); /打印字符,注意,此为syscall,会导致任务进入非实时性 /状态,当此调用完毕时将会重新

7、返回到实时性状态 /* 在实际应用中如果你的任务是周期性执行的,请在此处填写需要执行的周期性过程。 如果你的任务是需要等待某个事件、者信号量或者某个消息的到来,请你建立相应 的事件、信号量、消息,并在此处等待相应的量,相应的量到来时执行你需要的 操作。 */rt_task_wait_period(); /使当前任务进入休眠,知道下一次执行周期到达被唤醒, /如果execution time >= deadline那么此函数不会使 /任务进入休眠状态rt_make_soft_real_time(); /是任务进入软实时状态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选项用于告诉编译器编译成可执行文件。 DFLAGS宏用于设置连接选项,可以看到“-L/usr/realtime/lib这项,这项用于指定静态库“liblxrt.a的路径,因为此文件不在Linux的标准库路径下,需要手动设置其路径,其选项为“-L。需要手动指定其静态库,可见“-llxrt “-lpthread两项,其中“-llxrt实

10、为liblxrt.a的缩写,此实为GNU连接器的使用规那么,由此可知“-lpthread即为libpthread.a的缩写。 “$()符号用于对定义的宏进展解析,例如“$(CC)在上面的例子中等价为“gcc,“$(SOURCE)等价为“main.c,其他各项亦按此种形式解析。 3、编译main.c文件 假设你的main.c、Makefile两个文件放在绝对路径/usr/root/workspace/main目录里,那么在控制台下进入到此目录,执行以下命令即可: make 注:“为回车的意思。 此时控制台上会显示“gcc main.c -I/usr/realtime/include -o mai

11、n -L/usr/realtime/lib -llxrt -lpthread,同时在main目录下会生成可执行文件main。 4、执行main 此时,在上面步骤下在控制台下执行以下命令: ./main 此时,会返回一个错误,类似于“can't open file liblxrt.so.1 .之类的字样,其原因是文件liblxrt.so.1并不是在Linux系统设定的静态库路径下,那么要解决这个问题需要将在第2步中设定路径“/usr/realtime/lib参加到Linux系统能寻找的静态库的路径中,此可以通过以下命令设定: ldconfig /usr/realtime/lib 注:ld

12、config即为设置静态库查找路径命令,其参数即为你需要设置的静态库路径。 此时,你再执行: ./main 你又发现出问题了,其表现为控制台返回“segmentation fault,也即为段错误。还记得在“RTAI Linux 调度器一节中曾提到过rtai_hal.ko, rtai_sched.ko, rtai_lxrt.ko三个模块,根据该小节中的解释,需要运行main程序,必须要将这三个模块加载到内核空间,以使其提供调度任务效劳功能。首先要切换到目录/usr/realtime/modules下,也即如下命令: cd /usr/realtime/modules 继续执行以下命令: insm

13、od rtai_hal.ko insmod rtai_sched.ko insmod rtai_lxrt.ko 此时,再重新执行以下命令: ./main 此时,控制台上将会不断打印“Hello World!。 此时可以通过按下“Ctrl + C来终止程序,而更建议在任务管理器下将此进程杀死,因为程序里实现了信号kill的处理函数。疑惑还是存在 疑惑的存在主要是在main函数里的各个步骤还是难以让人理解。例如singal函数的调用是一件比较难以明白的处理,里面连接了kill信号,在kill的处理句柄里可以看到它将end赋0,而end为0将会导致main函数里的循环完毕。而在Linux系统里kil

14、l信号是有默认的处理句柄的,那么我们为什么不用它的默认处理句柄呢?它同样可以使应用程序退出并释放相应的内存。 1、头文件 首先,既然在用户空间编写RTAI-LXRT可运行程序,那么意味着并且实际上是可以调用Linux的系统调用,标准库等用户空间能运行的函数,那么可以包含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系统里,在收到kill信号后,默认的kill句柄将会执行从Linux内核中删除任务的操作,这个操作包括关闭收到该信号的进程所翻开的所有文件,释放该进程所占的内存页,将该进程的PCB从Linux内核中删除等操作,最终导致该进程的完毕。 根据上述,可以知道,当

17、本文所写的main函数的while循环没有被break,而收到的kill信号,也即是用户关闭该进程,而同时没有连接上述所写的endHandler句柄,那么将会直接执行Linux的默认kill信号句柄,此时将导致程序在while循环里被完毕,而没有执行到while循环以下的过程,比方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的任务号,其返回值即为该任务号。 第二个参数为该任务的优先级,这里设置为0,即为最高优先级。 第三个参数为任务的栈大小,如果

19、给0,将会使用默认的512单位未知。 第四个参数为任务的消息缓冲大小,如果为0,那么默认大小为256单位未知。 第五个参数为Linux任务的优先级设置。下文会有解释 第六个参数为处理器掩码,类如为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系统里有两种调度策略,一种是SCHED_OTHER,一种是SCHED_FIFO,一般情况下Linux用户进程使用的是SCHED_OTHER,SCHED_OTHER为Linux的经典调度算法实现的,而SCHED_FIFO为一种软实时调度机制,它的优先级有从199,而SCHED_OTHER代表的是0,数值越大,那么优先级越大。在SCHED_FIFO调

21、度策略里每一个优先级形成一个FIFO先进先出队列,高优先级的任务FIFO队列里只要有进程为就绪状态将会抢占低优先级FIFO队列里正在运行的进程,只有当高优先级FIFO队列里的进程都被阻塞时,低优先级的进程才能得到CPU执行下去。而在每一个优先级的队列里,当前进程运行被阻塞,它将会被插入到FIFO队列尾部,而同时如果没有更高优先级的任务就绪,那么将会调度本优先级里FIFO队列头的进程。 LXRT要改善Linux进程的软实时性,那么需要将Linux进程转换为SCHED_FIFO调度策略。 sched_setscheduler函数即为设置该属性的接口。第一个参数为选择运行的CPU,0即为选择CPU0

22、,第二个参数为调度策略,第三个即为需要设置进程的FIFO进程调度策略下的优先级。 rt_task_init即为想RTAI内核注册main进程使其成为RTAI的任务,其参数同rt_task_init_schmod函数的前面几个参数一样的含义。 “TEST任务名项主要是方便于任务之间的通信与同步。 5、锁定main进程所用的内存 Linux使用了分页管理内存和虚拟内存的机制,此机制即形成了Linux进程的第二级调度,进程的所占用的内存随时都会被Linux的内存管理单元将其换出。而在实时性系统中,当内存被换出时,会使得进程无法得到及时调度,因此将会破坏进程的实时性,因此需要将实时进程任务的内存锁定,使得其内存在任何时候都不会被换出,而不会影响到该进程的实时性能,如下所示: 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. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论