c-内核模块与用户空间程序通信的最佳方式是什么



这个问题看起来很简单,但我想发送一个事件来通知我的用户空间程序模块缓冲区已准备好读取。

例如,我在内核模块中有一个缓冲区,它的数据将由用户空间程序消耗。如果所有数据都被消耗掉了,内核模块必须在新数据到达时通知我的程序。

这是生产者/消费者的典型问题。生产者是一个内核模块,消费者是一个用户空间程序。

今天,我向程序(事件)发送一个信号,并使用ioctl函数访问数据缓冲区。但我不知道这种方法是否足以解决这类问题。我担心不必要地使用网络链接或内存映射来解决这个问题。

阅读一些其他模块,以实现您想要的功能。

在Linux内核中有很多这样做的选项,包括:

  • 虚拟文件系统,例如/proc、/sys、configfs、relayfs(实际上是relayfs)
  • netlink
  • 阻止系统调用
  • poll()/epoll()&相关的

/proc可能是最容易上手的,因为它已经存在很久了,而且有大量关于如何使用它的文档。创建一个映射到缓冲区的虚拟文件,然后让用户空间应用程序打开fd并使用select。简单且无处不在。有更现代和"更好"的方法——它们不可避免地会用/proc+select()来描述,所以首先学习这些方法会教会你一些有用的东西。

为了共享内核模块的状态信息,我建议使用任何一个可用的虚拟文件系统(例如:/proc/sys,或者如果您正在调试debugfs)。

但是,如果您想在内核之间传输大量数据,那么您可以考虑使用netlink套接字或使用mmap,这可能是传输数据最快的机制,尽管您必须实现自己的通知机制来通知用户空间程序数据何时准备就绪,反之亦然(用于消费)。

有关Linux下所有可用选项,请参阅此链接。

有两种众所周知的方法可以从用户空间到内核空间进行通信。

  • 类似/proc/sys/configfs/debugfs标准的虚拟文件系统
  • 系统调用,如read()write()open()close()fork()
  • 用于字符驱动程序的ioctl。带copy_to_usercopy_from_user
  • netlink插座-主要用于网络子系统
  • 使用基于udevuevent的事件机制从内核空间到用户空间阅读更多https://stackoverflow.com/a/23149574/775964
  • 从核心空间向用户空间线程发送signal。完整示例位于https://embetronicx.com/tutorials/linux/device-drivers/sending-signal-from-linux-device-driver-to-user-space/
  • 使用用户空间/内核空间都可以使用的公共内存如ION memoryDMABuf,请在此处阅读更多信息https://lwn.net/Articles/480055

上面列出的所有方法都使用公共方法从用户空间到内核空间调用remote procedure call(RPC)。

如果你能理解http://articles.manugarg.com/systemcallinlinux2_6.html然后,您可以在linux内核中开发自己的框架,用于用户空间到内核空间的通信。

您可以在用户空间中定义一个变量并将其映射到内核。当数据准备就绪时,内核将设置该变量。在用户空间中,应用程序可以轮询变量。设置后,可以执行ioctl从内核读取数据。缺点是必须在每个定义的时间轮询用户空间中的变量,但好处是可以避免锁定机制。

您可以通过Poll或在用户空间中选择系统调用并在内核空间中轮询fops来实现这一点。它将被来自用户空间的轮询系统调用阻止。当数据准备就绪时,从内核空间向用户空间发送通知/事件。收到此事件后,进程可以读取数据。

最新更新