用内核触发用户空间

时间:2013-10-14 12:30:09

标签: linux-kernel embedded-linux

我需要从内核向用户空间函数发送字符串,而不是特别从用户空间请求它,通过内核中的某些事件触发用户空间中的函数或应用程序。 到目前为止,我已经尝试了一个Ioctl,它在用户空间的init上启动,然后睡觉并继续阅读netlink,但找不到一个好的工作示例。 任何建议或例子都是非常有必要的。

3 个答案:

答案 0 :(得分:4)

以下是我的流程如何运作,我也会对任何改进建议感兴趣:

  1. 启动内核模块
  2. 启动用户空间应用程序,该应用程序向内核模块发送自定义命令以注册内核模块信号的用户空间PID。在我的例子中,这是通过写入/ dev / mymodule。内核模块注册PID:

    ...
    printk("registering a new process id to receive signals: %d\n", current->pid);
    signal_pid = current->pid;
    ...
    

    用户空间应用程序还为某些类型的信号注册了内核处理程序。

    void local_sig_handler(int signum) {
            printf("received a signal from my module\n");
            fflush(stdout); }
    ...
    signal(SIGIO, local_sig_handler);
    
  3. 内核模块生成信号

    ...
    struct siginfo info;
    struct task_struct *t;
    info.si_signo=SIGIO;
    info.si_int=1;
    info.si_code = SI_QUEUE;        
    
    printk("<1>IRQ received: %d\n", irq);
    printk("<1>searching for task id: %d\n", signal_pid);
    
    t= pid_task(find_vpid(signal_pid),PIDTYPE_PID);//user_pid has been fetched successfully
    
    if(t == NULL){
            printk("<1>no such pid, cannot send signal\n");
    } else {
            printk("<1>found the task, sending signal\n");
            send_sig_info(SIGIO, &info, t);
    }
    
  4. 内核将信号中继到应用程序的处理程序

答案 1 :(得分:2)

你有几个选择:

  1. 信号。用户进程定义信号处理程序,内核在收到事件时向用户进程发出信号。这很好用,但要求处理代码在异步信号处理程序中运行(这使得编写正确的代码变得更加棘手)。缺点是您可以使用信号处理程序传输的数据量有限。确保使用可以排队的信号(例如实时信号),这样当过程处理信号时你不会丢失信息。
  2. 阻止系统调用或文件访问。用户进程执行系统调用(或读/写文件),使其进入休眠状态。调用的内核驱动程序维护一个事件队列,并在事件到达时以及阻塞的服务器存在时使事件出列(这可以避免在用户进程被解除阻塞时丢失事件)。
  3. 创建一个配置sigevent的系统调用。在内核方面,创建一个sigqueue以触发相关事件。

答案 2 :(得分:0)

我过去使用的一个例子是从内核空间中的硬件中断向用户空间发送信号。

  

KERNEL SPACE

您必须在发送信号之前准备siginfo和task_struct:

struct siginfo info;
struct task_struct *t;

info.si_signo = SIG_TEST;
info.si_code = SI_QUEUE;
info.si_int = 1234; // Any value you want to send
rcu_read_lock();

并且还可以使用用户空间应用程序PID查找任务。您必须通过write或ioctl操作将它从用户空间发送到内核空间。

t = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID);

然后你可以发送信号。

rcu_read_unlock();      
send_sig_info(SIG_TEST, &info, t);

我在此省略,但您必须检查每个操作的结果。

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

  

USER SPACE

您必须定义并实现回调函数:

void signalFunction(int n, siginfo_t *info, void *unused) {
      .....
      .....  
}

在主要程序中:

struct sigaction sig;

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

我希望它有所帮助。