当前位置:首页 > 嵌入式 > 嵌入式硬件
[导读]摘要:介绍了RTLinux的两个重点特点:硬实时性和完备性,及其在嵌入式系统应用中的一些重要功能,并结合实时处理的具体实例对其编程方法加以说明。关键词:操作系统 实时处

摘要:介绍了RTLinux的两个重点特点:硬实时性和完备性,及其在嵌入式系统应用中的一些重要功能,并结合实时处理的具体实例对其编程方法加以说明。

关键词:操作系统 实时处理 Linux 嵌入式系统

近年来,基于PC的嵌入式系统得到迅速的发展。在各种不同的操作系统中,由于Linux操作系统的廉价、源代码的开放性以及系统的稳定性,使其在基于PC的嵌入式系统中的应用日益广泛。RTLinux(RealTime Linux)[1]是一种基于Linux的实时操作系统,是由FSMLabs公司(Finite State Machine Labs Inc.)推出的与Linux操作系统共存的硬实时操作系统。它能够创建精确运行的符合POSIX.1b标准的实时进程;并且作为一种遵循GPL v2协议的开放软件,可以达GPL v2协议许可范围内自由地、免费地使用、修改和再发生。本文介绍了RTLinux的特点及功能,并结合一个实时处理的具体实例对其编程方法加以说明。

1 RTLinux的特点

在Linux操作系统中,调度算法(其于最大吞吐量准则)、设备驱动、不可中断的系统调用、中断屏蔽以及虚拟内存的使用等因素,都会导致系统在时间上的不可预测性,决定了Linux操作系统不能处理硬实时任务。RTLinux为避免这些问题,在Linux内核与硬件之间增加了一个虚拟层(通常称作虚拟机),构筑了一个小的、时间上可预测的、与Linux内核分开的实时内核,使得在其中运行的实时进程满足硬实时性。并且RTLinux和Linux构成一个完备的整体,能够完成既包括实时部分又包括非实时部分的复杂任务。

1.1 硬实时性

RTLinux将Linux源码中所有的cli、sti、iret指令分别用宏S_CLI、S_STI、 S_IRET替换,引入虚拟层将截取所有的硬件中断,分割Linux系统与硬件中断之间的直接联系。当RTLinux虚拟层接收到与实时处理有关的硬件中断时,立即启动执行相应的实时中断服务程序;而接收到与实时处理无关的中断时,先保存相应的信息,等到RTLinux内核空闲时通过软中断传递给 Linux内核去处理,这样就使得RTLinux内核不受各种软、硬件中断的影响,不会造成时间上的不可预测性。同时又区别于其他实时处理方案,它并未对操作系统的内核作结构性的修改,因此并不会妨碍Linux操作系统的进一步发展和变化。

Linux采用基于最大吞吐量准则的调度策略,并不能确保各个实时进程的及时调度。而RTLinux在缺省情况下采用优先级的调度策略,即系统调度器根据各个实时任务的优先级来确定执行的先后次序。优先级高的先执行,优先级低的后执行,这样就保证了实时进程的迅速调度。同时RTLinux也支持其它的调度策略,如最短时限最先调度(EDP)、确定周期调度(RM)(周期短的实时任务具有高的优先级)。RTLinux将任务调度器本身设计成一个可装载的内核模块,用户可以根据自己的实际需要,编写适合自己的调度算法。

操作系统精确的定时机制,可以提高任务调度器的效率,但增加CPU处理定时中断的时间开销。RTLinux采用一种折衷的方案,不将8354定时器设计成10毫秒产生一次定时中断的固定模式,而是根据最近事件(进程)的时间需要,不断调整定时器的定时间隔。这样既可以提供高精度的时间值,又避免过多增加CPU处理定时中断的时间开销。RTLinux系统同时将各时间间隔相加,保持一个系统全局时间变量,并使用软中断的方式来模拟传统的100Hz定时中断,将其传递给Linux系统使用。

1.2 完备性

