从您列出的这三个因素中,只有第一个实际上是正确的。至于其余的——不是真的。用户空间代码可以执行 DMA 操作——这没有问题。有许多硬件设备公司在他们的产品中采用了这种技术。也可以有一个中断驱动的用户空间应用程序,即使所有的 I/O 都是通过完整的内核旁路完成的。当然,简单地做一个mmap()
on并不容易/dev/mem
。
您必须在内核中拥有驱动程序的最小部分——这是为您的用户空间提供内核所需的最低限度所必需的(因为如果您考虑一下/dev/mem
)也由一个字符支持设备驱动)。
对于 DMA,它实际上太简单了——您所要做的就是处理mmap
请求并将 DMA 缓冲区映射到用户空间。对于中断 - 有点棘手,无论如何,中断必须由内核处理,但是,内核可能不做任何工作,只是唤醒调用的进程,例如,epoll_wait()
. 另一种方法是像 DOSEMU 那样向进程传递信号,但这非常慢,不推荐使用。
至于您的实际问题,您应该考虑的一个因素是资源共享。只要您不必在多个应用程序之间共享设备,并且在用户空间中没有什么是您不能做的,那就去用户空间吧。您可能会在开发周期中节省大量时间,因为编写用户空间代码非常容易。然而,当两个或更多应用程序需要共享设备(或其资源)时,您可能会花费大量时间来实现它——想象一下多个进程同时分叉、崩溃、映射(相同?)内存等. 毕竟,IPC 通常是通过内核完成的,所以如果应用程序需要开始相互“对话”,性能可能会大大降低。
另一个因素是内核基础设施。假设您要编写网络设备驱动程序。在用户空间中这样做不是问题。但是,如果您这样做,那么您也需要编写一个完整的网络堆栈,因为无法使用 Linux 内核中的默认堆栈。
如果可能的话,我会说去用户空间,并且使事情工作的努力少于编写内核驱动程序,并记住有一天可能需要将代码移动到内核中。事实上,根据是否定义了某些宏,为用户空间和内核空间编译相同的代码是一种常见的做法,因为在用户空间进行测试要愉快得多。