使用 select() 检测 UIO 设备文件上的块

问题描述 投票:0回答:2

我正在开发运行 Yocto 的嵌入式处理器。我有一个修改过的 uio_pdrv_genirq.c UIO 驱动程序。

我正在编写一个库来控制 DMA。有一个函数可以写入设备文件并启动 DMA。第二个函数旨在通过调用 select() 等待 DMA 完成。当 DMA 正在进行时,设备文件会阻塞。完成后,DMA 控制器发出中断,释放设备文件上的块。

我使用 read() 让系统按预期工作,但我想切换到 select(),以便我可以包含超时。然而,当我使用 select() 时,它似乎无法识别该块并且总是立即返回(在 DMA 完成之前)。我已经包含了代码的简单版本:

int gannet_dma_interrupt_wait(dma_device_t *dma_device,
        dma_direction dma_transfer_direction) {

    fd_set rfds;
    struct timeval timeout;
    int select_res;

    /* Initialize the file descriptor set and add the device file */
    FD_ZERO(&rfds);
    FD_SET(dma_device->fd, &rfds);

    /* Set the timeout period. */
    timeout.tv_sec = 5;
    timeout.tv_usec = 0;

    /* The device file will block until the DMA transfer has completed. */
    select_res = select(FD_SETSIZE, &rfds, NULL, NULL, &timeout);

    /* Reset the channel */
    gannet_dma_reset(dma_device, dma_transfer_direction);

    if (select_res == -1) {
        /* Select has encountered an error */
        perror("ERROR <Interrupt Select Failed>\n");
        exit(0);
    }
    else if (select_res == 1) {
        /* The device file descriptor block released */
        return 0;
    }
    else {
        /* The device file descriptor block exceeded timeout */
        return EINTR;
    }
}

我的代码有什么明显的错误吗?或者有人可以建议替代选择吗?

c blocking posix-select
2个回答
1
投票

原来UIO驱动包含两个计数器。一个记录了 事件数量(

event_count
),另一个记录有多少个事件 调用函数知道 (
listener->event_count
)。

当您在 UIO 驱动程序上执行

read()
时,它会返回事件数并 使
listener->event_count
等于
event_count
。 IE。听者是 现在了解已发生的所有事件。

当您在 UIO 驱动程序上使用

poll()
select()
时,它会检查这两个是否 数字不同,如果不同则返回(如果相同则返回 等待直到它们不同然后返回)。它不会更新
listener->event_count

显然,如果您在调用

read()
之间不执行
select()
那么
listener->event_count
event_count
和第二个不匹配
select()
会立即返回。 因此需要调用
read()
在致电
select()
之间。

事后看来,

select()
应该以这种方式工作似乎很明显,但当时对我来说并不明显。


0
投票

这个答案假设可以将 select() 用于指定的设备文件(我仅将 select() 用于套接字描述符)。作为 select() 的替代函数,您可能需要查看 poll() 系列函数。接下来的内容至少有望提供有关如何解决调用 select() 问题的提示。

select() 函数的第一个参数必须是最大描述符编号加 1。由于只有一个描述符,因此可以将其直接传递给 select() 作为其第一个参数并加 1。还要考虑文件描述符dma_device 中的可能无效。在超时时返回 EINTR 实际上可能是您想要做的事情,但如果情况并非如此,并且为了测试无效描述符,这里有一个不同的版本供您考虑。 select() 调用可能会被信号中断,在这种情况下,返回值为 -1 并且 errno 将设置为 EINTR。这可以由您的函数在内部处理,如下所示:

FD_ZERO(&rfds);
FD_SET(dma_device->fd, &rfds);

timeout.tv_sec = 5;
timeout.tv_usec = 0;

// restart select() if it's interrupted by a signal;

do {

  select_res = select(dma_device->fd + 1, &rfds, NULL, NULL, &timeout);

}
while( select_res < 0 && errno == EINTR);


if (select_res > 0) {

  // a file descriptor is legible

}
else {

  if (select_res == 0) {

    // select() timed-out
  }
  else  {

    // an error other than a signal occurred

    if (errno == EBADF) {

      // your file descriptor is invalid 

    }
  } 
}
© www.soinside.com 2019 - 2024. All rights reserved.