gpt4 book ai didi

linux - 在Linux内核模块中实现民意测验

转载 作者:IT王子 更新时间:2023-10-29 00:13:29 25 4
gpt4 key购买 nike

我有一个简单的字符设备驱动程序,可让您从自定义硬件设备中读取。它使用DMA将数据从设备内存复制到内核空间(然后由用户决定)。
read调用非常简单。它开始DMA写操作,然后在等待队列中等待。 DMA完成后,中断处理程序将设置一个标志并唤醒等待队列。需要注意的重要一点是,即使在设备要提供数据之前,我也可以随时启动DMA。 DMA引擎将坐下等待,直到有要复制的数据为止。这很好。我可以在用户空间中实现一个简单的阻塞读取调用,它的行为与我期望的一样。

我想实现poll,以便可以在用户空间中使用select系统调用,从而可以同时监视此设备和套接字。

我可以在poll上找到的大多数resources都说:

  • 为每个等待队列调用poll_wait,这可能表明
  • 状态发生了变化
  • 返回一个位掩码,指示数据是否可用

  • 第二部分使我感到困惑。我见过的大多数示例都有一种简单的方法(指针比较或状态位)来检查数据是否可用。就我而言,除非启动DMA,否则数据将永远不可用,即使执行了此操作,数据也不会立即可用(在设备实际拥有数据并完成DMA之前可能要花费一些时间)。

    那将如何实现呢? poll函数是否应该实际启动DMA,以便最终获得数据?我想这会破坏我的 read函数。

    最佳答案

    免责声明

    嗯,这是一个很好的体系结构问题,它暗示了有关您的硬件和所需用户空间接口(interface)的一些假设。因此,让我得出结论以进行更改,并尝试猜测哪种解决方案最适合您的情况。

    设计

    考虑到您还没有提到write()操作,我将进一步假设您的硬件一直在生成新数据。如果是这样,您提到的设计可能正是使您感到困惑的地方:

    The read call is very simple. It starts a DMA write, and then waits on a wait queue.



    这正是阻止您以常规,常用(可能是您所希望的)方式使用驱动程序的原因。让我们思考开箱即用的情况,并首先提出所需的用户界面(如何从用户空间使用驱动程序)。在我看来,下一种情况是常用且足够的:
  • poll()您的设备文件以等待新数据到达
  • read()您的设备文件以获得到达的数据

  • 现在您可以看到,向DMA的数据请求应该通过 read()操作开始 而不是。正确的解决方案是在驱动程序中连续读取数据(不从用户空间触发任何数据)并将其存储在内部,并且当用户要求驱动程序提供数据以便 消耗(通过 read()操作)时-为用户提供内部存储的数据。如果驱动程序内部没有存储任何数据-用户可以使用 poll()操作等待新数据到达。

    如您所见,这就是众所周知的 producer-consumer problem。您可以使用 circular buffer将来自硬件的数据存储在驱动程序中(因此,在缓冲区已满时有意丢失旧数据以防止缓冲区溢出的情况)。因此,生产者(DMA)写入该RX环形缓冲区的 ,而消费者(用户在用户空间中执行 read())从该RX环形缓冲区的 读取。

    代码引用

    所有这些情况使我想起了串行控制台[ 12]驱动程序。因此,请考虑在驱动程序实现中使用 Serial API(如果您的设备 实际上是串行控制台)。例如,参见 drivers/tty/serial/atmel_serial.c驱动程序。我对UART API并不是很熟悉,所以我无法确切地告诉您发生了什么,但是乍一看它看起来并不难,因此您可以从该代码中找出一两个问题您的驱动程序设计。

    如果您的驱动程序不应该使用串行API,则可以使用下一个驱动程序作为引用:
  • drivers/char/virtio_console.c
  • drivers/char/xillybus/xillybus_core.c

  • 补充

    在评论中回答您的问题:

    are you suggesting that read calls poll when there is no data available and read should block?



    首先,您要决定是否要提供:
  • 阻止I/O
  • non-blocking I/O
  • 或两者都

  • 让我们假设(出于争论的目的)您想在驱动程序中同时提供这两个选项。在这种情况下,如果 open()参数包含 flags标志,则应 checkin O_NONBLOCK调用。从 man 2 open :

    O_NONBLOCK or O_NDELAY

    When possible, the file is opened in nonblocking mode. Neither the open() nor any subsequent operations on the file descriptor which is returned will cause the calling process to wait. For the handling of FIFOs (named pipes), see also fifo(7). For a discussion of the effect of O_NONBLOCK in conjunction with mandatory file locks and with file leases, see fcntl(2).



    现在,当您知道用户选择的模式时,可以下一步(在驱动程序中):
  • 如果flags中的open()不包含此类标志,则可以阻止read()(即,如果数据不可用,请等待DMA事务完成然后返回新数据)。
  • 但是,如果O_NONBLOCK标志中有open(),并且循环缓冲区中没有可用数据,则应从read()调用返回,并返回EWOULDBLOCK错误代码。

  • man 2 read :

    EAGAIN or EWOULDBLOCK

    The file descriptor fd refers to a socket and has been marked nonblocking (O_NONBLOCK), and the read would block. POSIX.1-2001 allows either error to be returned for this case, and does not require these constants to have the same value, so a portable application should check for both possibilities.



    您可能还想阅读下一篇文章,以更好地了解相应的接口(interface):

    [1] Serial Programming Guide for POSIX Operating Systems

    [2] Serial Programming HOWTO

    补充2

    I need some sort of background task that is continuously reading from the device and populating the ring buffer. poll is now trivial - just check if there's anything in that buffer, but read is more difficult because it may need to wait for something to be posted to the ring buffer.



    例如,查看 drivers/char/virtio_console.c驱动程序实现。
  • poll()函数中:执行poll_wait()(以等待新数据到达)
  • receive data interrupt handler中:执行wake_up_interruptible()(唤醒pollread操作)
  • read()函数中:
  • ,如果端口has no data:
  • (如果设置了O_NONBLOCK标志)(在open()操作中):立即返回-EAGAIN = -EWOULDBLOCK
  • 否则我们将阻止读取:执行wait_event_freezable()以等待新数据到达
  • (如果端口有数据):返回data from buffer


  • 另请参阅相关问题: How to add poll function to the kernel module code?

    关于linux - 在Linux内核模块中实现民意测验,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34027366/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com