内核空间中的信号处理

Gur*_*sad 0 c linux signals linux-kernel

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

我现在正尝试将其添加为内核中的测试模块。
我发现我不得不用其底层的syscalls..examples timer_createsys_timer_create timer_settimewith sys_timer_settime等替换libc提供的许多功能。

但是,我在遇到问题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;
}
Run Code Online (Sandbox Code Playgroud)

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

Giu*_*Pes 5

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

当然不是!您正在做的是直接从内核空间调用系统调用的实现,但是不能保证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
Run Code Online (Sandbox Code Playgroud)

顺便说一句,你应该叫任何人,他们是为了从用户空间调用。