2013-10-14 111 views
2

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

回答

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

+5

您不应该使用PID来识别内核中的进程。该过程可以退出并且不同的过程重新使用该PID。相反,你应该为进程使用指向'task_struct'的指针(而不是在注册时存储'current-> pid',只需存储'current')。 – caf

2

你有几种选择:

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

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

核空间

你必须发送一个信号之前准备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任务。您必须通过写或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); 

我希望它能帮助。

相关问题