【问题标题】:Sending realtime signal from a kernel module to user space fails从内核模块向用户空间发送实时信号失败
【发布时间】:2015-10-09 14:46:38
【问题描述】:

我找到了有关如何从内核模块向用户空间发送实时信号的示例代码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 发行版。 埃版本 v2012.05 - 内核 3.2.0-00351-gb80917e

【问题讨论】:

  • 次要修复:send_sig_info() 应与 rcu_read 部分一起调用,这保证其 t 参数仍然有效。顺便说一句,comments__send_signal 实现中说:Real-time signals must be queued if sent by sigqueue, or some other real-time mechanism. It is implementation defined whether kill() does so. 可能这是问题的根源:虽然看起来很相似,但kill 系统调用与send_sig_info 内核函数不同。
  • 感谢指正。但是,更改对结果没有影响。用户空间任务仍然没有收到来自模块的信号。
  • elixir.bootlin.com/linux/v5.9.8/source/kernel/signal.c#L1103 是高内核版本第一条评论的固定链接。

标签: linux linux-kernel embedded-linux


【解决方案1】:

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

在我的例子中,

  • 内核模块:send_sig_info(SIGRTMIN)

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

我真正的问题是“用户进程的 SIGRTMIN”与内核不同。

  • 用户进程的SIGRTMIN = 34

  • 内核的SIGRTMIN = 32

所以,我将信号编号从 SIGRTMIN 更改为 36,并成功修复它。

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

谢谢。

镇范公园。

【讨论】:

  • 我使用了 35 号信号。我最终改用了 netlink,它也允许我将数据发送到用户空间。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
  • 2021-08-03
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多