xenomai内核解析--双核系统调用(三)--如何为xenomai添加一个系统调用

简介: 本文介绍了如何在Xenomai中添加自定义系统调用`get_timer_hits()`,该调用用于获取CPU定时器中断次数。首先,在`syscall.h`中定义127号系统调用,并在`clock.h`和`clock.c`中声明和实现该函数。接着,更新libcobalt库以包含新接口。最后,提供了一个示例应用,演示如何在实时任务中使用此系统调用。编译内核和库后,运行示例程序显示定时器中断次数,体现了Xenomai的tickless特性。

版权声明:本文为本文为博主原创文章,转载请注明出处。如有错误,欢迎指正。
@[toc]

一、添加系统调用

下面给xenomai添加一个系统调用get_timer_hits(),用于获取应用程序运行CPU的定时器中断产生的次数,类似于VxWorks里的tickGet()。需要说明一下VxWorks是采用周期tick的方式来驱动系统运作,tickGet()获取的也就是tick定时器中断的次数,但xenomai使用的tickless,即定时器不是周期产生tick的。所以get_timer_hits()用于获取定时器中断次数,get_timer_hits()没有具体用途,这里主要用来举例怎么为xenomai添加一个实时系统调用。

在前两篇文中说到,xenomai每个系统的系统系统调用号在\cobalt\uapi\syscall.h中:

#define sc_cobalt_bind                0
#define sc_cobalt_thread_create            1
#define sc_cobalt_thread_getpid            2
    ......
#define sc_cobalt_extend            96

在此添加sc_cobalt_get_timer_hits的系统,为了避免与xenomai系统调用冲突(xenomai官方添加的系统调用号从小到大),那我们就从最后一个系统调用添加,即127号系统调用,如下。

#define sc_cobalt_bind                0
#define sc_cobalt_thread_create            1
#define sc_cobalt_thread_getpid            2
    ......
#define sc_cobalt_extend            96
#define sc_cobalt_ftrace_puts                   97
#define sc_cobalt_recvmmsg                      98
#define sc_cobalt_sendmmsg                      99
#define sc_cobalt_clock_adjtime                 100
#define sc_cobalt_thread_setschedprio           101


#define sc_cobalt_get_timer_hits            127
#define __NR_COBALT_SYSCALLS                    128 /* Power of 2 */

先确定一下我们这个函数的API形式,由于是一个非标准的形式,这里表示如下:

int get_timer_hits(unsigned long *u_tick);

参数为保存hits的变量地址;

返回值:成功0;出错 <0;

系统调用的头文件,然后添加一个系统调用的声明,觉得它和clock相关,那就放在kernel\xenomai\posix\clock.h中吧。

#include <linux/ipipe_tickdev.h>

COBALT_SYSCALL_DECL(get_timer_hits,
           (unsigned long __user *u_tick));

然后是该函数的内核实现,放在/kernel\xenomai\posix\clock.c,如下:

COBALT_SYSCALL(get_timer_hits, primary,
           (unsigned long __user *u_tick))
{
    struct xnthread *thread;
    unsigned long tick;
    int cpu;
    int ret = 0;
    unsigned int irq;

    thread = xnthread_current();
    if (thread == NULL)
        return -EPERM;

    /*得到当前任务CPU号*/
    cpu = xnsched_cpu(thread->sched);

    irq = per_cpu(ipipe_percpu.hrtimer_irq, cpu);    
    /*读取该CPU中断计数*/
    tick = __ipipe_cpudata_irq_hits(&xnsched_realtime_domain, cpu,
                                irq);
    if (cobalt_copy_to_user(u_tick, &tick, sizeof(tick)))
        return -EFAULT;

    return ret;
}

需要注意的是该系统调用的权限,这里使用primary,表示只有cobalt上下文(实时线程)才能调用。

修改完成后重新编译内核并安装。

二、Cobalt库添加接口

在前两篇文中说到,xenomai系统调用由libcobalt发起,所以修改应用库来添加该函数接口,添加声明include\cobalt\time.h

COBALT_DECL(int, get_timer_hits(unsigned long tick));

xenomai3.x.x\lib\cobalt\clock.c添加该接口定义:

COBALT_IMPL(int, get_timer_hits, (unsigned long * tick))
{
        int ret;

        ret = -XENOMAI_SYSCALL1(sc_cobalt_get_tick,
                                tick);

        return ret;
}

重新编译并安装xenomai库,详见本博客其他文章。

三、应用使用

由于我们添加get_timer_hits()系统调用时,指定了系统调用的权限为primary,这里创建一个实时任务,使用宏__RT()指定链接到libcobalt库。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sched.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <alchemy/task.h>
#include <alchemy/timer.h>
#include <alchemy/sem.h>
#include <boilerplate/trace.h>
#include <xenomai/init.h>

