我正在开发一个运行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;
}
}
我的代码有什么明显错误吗?或者任何人都可以建议选择?
答案 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_count
与event_count
和第二个select()
不匹配
read()
将立即返回。 因此有必要打电话
在select()
之间拨打select()
。
事后看来Result
似乎应该以这种方式运作,但当时对我来说并不明显。