3

我需要从内核向用户空间函数发送一个字符串,而不需要特别从用户空间请求它,通过内核中的某个事件触发用户空间中的函数或应用程序。到目前为止,我已经尝试了一个 Ioctl,它从用户空间的一个 init 开始,然后休眠并继续阅读有关 netlink 的内容,但找不到一个好的工作示例。任何建议或示例将非常有义务。

4

3 回答 3

5

这是我的流程的工作方式,我也会对任何改进建议感兴趣:

  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. 内核将信号中继到应用程序的处理程序

于 2013-10-14T13:38:31.070 回答
3

你有几个选择:

  1. 信号。用户进程定义了一个信号处理程序,内核在收到事件时向用户进程发出信号。这很好用,但需要处理代码在异步信号处理程序中运行(这使得编写正确代码变得更加棘手)。缺点是您可以使用信号处理程序传输的数据量有些有限。确保使用可以排队的信号(例如实时信号),这样您就不会在进程正在处理信号时丢失消息。
  2. 阻止系统调用或文件访问。用户进程执行系统调用(或读/写文件)使其进入睡眠状态。调用的内核驱动程序维护一个事件队列,并在事件到达和阻塞的等待者存在时将事件出列(这样可以避免在用户进程解除阻塞时丢失事件)。
  3. 创建一个系统调用来配置一个sigevent. 在内核端,创建一个sigqueue来触发相关事件。
于 2013-10-14T14:15:33.073 回答
1

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

内核空间

您必须在发送信号之前准备好 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。

用户空间

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

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);

我希望它有所帮助。

于 2017-01-17T14:35:23.863 回答