2013-11-04 63 views
0

我写过一个使用SIGALRM和信号处理程序的程序。内核空间中的信号处理

我现在试图添加这个作为内核的测试模块。
我发现我必须替换很多libc提供的函数以及它们的底层系统调用...例如timer_createsys_timer_createtimer_settimesys_timer_settime等等。

但是,我遇到sigaction问题。
编译内核引发以下错误
arch/arm/mach-vexpress/cpufreq_test.c:157:2: error: implicit declaration of function 'sys_sigaction' [-Werror=implicit-function-declaration]

我已经把它贴在下面

int estimate_from_cycles() { 
    timer_t timer; 
    struct itimerspec old; 

    struct sigaction sig_action; 
    struct sigevent sig_event; 
    sigset_t sig_mask; 

    memset(&sig_action, 0, sizeof(struct sigaction)); 
    sig_action.sa_handler = alarm_handler; 
    sigemptyset(&sig_action.sa_mask); 

    VERBOSE("Blocking signal %d\n", SIGALRM); 
    sigemptyset(&sig_mask); 
    sigaddset(&sig_mask, SIGALRM); 

    if(sys_sigaction(SIGALRM, &sig_action, NULL)) { 
      ERROR("Could not assign sigaction\n"); 
      return -1; 
    } 

    if (sigprocmask(SIG_SETMASK, &sig_mask, NULL) == -1) { 
      ERROR("sigprocmask failed\n"); 
      return -1; 
    } 

    memset (&sig_event, 0, sizeof (struct sigevent)); 
    sig_event.sigev_notify = SIGEV_SIGNAL; 
    sig_event.sigev_signo = SIGALRM; 
    sig_event.sigev_value.sival_ptr = &timer; 


    if (sys_timer_create(CLOCK_PROCESS_CPUTIME_ID, &sig_event, &timer)) { 
      ERROR("Could not create timer\n"); 
      return -1; 
    } 

    if (sigprocmask(SIG_UNBLOCK, &sig_mask, NULL) == -1) { 
      ERROR("sigprocmask unblock failed\n"); 
      return -1; 
    } 

    cycles = 0; 
    VERBOSE("Entering main loop\n"); 

    if(sys_timer_settime(timer, 0, &time_period, &old)) { 
      ERROR("Could not set timer\n"); 
      return -1; 
    } 

    while(1) { 
      ADD(CYCLES_REGISTER, 1); 
    } 
    return 0; 
} 

相关的代码块是接受用户空间代码,并单独改变足以运行调用这种方法内核空间中的代码?

+2

不,不是真的。内核模块必须运行的环境与用户级程序运行的环境大不相同,可调用的某些函数的名称只是一个相当大的冰山的一角... – twalberg

+0

什么是在内核空间中执行信号处理/警报的正确方法呢? –

+0

我不这么认为。你能举一个例子说明如何发送信号给内核? –

回答

4

就是这样的一种方法:取用户空间代码和改变调用 单独足以在内核空间运行代码?

当然不是!你在做什么是直接从内核空间调用系统调用的实现,但有而不是保证它们的SYS_function具有与系统调用相同的函数定义。正确的方法是搜索正确的内核例程,以满足您的需求。除非你正在编写驱动程序或内核功能,否则你不需要编写内核代码。系统调用只能从用户空间调用。他们的主要目的是提供一种安全的方式来访问操作系统(如File System,Socket等)提供的低级机制。

关于信号。你有一个TERRIBLE想法尝试使用来自内核空间的信号系统调用来接收信号。一个进程向另一个进程发送一个信号,并且信号用于用户空间,所以在用户空间进程之间。通常,将信号发送到另一个进程时发生的情况是,如果信号未被屏蔽,则接收进程停止并执行信号处理程序。请注意,为了实现这个结果,需要在用户空间和内核空间之间进行两次切换。

但是,内核的内部任务具有完全相同的用户空间结构,但存在一些差异(例如内存映射,父进程等)。当然,你不能从用户进程发送信号给内核线程(想象一下,如果你发送SIGKILL到关键组件,会发生什么)。由于内核线程具有相同的用户空间线程结构,因此它们可以接收信号,但其默认行为是放弃它们,除非有不同的指定。

我建议将代码更改为尝试从内核空间向用户空间发送信号,而不是尝试接收一个。 (你将如何发送一个信号给内核空间?你会指定哪个pid?)。这可能是一个很好的起点:http://people.ee.ethz.ch/~arkeller/linux/kernel_user_space_howto.html#toc6

由于这是系统调用的旧定义,因此您有sys_sigaction问题。正确的定义应该是sys_rt_sigaction。 来自内核源码3。12:

#ifdef CONFIG_OLD_SIGACTION 
asmlinkage long sys_sigaction(int, const struct old_sigaction __user *, 
           struct old_sigaction __user *); 
#endif 

#ifndef CONFIG_ODD_RT_SIGACTION 
asmlinkage long sys_rt_sigaction(int, 
            const struct sigaction __user *, 
            struct sigaction __user *, 
            size_t); 
#endif 

BTW,你应该调用其中任何一个,他们是为了从用户空间调用。

+0

大多数系统调用可能与它们的libc实现非常相似,因为libc只是围绕这些调用。几乎所有我最终使用的系统调用在签名后面都有相同的签名和相同的想法。关于信号,我认为你误解了......我不是试图从*用户空间发送信号给内核* ..我试图运行一个模块作为尝试接收信号的内核的一部分...所有在内核本身..但我看到一个困难,你正确提出..什么'pid'我会指定..不确定.. –

+0

我已经正确地理解你正在尝试做什么,我试图解释它为什么是一个坏主意。如果你想测试信号到内核空间,最好和最简单的方法是将它们发送到用户空间。为此,我指出了那篇文章。 –

1

你正在内核空间工作,所以你应该开始思考,你在内核空间工作,而不是试图将用户空间入侵内核。如果您需要在内核空间中调用sys_*函数家族,99.95%的时间,您已经在做一些非常非常错误的事情。

而不是while (1),让它打破volatile变量上的循环,并启动一个简单的休眠线程,并在完成时更改变量的值。

I.e.

void some_function(volatile int *condition) { 
    sleep(x); 
    *condition = 0; 
} 

volatile int condition = 1; 
start_thread(some_function, &condition); 
while(condition) { 
     ADD(CYCLES_REGISTER, 1); 
} 

但是,你在做什么(我假设你正在试图让CPU在运行周期数)是Linux这样抢占内核本身不可能没有很多黑客的。如果你保持中断,你的循环计数将是不准确的,因为你的内核线程可能随时被切换出来。如果关闭中断,其他线程将不会运行,并且您的代码将无限循环并挂起内核。

您确定无法简单地使用内核中的BogoMIPs值吗?它基本上是你要测量的内容,但内核在启动过程中很早就做到了,并且做得很对。

+0

是的,你是对的。理想情况下,我应该使用BogoMIPS代码,但我已经试过了多次,我从来没有真正感觉到我理解发生了什么。所以我决定写我自己的一段代码,做类似的事情.. 我不愿意使用条件的原因是用我的代码,我完全知道**循环需要多少次循环..我想我可以请仔细阅读指令集,并与条件一致。 –

+0

不,它仍然可能不准确。不要忘记,内核可以上下文切换你的线程。 – tangrs