【问题标题】:Event notification from kernel space to user space从内核空间到用户空间的事件通知
【发布时间】:2014-08-18 03:23:45
【问题描述】:

当内核空间发生事件时如何通知用户空间应用程序?

当数据到达某个 GPIO 时,硬件会产生中断。 该数据被复制到内核缓冲区。此时,我希望驱动程序通知应用程序它可以调用read函数将数据从内核缓冲区复制到用户空间缓冲区。

我想过使用epoll方法,但epoll表示设备是否准备好读取。我想要的是,epoll 指示内核缓冲区何时已满。

还有,有没有办法修改驱动程序中poll_wait() 函数的行为?

【问题讨论】:

  • 当有数据要读取时,读取设备。那么究竟是什么问题呢?
  • 问题是,驱动从设备读取数据到内核缓冲区后,产生了中断。在 ISR 中,我希望 poll_wait() 函数唤醒并将掩码设置为 POLLIN。 poll_wait() 函数是否在我们的控制范围内?
  • 看看poll_wait的第二个参数。
  • 这是一个指向 wait_queue_head_t 的指针。我可以在 ISR 中使用 wake_up() 吗?
  • 这就是它的用途。你有没有费心阅读some documentation

标签: linux linux-kernel linux-device-driver epoll


【解决方案1】:

(已在聊天会话中回复,但似乎应该在答案中,因此将其放在这里更详细。)

poll_wait 所做的是将您的驱动程序添加到用户空间程序正在等待的文件描述符列表中。模式是:

  • 用户程序调用 poll/select/epoll_ctl
  • 核心内核调用驱动程序的轮询入口点
  • 驱动程序调用 poll_wait 将其等待队列添加到等待队列列表中(除非 GPIO 数据已经可读,您通过返回值指示)
  • 稍后,当设备中断时,您在等待队列上调用 wake_up,如果进程(仍在)在 poll/select 调用中等待,这会解除阻塞
  • 用户态程序唤醒,调用read实际获取数据

IOW,poll_wait 本身不休眠(或阻塞);它只是将您的设备添加到稍后可能唤醒进程的程序列表中。睡眠是在核心内核中完成的(例如,在 select 系统调用中)。这样,用户程序可以使用 select 一次在任意数量的设备上等待。

如果您的用户空间程序在等待时确实没有其他事情可做,那么您可以简单地读取用户程序调用,并让您的驱动程序设置其等待队列并调用 wait_event_interruptible(或其他 wait_event_* 变体)。这将阻塞进程,直到您的中断处理程序调用wake_up;此时您从内核缓冲区复制到用户缓冲区。

或者您可以同时支持这两种方法。通常,如果您支持 select 方法,您还可以在读取函数中检查 O_NONBLOCK 文件标志,以便用户代码可以选择在读取中阻塞。

是的,ISR 可以调用 wake_up。这是设备 I/O 的常见模式:在“进程上下文”中等待/阻塞,在“中断上下文”中唤醒,然后在返回进程上下文后完成 I/O。

顺便说一句,从驱动程序的角度来看,使用 select、poll 或 epoll 通常是相同的。从用户的角度来看,使用 select 或 poll 更容易一些。这是一个“一次性”交易:“这里有一组文件描述符;阻塞直到其中一个准备好读取(或写入等)或直到超时”。

而使用 epoll,您首先创建一个 epoll 描述符,然后单独添加 I/O 文件描述符。但随后“等待”调用只指定了单个 epoll 描述符。所以如果你有大量的文件描述符要等待,你不必在每个系统调用中都指定它们,这会降低每个 epoll 调用的系统调用开销。

【讨论】:

  • 嗨,epoll(在用户空间中)的处理程序是否在中断上下文中完成?
  • 没有。用户空间中的任何事情都不会在中断上下文中完成。
  • 使用 poll_wait 或 wait_event_interruptible 从内核到用户空间的延迟是否更小?
  • 差异不太可能是可测量的。
猜你喜欢
  • 2023-03-12
  • 2011-10-22
  • 1970-01-01
  • 2016-06-26
  • 2020-02-26
  • 1970-01-01
  • 2011-03-02
  • 1970-01-01
  • 2012-06-23
相关资源
最近更新 更多