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

@[toc]linux

1、添加系统调用

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

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

#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号系统调用,以下。bash

#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形式,因为是一个非标准的形式,这里表示以下:cookie

int get_timer_hits(unsigned long *u_tick);
复制代码

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

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

系统调用的头文件,而后添加一个系统调用的声明,以为它和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,以下:ui

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上下文(实时线程)才能调用。spa

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

2、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库,详见本博客其余文章。

3、应用使用

因为咱们添加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调度及时间子系统相关文章,敬请关注。