c - 内核空间中的信号处理

标签 c linux linux-kernel signals

我编写了一个使用 SIGALRM 和信号处理程序的程序。

我现在正尝试将其添加为内核中的测试模块。
我发现我必须用它们的底层系统调用替换 libc 提供的许多函数..例如 timer_createsys_timer_create timer_settimesys_timer_settime 等等。

但是,我在使用 sigaction 时遇到了问题。
编译内核抛出如下错误
arch/arm/mach-vexpress/cpufreq_test.c:157:2:错误:函数“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;
}

这种采用用户空间代码并单独更改调用的方法是否足以在内核空间中运行代码?

最佳答案

Is such an approach of taking user-space code and changing the calls alone sufficient to run the code in kernel-space?

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

关于信号。您有一个糟糕的想法,试图从内核空间使用信号系统调用来接收信号。一个进程向另一个进程发送信号,而信号是在用户空间中使用的,因此在用户空间进程之间。通常,当您向另一个进程发送信号时发生的情况是,如果信号未被屏蔽,则接收进程将停止并执行信号处理程序。请注意,为了实现此结果,需要在用户空间和内核空间之间进行两次切换。

然而,内核有其内部任务,它们具有完全相同的用户空间结构,但有一些差异(例如内存映射、父进程等)。当然,您不能将信号从用户进程发送到内核线程(想象一下如果您将 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

顺便说一句,你不应该调用它们中的任何一个,它们应该从用户空间调用。

关于c - 内核空间中的信号处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19773666/

相关文章:

c - Linux 中的 "pinned"页如何呈现(或实际上是 "pin")自身

linux-kernel - 如何从 ARM v7 上的 Linux 内核空间刷新 L1 和 L2 缓存中的地址范围?

c - 返回 time_t 错误

linux - CUPS远程打印(http ://) files from command line

linux - 如何通过 vim 终端向上翻页/向下翻页

linux - Docker 容器 crontab 未运行

c++ - 为什么芯片控制语言选择

c - 通过引用传递 GList

java - awk 完整的 C/C++/Java 函数

c - 使用 ioctl 与读取时的 PCIe 总线延迟?