从内核模块向用户空间发送实时信号失败

时间:2015-10-09 14:46:39

标签: linux linux-kernel embedded-linux

我找到了关于如何从内核模块向用户空间发送实时信号的示例代码here

我在内核模块中实现了它,如下所示:

static int dmtimer_sendSignal(int val, int id, int sig)
{
    struct siginfo info;
    struct task_struct *t;
    int ret;

    ret = 0;

    if ((id > 0) && (sig > 0))
    {
        /* send the signal */
        memset(&info, 0, sizeof(struct siginfo));
        info.si_signo = sig;
        info.si_code = SI_QUEUE;    // this is bit of a trickery: SI_QUEUE is normally used by sigqueue from user space,
                                    // and kernel space should use SI_KERNEL. But if SI_KERNEL is used the real_time data
                                    // is not delivered to the user space signal handler function.
        info.si_int = val;          //real time signals may have 32 bits of data.
        info._sifields._rt._sigval.sival_int = val;
        info.si_errno = 0;


        rcu_read_lock();
    //  t = find_task_by_pid_type(PIDTYPE_PID, pid);  //find the task_struct associated with this pid
        t = pid_task(find_pid_ns(id, &init_pid_ns), PIDTYPE_PID);
        if(t == NULL)
        {
            printk("no such pid\n");
            rcu_read_unlock();
            return -ENODEV;
        }
        ret = send_sig_info(sig, &info, t);    //send the signal
        rcu_read_unlock();
        if (ret < 0)
        {
            printk("error sending signal\n");
            return ret;
        }
        else
            printk("Send sig %d val %d pid %d\n", sig, val, id);

    }
    return ret;
}

从模块中的中断服务程序调用函数dmtimer_sendSignal()。

在用户空间:

main()
{
    sigemptyset (&alarm_sig);
    for (i = SIGRTMIN; i <= SIGRTMAX; i++)
        sigaddset (&alarm_sig, i);
    sigprocmask (SIG_BLOCK, &alarm_sig, NULL);

}

void * DATA_taskInput(void *pArg)
{
    siginfo_t   info;
    int32_t input;
    sigset_t input_sig;
    int fd;

    // Create digital input event
    sig = SIGRTMIN+1;
    sigemptyset(&gSig_input);
    sigaddset(&gSig_input, sig);


    // Set real time signal number for module to use
    if (TIMER_setParm(PARM_SIGRT, SIGRTMIN + 1 ) < 0)
        error(0, errno, "THREADS_events() called TIMER_setParm():");

    // Set PID in module
    TIMER_setParm(PARM_PID, getpid()); 

    fd = signalfd(-1, &gSig_input, 0);

    while(!gQuitInput)
    {
        sigwaitinfo(&gSig_input, &info);            // digital input event
//      read(fd, &info, sizeof(info));

        printf("val = 0x%x\n", info.si_int);
    }

    close(fd);

    printf("DATA_taskInput() end.\n");

    return NULL;

} // end: DATA_taskInput

用户空间应用程序pid和实时信号编号实现为模块参数,由用户空间应用程序使用TIMER_setParm()设置。

问题是用户空间应用程序在等待信号时保持阻塞状态(sigwaitinfo()永远不会返回)。我从控制台看到了printk()调用的输出:

“发送sig 35 val xxxx pid nnnn”

使用正确的信号值(35)和pid。

如果我从用户空间应用程序中调用sigqueue()或者从控制台输入“kill -35 nnnn”,则

sigwaitinfo()会成功返回。

我做错了什么?

是否需要从工作队列中调用dmtimer_sendSignal()?

我已尝试将代码设置为SI_KERNEL(无差异),解锁信号(应用程序关闭)和kill_proc_info()(未找到)。

我正在使用来自Critical Link的AM335x SOM上运行的Angstrom发行版。 Angstrom版本v2012.05 - 内核3.2.0-00351-gb80917e

1 个答案:

答案 0 :(得分:0)

我遇到了类似的问题,我已经解决了。

在我的例子中,

  • KernelModule:send_sig_info(SIGRTMIN)

  • UserProcess:sigaction(SIGRTMIN)(sa_sigaction处理程序的等待信号)

我真正的问题是“UserProcess的SIGRTMIN”与内核不同。

  • UserProcess的SIGRTMIN = 34

  • 内核的SIGRTMIN = 32

所以,我将SIGRTMIN的信号编号改为36,我成功修复了它。

您在内核模块中使用了哪个信号编号? SIGRTMIN? 如果您使用SIGRTMIN,我建议您更改信号编号。

感谢。

Jinbum Park。