过去,实时操作系统仅是一组原始的、简单的可执行程序,它所做的仅仅是向应用程序提供一程序库,但如今,实时应用程序通常要求能够支持TCP/IP、图形显示、文件和数据库系统及其它复杂的服务。为了满足当今实时应用程序的多种需求,通常采用在实时控制内核上增加这些服务或完全修改标准操作系统内核的方法,而RTLinux所采用的是一种新型高效的方式。将一个简单的小型实时内核与Linux内核共存,用简单的小型实时内核处理实时任务,将非实时任务交给Linux内核去处理,而Linux内核本身也作为一个RTLinux实时内核在空闲时运行的进程。这种将实时系统和平均时间优化的标准Linux操作系统协同工作的方式,使得许多实时应用都显示出一种增效。实时内核中的实时任务可以直接访问硬件,不使用虚拟内存,给实时进程提供了很大的灵活性;运行在Linux用户空间中的非实时任务,可以方便地使用系统提供的各种资源(网络、文件系统等),并受到系统的保护,增加了系统的安全性。

2 RTLinux的主要功能

RTLinux提供了一整套对硬实时进程的支持函数集。在此,仅对在嵌入式系统中最重要的三个方面:进程间的通讯、中断和硬件设备的访问以及线程间的同步加以阐述。

2.1 进程间的通信(IPC)

RTLinux要求将应用程序分成实时部分和非实时部分。应用程序的实时部分应该是简单的和轻负荷的,在RTLinux的实时内核中完成;而非实时部分,在Linux的用户空间完成。因此RTLinux提过了多种内核实时进程和 Linux用户空间进程间的通讯机制,最重要的是实时FIFO和共享内存。

实时FIFO是能够被内核实时进程和Linux用户空间进程访问的快进快出队列,是一种单向的通讯机制,可以通过两路实时FIFO构成双向的数据交换方式。在使用实时FIFO前先要对实时FIFO通道初始化:

#include

int rtf_create(unsigned int fifo,int size)

使用后应该注销实时FIFO通道:

int rtf_destroy(unsigned int fifo)

在初始化实时FIFO通道后,RTLinux内核的实时进程和Linux用户空间的进程都可以使用标准的POSIX函数open、read、write和close等对实时FIFO通道进行访问。内核实时进程还可以使用 RTLinux的专有函数rtf_put和rtf_get对实时FIFO通道进行读写。

RTLinux共享内存由mbuff.o模块支持,可以使用下面的函数分配和释放共享内存块:

#include

void *mbuff_alloc(const char *name,int size)

void mbuff_free(const char *name,void *mbuf)

函数mbuff_alloc有两个参数,共享内存名name和共享内存块的大小 size。如果指定的内存共享名并不存在,分配成功时返回共享内存指针,访问计数置为1,分配失败时返回空指针;如果指定的内存共享名已经存在,返回该块共享内存的指针,并将访问计数值直接加1。函数mbuff_free将该块共享内存的访问计数值减1,当计数值为0时,该共享内存被释放。在实时内核模块中使用该函数时,应该将函数mbuff_alloc和mbuff_free分别放在init_module和cleanup_module模块之中。

2.2 中断和访问硬件

硬中断(实时中断)具有最低的延时,在系统内核中只有少数的实时进程使用。函数rtl_request_irq和rtl_free_irq用于安装和卸载指定硬件中断的中断服务程序。

#include

int rtl_request_irq(unsigned int irq,unsigned int (*handler)(unsigned int ,struct pt_regs *))

int rtl_free_irq(unsigned int irq)

中断驱动的线程可以使用唤醒和挂起函数:

int pthread_wakeup_np(pthread_t thread)

int pthread_suspend_np(void)

一个中断驱动的线程可以调用函数 pthread_suspend_np(pthread_self())阻塞自身线程的执行,然后由中断服务函数调用函数 pthread_wakeup_np唤醒该线程的换行,直到此线程再次调用函数pthread_suspend_np(pthread_self())将自身挂起。

软中断是Linux内核常常使用的中断,它能够更安全地调用系统函数。无论如何,对于许多任务来说并不能提供硬实时性能,将会导致一定的延时。

Int rtl_get_soft_irq(void (*handler)(int,void*,struetpt_regs ),const char* devname)分配一个虚中断并安中断;void rtl_free_soft_irq(unsigned int irq)释放分配的虚中断。

