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

时间:2016-07-11 10:30:44

标签: c select blocking

我正在开发一个运行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;
    }
}

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

2 个答案:

答案 0 :(得分:0)

这个答案假定可以使用select()作为指定设备文件的意图(我只使用select()作为套接字描述符)。作为select()的替代函数,您可能想要查看poll()函数系列。以下内容有望至少提供一些提示,说明如何通过调用select()解决问题。

select()函数的第一个参数必须是最大despriptor数加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 

    }
  } 
}

答案 1 :(得分:0)

事实证明,UIO驱动程序包含两个计数器。一个记录了 事件数量(event_count),其他事件记录了多少事件 调用函数知道(listener->event_count)。

当您在UIO驱动程序上执行read()时,它会返回事件数和 使listener->event_count等于event_count。即。听众是 现在已经发生了所有已发生的事件。

在UIO驱动程序上使用poll()select()时,它会检查这两个驱动程序 数字是不同的,如果它们是相同的(如果它们是相同的话) 等到它们不同然后返回)。它没有更新 listener->event_count

显然,如果您在拨打read()之间没有select(),那么 listener->event_countevent_count和第二个select()不匹配 read()将立即返回。 因此有必要打电话 在select()之间拨打select()

事后看来Result似乎应该以这种方式运作,但当时对我来说并不明显。