zoukankan      html  css  js  c++  java
  • 【原创】xenomai内核解析--双核系统调用(三)--如何为xenomai添加一个系统调用

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

    一、添加系统调用

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

    在前两篇文中说到,xenomai每个系统的系统系统调用号在cobaltuapisyscall.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相关,那就放在kernelxenomaiposixclock.h中吧。

    #include <linux/ipipe_tickdev.h>
    
    COBALT_SYSCALL_DECL(get_timer_hits,
    		   (unsigned long __user *u_tick));
    

    然后是该函数的内核实现,放在/kernelxenomaiposixclock.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发起,所以修改应用库来添加该函数接口,添加声明includecobalt ime.h

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

    xenomai3.x.xlibcobaltclock.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
    ",
    			__func__,strerror(-ret));
    		return ret;
    	}	
        fprintf(stdout,"timer_hits:%ld
    ",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
    ",
    			__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调度及时间子系统相关文章,敬请关注。

  • 相关阅读:
    ubuntu 安装 redis desktop manager
    ubuntu 升级内核
    Ubuntu 内核升级,导致无法正常启动
    spring mvc 上传文件,但是接收到文件后发现文件变大,且文件打不开(multipartfile)
    angular5 open modal
    POJ 1426 Find the Multiple(二维DP)
    POJ 3093 Margritas
    POJ 3260 The Fewest Coins
    POJ 1837 Balance(二维DP)
    POJ 1337 A Lazy Worker
  • 原文地址:https://www.cnblogs.com/wsg1100/p/13338774.html
Copyright © 2011-2022 走看看