RTLinux与Linux一样通过/dev/mem设备访问物理内存,具体由模块rtl_posixio.o提供此项功能。首先应用程序应该打开/dev/mem设备,通过函数mmap对某段物理内存进行映射后,即可使用映射后的地址访问该段物理内存。应用程序只能在Linux进程中(即在应用程序的init_module()模块中)调用mmap,在实时进程中调用mmap将会失败。另一种访问物理内存的方法是通过Linux将会失败。另一种访问物理内存的方法是通过Linux的函数ioremap(2)。RTLinux访问 I/O端口的函数如下(对于x86结构):

输出一个字节到端口:

#include

void outb(unsigned int value,unsigned short port)

void outb_p(unsigned int value,unsigned short port)

输出一个字到端口:

#include

void outw(unsigned int value,unsigned short port)

void outw_p(unsigned int value,unsigned short port)

从端口读一个字节:

#include

char inb(unsigned short port)

char inb_p(unsigned short port)

从端口读一个字:

#include

short inw(unsigned short port)

short inw_p(unsigned short port)

其中带后缀_p的函数使读写端品时有一个小的延时,这在快速的计算机访问慢速的ISA设备时是必需的。

2.3 线程同步

当多个实时线程需要访问共享资源时,如果没有一种同步机制,将破坏共享资源中数据的完整性。RTLinux提供一种简单的加锁方法mutex来控制对共享资源的存取,并支持POSIX的pthread_mutex_family函数组[3]。目前有以下函数可以使用:

pthread_mutexattr_getpshared //得到指定属性线程共享属性值;

pthread_mutexattr_setpshared //设置指定属性线程共享属性值;

pthread_mutexattr_init //初始化mutex的属性;

pthread_mutexattr_destroy //删除mutex的属性;

pthread_mutexattr_settype //设置mutex信号的类型;

pthread_mutexattr_gettype //得到mutex信号的类型;

pthread_mutex_init //按指定的属性初始化mutex;

pthread_mutex_destroy //删除给定的mutex;

pthread_mutex_lock //锁定mutex,如果mutex已被锁定,阻塞当前线程直到解锁;

prhread_untex_trylock //锁定mutex,如果mutex已被锁定,函数立即返回;

pthread_untex_unlock //解锁mutex;

互斥信号类型有PTHREAD_MUTEX_NORMAL(default POSIX mutexes)的PTHREAD_MUTEX_SPINLOCK(spinlocks)

3 RTLinux的编程实例分析

下面结合一个具体的程序parport.c[4],对RTLinux的编程特点加以说明。程序parport.c中的实时线程在并口的2、3脚(并口的数据D0和D1)上周期输出信号1,而对应硬件中断7的实时中断服务程序将在并口的2、3脚输出信号0。连接并口的2脚和10脚(并口的确认信号线,对应于计算机的中断7),则可在并口的2、3脚上产生一个方波信号。 parport.c源程序如下:

#include

#include

#include

#include

#include

#include

pthread_t thread;

unsigned int intr_handler(unsigned int irq,struct pt_regs *regs) { //中断服务函数

outb(0,0x378); //输出字节0到并口数据线

rtl_hard_enable_irq(7); //使能硬件中断7

return 0;

}

void * start_routine (void *arg){ //实时线程

struct sched_param p; //定义实时线程控制参数的数据结构

p.sched_priority = 1; //设置优先级为1

pthread_setschedparam (pthread_self(),SCHED_FIFO,&p); //设置实时线程的控制参数

pthread_make_periodic_np(pthread_self(),gethrtime(),100000);

//启动周期为10ns的实时线程

while (1){

pthread_wait_np(); //实时线程挂起

outb(3,0x378); //实时线程周期执行,输出3到并口数据线

}

return 0;

}

int init_module(void) {//初始化模块

int status;

rtl_irqstate_t f; //保存当前的中断状态标志到变量f,并禁止中断

status=rtl_request_irq(7,irtr_handler); //设置硬件中断7的处理程序

rtl_printf("rtl_request_irq:%d",status); //输出的控制台

outb_p(inb_p(0x37A) |0x10,0x37A); //使能并口中断(硬件上)

rtl_hard_enable_irq(7); //使能中断7(软件上)

rtl_restore_interrupts(f); //按照变量f恢复当前的中断状态标志,并使能中断

return pthread_create (&thread,NULL,start_routine,0);

//创建实时进程thread

}