#define PRIO 50

void test(void *cookie)
{
    unsigned long tick;
    int ret;
    ret  = __RT(get_timer_hits(&tick));
    if (ret){
        fprintf(stderr,
            "%s: failed to get_tick,%s\n",
            __func__,strerror(-ret));
        return ret;
    }    
    fprintf(stdout,"timer_hits:%ld\n",tick);
    /*....*/
    return 0;
}

int main(int argc, char *const *argv)
{
    struct sigaction sa __attribute__((unused));
    int sig, cpu = 0;
    char sem_name[16];
    sigset_t mask;
    RT_TASK task;
    int ret;

    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigaddset(&mask, SIGTERM);
    sigaddset(&mask, SIGHUP);
    sigaddset(&mask, SIGALRM);
    pthread_sigmask(SIG_BLOCK, &mask, NULL);
    setlinebuf(stdout);

    ret = rt_task_spawn(&task, "test_task", 0, PRIO, 
                        T_JOINABLE, test, NULL);
    if (ret){
        fprintf(stderr,
            "%s: failed to create task,%s\n",
            __func__,strerror(-ret));
        return ret;
    }

    __STD(sigwait(&mask, &sig));
    rt_task_join(&task);
    rt_task_delete(&task);

    return 0;
}

编译Makefile:

XENO_CONFIG := /usr/xenomai/bin/xeno-config

PROJPATH = .

CFLAGS := $(shell $(XENO_CONFIG)   --posix --alchemy --cflags)
LDFLAGS := $(shell $(XENO_CONFIG)  --posix --alchemy --ldflags)
INCFLAGS= -I$(PROJPATH)/include/


EXECUTABLE := get-timer-hits

src = $(wildcard ./*.c)
obj = $(patsubst %.c, %.o, $(src))

all: $(EXECUTABLE)

$(EXECUTABLE): $(obj)
        $(CC) -g -o $@ $^  $(INCFLAGS) $(CFLAGS) $(LDFLAGS)

%.o:%.c
        $(CC) -g -o $@ -c $<  $(INCFLAGS) $(CFLAGS) $(LDFLAGS)

.PHONY: clean
clean:
        rm -f $(EXECUTABLE) $(obj)

运行结果:

$./get-timer-hits
timer_hits:3

可以看到,虽然系统已经启动十几分钟了,但一直没有运行xenomai应用,xenomai tick相关中断才产生了3次,这就是tickless,后面会出xenomai调度及时间子系统相关文章,敬请关注。

目录
相关文章
|
21天前
|
存储 物联网 调度
操作系统的心脏:内核深度解析
在数字世界的构建中,操作系统扮演着基石的角色,而其核心—内核,则是这一复杂系统的灵魂。本文将深入探讨操作系统内核的工作原理,揭示它是如何管理硬件资源、运行程序以及提供系统服务的。通过理解内核的结构和功能,我们可以更好地把握计算机系统的运作机制,进而优化和创新我们的技术实践。
|
15天前
|
存储 人工智能 安全
操作系统的心脏——内核深度解析
【10月更文挑战第29天】 本文深入探讨了操作系统的核心组件——内核,包括其定义、功能、架构以及在现代计算中的重要性。通过对比不同操作系统内核的设计哲学和技术实现,揭示了内核如何影响系统性能、稳定性和安全性。此外,文章还讨论了未来内核技术的潜在发展方向,为读者提供了一个全面了解内核工作原理的平台。
|
12天前
|
存储 消息中间件 算法
深入探索操作系统的心脏——内核机制解析
本文旨在揭示操作系统核心——内核的工作原理,通过剖析其关键组件与机制,为读者提供一个清晰的内核结构图景。不同于常规摘要的概述性内容,本文摘要将直接聚焦于内核的核心概念、主要功能以及其在系统管理中扮演的角色,旨在激发读者对操作系统深层次运作原理的兴趣与理解。
|
19天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
53 4
|
20天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
1月前
|
安全 中间件 人机交互
探索操作系统:从内核到用户界面的全面解析
本文旨在深入探讨操作系统的本质、核心组件及其功能。通过分析操作系统的各个层次,包括内核、驱动程序、中间件及用户界面,揭示其背后的技术原理和设计思想。此外,本文还将讨论操作系统在现代计算中的重要性及其未来发展趋势。
|
2月前
|
存储 算法 安全
操作系统的心脏:内核深入解析
本文将带您走进计算机的大脑—操作系统内核,探索它如何管理硬件资源、提供系统服务,并确保多任务高效运行。文章以浅显易懂的语言,逐步揭示内核的神秘面纱,从基础概念到实际应用,让您对操作系统的核心组件有更深的理解。
107 5
|
10天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
35 2
|
1月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
70 0
|
1月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
57 0

推荐镜像

更多
下一篇
无影云桌面