嵌入式系统Linux实时化(四)Xenomai应用开发测试
通过在E2000硬件平台运行普通的多线程切换测试与Xenomai技术框架的多线程实时切换测试比较,Linux系统通过Xenomai的双内核技术进行实时化改造,实时性能获得较大的提高,可以满足嵌入式领域一些软实时应用场景的运用
1、Xenomai 原生API
-
任务管理
Xenomai 本身提供的一系列多任务调度机制,主要有以下一些函数:
int rt_task_create (RT_TASK task, const char name, int stksize, int prio, intmode) ; 任务的创建;
int rt_task_start(RT_TASK task, void(entry)(void cookie), void cookie) ; 开始任务调度;
int rt_task_suspend (RT_TASK *task); 挂起任务;
int rt_task_delete (RT_TASK *task) ; 删除任务;
int rt_task_set_periodic (RT_TASK *task, RTIME idate, RTIME period) ;设置任务运行周期;
int rt_task_wait_period (unsigned long *overruns_r) ;挂起任务到下个周期再运行;
int rt_task_set_priority (RT_TASK *task, int prio);设置任务优先级;
-
内存堆服务
int rt_heap_create (RT_HEAP heap, const char name, size_t heapsize, int mode) 创建一个内存堆空间或一个共享内存片段;
int rt_heap_delete (RT_HEAP *heap) 删除一个内存堆空间或一个共享内存片段;
int rt_heap_bind(RT_HEAP heap, const char name, RTIME timeout) 绑定共享内存空间;
int rt_heap_unbind (RT_HEAP *heap) 接触共享内存空间的绑定;
-
信息管道服务
int rt_pipe_create (RT_PIPE pipe, const char name, int minor, size_t poolsize) 创建通讯管道;
int rt_pipe_delete (RT_PIPE *pipe) 删除通讯管道;
ssize_t rt_pipe_receive (RT_PIPE pipe, RT_PIPE_MSG *msgp, RTIME timeout) 从管道接受一条信息;
ssize_t rt_pipe_send (RT_PIPE pipe, RT_PIPE_MSG msg, size_t size, int mode) 向管道发送一条信息;
Xenomai 在实时内核之上还提供了多组API 模拟多种不同的实时操作系统和编程规范,包括POSIX、VxWorks 和RTAI 等。
这使得实时应用系统的开发和移植变得非常方便。
2、创建实时任务基础
-
RT_TASK 结构
当在Xenomai中创建实时任务时,RT_TASK结构将作为引用此任务的描述符。
struct RT_TASK {
uintptr_t handle;
pthread_t thread;
};
-
任务创建rt_task_create
任务创建将会通过调用 rt_task_create函数进行创建:
int rt_task_create (RT_TASK task, const char name, int stack_size, int priority, int mode)
其中:
*task 为指向RT_TASK 类型结构体指针
*name为创建实时任务的名称
stack_size 新任务使用的堆栈大小
priority 设定任务的优先级,[0–99]
“mode” 是一组影响任务的标志,例如:
T_JOINABLE允许另一个任务在新任务结束时等待。此任务终止后,应调用rt_task_join(),以清除任何资源。
T_LOCK导致新任务在进入rt_task_start()指定的用户任务函数之前锁定该程序。需要从新任务调用rt_task_set_mode(),才能解除此锁。
-
rt_task_start()任务启动
任务创建过后则需要启动运行这个程序,任务将进入休眠状态则使用函数 rt_task_start()进行任务启动运行:
int rt_task_start (RT_TASK task, void()(void arg) entry, void arg)
其中:
*task 为指向RT_TASK 类型结构的指针,该结构必须已由对RT_task_create()的调用初始化
“entry” 是此实时任务要执行的任务函数的地址
“arg” 是给任务函数的void类型指针参数
-
RT_TASK_INFO结构
int prio(任务优先级)
struct threadobj_stat stat(任务的状态)
char name [XNOBJECT_NAME_LEN](任务名)
pid_t pid
-
rt_task_inquire()检索有关实时任务的信息
任务状态描述符,此结构用于保存实时任务的各种静态和运行时信息,这些信息由对rt_task_inquire()的调用填充。
rt_task_inquire()检索有关实时任务的信息,返回有关 Alchemy 任务的各种信息。此函数还可用于探测任务是否存在。
int rt_task_inquire ( RT_TASK task, RT_TASK_INFO info )
其中 * task 任务描述符,如果task为空,则返回有关当前任务的信息。注意:如果task为空则必为Alchemy 任务。
info 任务信息将写入的结构的地址
如果任务存在,则返回零。另外,如果信息为非空,则用任务信息填写info结构内容。
3、Makefile文件
Xenomai应用程序在编译时,需要使用到xeno-config工具,可以通过如下编写如下Makefile文件进行调用与编译程序。
XENO_CONFIG := /usr/xenomai/bin/xeno-config
#CFLAGS := $(shell $(XENO_CONFIG) --vxworks --cflags)
#LDFLAGS := $(shell $(XENO_CONFIG) --vxworks --ldflags)
CFLAGS := $(shell $(XENO_CONFIG) --posix --cflags)
LDFLAGS := $(shell $(XENO_CONFIG) --posix --ldflags) -lalchemy -lcopperplate
CC := $(shell $(XENO_CONFIG) --cc)
OBJ := tapp
$(OBJ):thread.c
$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $(OBJ)
4、实时任务创建运行
下面通过rt_task_**系列函数,创建运行一个实时任务,打印出任务的名字。
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <alchemy/task.h>
RT_TASK hello_task;
// 任务执行的功能函数
void helloWorld(void *arg)
{
RT_TASK_INFO curtaskinfo;
printf("Hello World!\n");
// 询问当前的任务
rt_task_inquire(NULL,&curtaskinfo);
// 打印出任务的名字
printf("Task name : %s \n", curtaskinfo.name);
}
int main(int argc, char* argv[])
{
char str[10];
int retval;
printf("start task\n");
sprintf(str,"hello");
rt_task_create(&hello_task, str, 0, 50, 0);
retval = rt_task_start(&hello_task, &helloWorld, 0);
if (retval < 0 )
{
printf("task_start error %d : %s\n",-retval,strerror(-retval));
} else {
printf("task_start success\n");
}
}
修改Makefile

OBJ := xen-test1
$(OBJ):xen-test1.c
编译程序
# make

测试
#sudo ./xen-test1
测试输出如下:

注意:xenomai应用程序需要使用根用户权限进行运行。
5、实时程序测试对比
使用posix多线程实时切换测试程序rt-test:
程序运行测试结果如下:

使用xenomai编程接口重新实现多线程实时切换测试程序:

通过在E2000硬件平台运行普通的多线程切换测试与Xenomai技术框架的多线程实时切换测试比较,Linux系统通过Xenomai的双内核技术进行实时化改造,实时性能获得较大的提高,可以满足嵌入式领域一些软实时应用场景的运用。
E2000开发板:4核(2核1.8G,2核1.5G),4GB内核
线程间隔:1000us,循环次数:10万次
-
普通的多线程切换:最大切换时间:18370us,最大平均时间:72.7us
-
实时的多线程切换:最大切换时间:6us,最大平均时间:1.13us
更多推荐
所有评论(0)