C 内核空间中的信号处理
我已经编写了一个程序,它使用了C 内核空间中的信号处理,c,linux,linux-kernel,signals,C,Linux,Linux Kernel,Signals,我已经编写了一个程序,它使用了SIGALRM和一个信号处理程序 我现在正试图将其作为测试模块添加到内核中。 我发现我必须将libc提供的许多函数替换为它们的底层系统调用..例如timer\u createwithsys\u timer\u createtimer\u settimewithsys\u timer\u settime等等 但是,我对sigaction 编译内核会引发以下错误 arch/arm/mach-vexpress/cpufreq_-test.c:157:2:错误:函数'sys
SIGALRM
和一个信号处理程序
我现在正试图将其作为测试模块添加到内核中。我发现我必须将libc提供的许多函数替换为它们的底层系统调用..例如
timer\u create
withsys\u timer\u create
timer\u settime
withsys\u timer\u settime
等等
但是,我对sigaction
编译内核会引发以下错误
arch/arm/mach-vexpress/cpufreq_-test.c:157:2:错误:函数'sys_-sigaction'的隐式声明[-Werror=隐式函数声明]
我在下面附上了相关的代码块
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;
}
这样一种获取用户空间代码并单独更改调用的方法是否足以在内核空间中运行代码
这是一种获取用户空间代码并更改调用的方法吗
单独运行足够在内核空间中运行代码吗
当然不是!您要做的是直接从内核空间调用系统调用的实现,但不能保证它们的SYS_函数与系统调用具有相同的函数定义。正确的方法是搜索执行所需操作的正确内核例程。除非您正在编写驱动程序或内核功能,否则您不需要编写内核代码。只能从用户空间调用系统调用。它们的主要目的是提供一种安全的方式来访问操作系统(如文件系统、套接字等)提供的低级机制
关于信号。您有一个非常糟糕的想法,试图使用来自内核空间的信号系统调用来接收信号。一个进程向另一个进程发送一个信号,该信号将在用户空间中使用,因此在用户空间进程之间也是如此。通常,当您向另一个进程发送信号时会发生的情况是,如果该信号未被屏蔽,则停止接收进程并执行信号处理程序。请注意,为了实现此结果,需要在用户空间和内核空间之间进行两次切换
但是,内核有其内部任务,这些任务具有完全相同的用户空间结构,但存在一些差异(例如内存映射、父进程等)。当然,您不能从用户进程向内核线程发送信号(想象一下,如果您向关键组件发送SIGKILL,会发生什么情况)。由于内核线程具有与用户空间线程相同的结构,它们可以接收信号,但其默认行为是丢弃它们,除非另有规定
我建议您更改代码,尝试从内核空间向用户空间发送信号,而不是尝试接收信号。(您将如何向内核空间发送信号?您将指定哪个pid?)。这可能是一个很好的起点:
由于这是系统调用的旧定义,因此您对系统操作有问题。正确的定义应该是sys\u rt\u 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
顺便说一句,你应该不要调用它们中的任何一个,它们应该是从用户空间调用的
这是一种获取用户空间代码并更改调用的方法吗
单独运行足够在内核空间中运行代码吗
当然不是!您要做的是直接从内核空间调用系统调用的实现,但不能保证它们的SYS_函数与系统调用具有相同的函数定义。正确的方法是搜索执行所需操作的正确内核例程。除非您正在编写驱动程序或内核功能,否则您不需要编写内核代码。只能从用户空间调用系统调用。它们的主要目的是提供一种安全的方式来访问操作系统(如文件系统、套接字等)提供的低级机制
关于信号。您有一个非常糟糕的想法,试图使用来自内核空间的信号系统调用来接收信号。一个进程向另一个进程发送一个信号,该信号将在用户空间中使用,因此在用户空间进程之间也是如此。通常,当您向另一个进程发送信号时会发生的情况是,如果该信号未被屏蔽,则停止接收进程并执行信号处理程序。请注意,为了实现此结果,需要在用户空间和内核空间之间进行两次切换
但是,内核有其内部任务,这些任务具有完全相同的用户空间结构,但存在一些差异(例如内存映射、父进程等)。当然,您不能从用户进程向内核线程发送信号(想象一下,如果您向关键组件发送SIGKILL,会发生什么情况)。由于内核线程具有与用户空间线程相同的结构,它们可以接收信号,但其默认行为是丢弃它们,除非另有规定
我建议您更改代码,尝试从内核空间向用户空间发送信号,而不是尝试接收信号。(您将如何向内核空间发送信号?您将指定哪个pid?)。这可能是一个很好的起点:
由于这是系统调用的旧定义,因此您对系统操作有问题。正确的定义应该是sys\u rt\u 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
顺便说一句,你应该不要调用它们中的任何一个,它们应该是从用户空间调用的 您在内核空间中工作,因此您应该开始像在内核空间中工作一样思考,而不是尝试将用户空间黑客移植到内核中。如果您需要在内核空间中调用
sys.*
函数族,99.95%的时候,您已经做了非常非常错误的事情
与其使用while(1)
,不如让它中断volatile变量的循环,并启动一个simp线程