如何从内核向用户空间发送信号 [英] How to send signal from kernel to user space

查看:264
本文介绍了如何从内核向用户空间发送信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的内核模块代码需要向用户登陆程序发送信号[ def.],将其执行转移到已注册的信号处理程序.

My kernel module code needs to send signal [def.] to a user land program, to transfer its execution to registered signal handler.

我知道如何在两个用户登陆过程之间发送信号,但是我找不到有关该任务的任何在线示例.

I know how to send signal between two user land processes, but I can not find any example online regarding the said task.

具体来说,我的预期任务可能需要如下所示的接口(一旦error!= 1,不应执行代码行int a=10):

To be specific, my intended task might require an interface like below (once error != 1, code line int a=10 should not be executed):

void __init m_start(){
    ...
    if(error){
        send_signal_to_userland_process(SIGILL)
    }
    int a = 10;
    ...
}

module_init(m_start())

推荐答案

我过去使用的一个示例是从内核空间中的硬件中断向用户空间发送信号.就是这样:

An example I used in the past to send signal to user space from hardware interrupt in kernel space. That was just as follows:

内核空间

#include <asm/siginfo.h>    //siginfo
#include <linux/rcupdate.h> //rcu_read_lock
#include <linux/sched.h>    //find_task_by_pid_type

static int pid; // Stores application PID in user space

#define SIG_TEST 44

需要一些包含"和定义.基本上,您需要在用户空间中使用应用程序的PID.

Some "includes" and definitions are needed. Basically, you need the PID of the application in user space.

struct siginfo info;
struct task_struct *t;

memset(&info, 0, sizeof(struct siginfo));
info.si_signo = SIG_TEST;
// 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_code = SI_QUEUE;
// real time signals may have 32 bits of data.
info.si_int = 1234; // Any value you want to send
rcu_read_lock();
// find the task with that pid
t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);
if (t != NULL) {
    rcu_read_unlock();      
    if (send_sig_info(SIG_TEST, &info, t) < 0) // send signal
        printk("send_sig_info error\n");
} else {
     printk("pid_task error\n");
     rcu_read_unlock();
    //return -ENODEV;
}

前面的代码准备信号结构并发送它.请记住,您需要应用程序的PID.在我的情况下,来自用户空间的应用程序通过ioctl驱动程序过程发送其PID:

The previous code prepare the signal structure and send it. Bear in mind that you need the application's PID. In my case the application from user space send its PID through ioctl driver procedure:

static long dev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    ioctl_arg_t args;
    switch (cmd) {
        case IOCTL_SET_VARIABLES:
              if (copy_from_user(&args, (ioctl_arg_t *)arg, sizeof(ioctl_arg_t))) return -EACCES;
              pid = args.pid;
        break;

用户空间

定义并实现回调函数:

#define SIG_TEST 44

void signalFunction(int n, siginfo_t *info, void *unused) {
    printf("received value %d\n", info->si_int);
}

在主过程中:

int  fd = open("/dev/YourModule", O_RDWR); 
if (fd < 0) return -1;

args.pid       = getpid();
ioctl(fd, IOCTL_SET_VARIABLES, &args); // send the our PID as argument

struct sigaction sig;

sig.sa_sigaction = signalFunction; // Callback function
sig.sa_flags = SA_SIGINFO;
sigaction(SIG_TEST, &sig, NULL);

尽管答案有点长,但我希望它会有所帮助,但这很容易理解.

I hope it helps, despite the fact the answer is a bit long, but it is easy to understand.

这篇关于如何从内核向用户空间发送信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