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

 

 

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