【发布时间】: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