void cleanup_module(void){ //清除模块

rtl_free_irq(7); //禁止中断7

pthread_delete_np(thread); //删除实时进程thread

}

程序parport.c的make文件如下:

all:parport.o

include rtl.mk

clean:

rm -f *.0

按照如下命令对程序进行编译:

make

运行程序对采用以下命令:

modprobe rtl_sched //调入所需的处理模块

insmod parport.o //调入parport.o模块

连接并口的2脚和10脚,即可通过示波器在并口的3脚上观测到输出的方波信号。

可以看到,RTLinux的实时程序被编写成可加载的Linux内核模块,它能被动态地加入内存,不能执行Linux系统调用,模块的初始化代码对实时任务的结构作初始化,把实时任务时限、周期和释放时间等实时参数传递给RTLinux。

通过对Linux最小的改动,提供一种可靠且廉价的硬实时操作系统 RTLinux。RTLinux开发者可以充分利用Linux提供的各种方便来编写任务的非实时部分,加速自己的任务进度。目前RTLinux的最新版本为3.1,支持Linux2.4内核,程序源代码可以通过网站http://www.rtlinux.org/免费下载。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

Python由荷兰数学和计算机科学研究学会的吉多·范罗苏姆于1990年代初设计,作为一门叫做ABC语言的替代品。 Python提供了高效的高级数据结构,还能简单有效地面向对象编程。

关键字: python 函数 对象编程

测试数据综合分析的绝佳工具,深受工程师和研究员欢迎

关键字: 后处理分析软件 向导 函数

由上图中可以知道进程地址空间中最顶部的段是栈,代码中调用函数、定义局部变量(但不包含static修饰的变量)或声明的类的实例等等都要使用栈空间,当函数执行完(也就是程序执行超过了这个函数的作用范围的时候),操作系统会把该...

关键字: 进程地址 局部变量 函数

本文转载自公众号Java技术栈我们都知道,Java目前最小的系统调度单元只支持线程,官方是不支持协程的,但可以通过第三方框架实现,估计也很少有人会用吧,多线程就能满足需求。好消息来了,不久的将来,Java要开始支持协程了...

关键字: JAVA THREAD VIRTUAL FACTORY

星标/置顶 公众号,硬核文章第一时间送达!链接| https://zhuanlan.zhihu.com/p/274473971题很多,先上题后上答案,便于大家思考问题点:1、C和C的特点与区别?2、C的多态3、虚函数实现...

关键字: 腾讯 函数 进程 AI

程序接口是操作系统为用户提供的两类接口之一,编程人员在程序中通过程序接口来请求操作系统提供服务。面向过程语言最基本的单元是过程和函数。

关键字: 程序接口 过程 函数

星标「嵌入式大杂烩」,一起进步!链接:https://www.cnblogs.com/jozochen/p/8541714.html一、问题复现稳定复现问题才能正确的对问题进行定位、解决以及验证。一般来说,越容易复现的问...

关键字: 嵌入式开发 函数 代码 寄存器

基本上,没有人会将大段的C语言代码全部塞入main()函数。更好的做法是按照复用率高、耦合性低的原则,尽可能的将代码拆分不同的功能模块,并封装成函数。C语言代码的组合千变万化,因此函数的功能可能会比较复杂,不同的输入,常...

关键字: 函数 PEN C语言代码 C语言程序

↓推荐关注↓前言堆内存(HeapMemory)是一个很有意思的领域。你可能和我一样,也困惑于下述问题很久了:如何从内核申请堆内存?谁管理它?内核、库函数,还是应用本身?内存管理效率怎么这么高?!堆内存的管理效率可以进一步...

关键字: 分配器 内存分配 BSP THREAD

Part1一、让自己习惯C条款01:视C为一个语言联邦C并不是一个带有一组守则的一体语言:他是从四个次语言(C、Object-OrientedC、Template、STL) 组成的联邦政府,每个次语言都有自己的规约。记住...

关键字: 函数 ASPECT 编译器
关闭
关闭