通过等待队列从计时器处理程序发出 poll/select 事件
Emitting a poll/select event from a timer handler through a wait queue
我正在为连接到带有慢速 ARM SoC 的开发板的自定义实验室硬件编写一个 Linux 字符驱动程序,但在尝试从内核 space 到用户 space.
基本上,我定期(每 10 毫秒)从 HW 读取数据,通过内核中的一些过滤器 运行ning 处理这些数据 space(这部分没问题),并通知用户space 当满足某些条件时。我的方法是让用户 space 守护进程使用 poll()
系统调用等待来自驱动程序的通知(自然,因为我也在监视那里的网络套接字)。
在驱动程序初始化时,我创建了定时器(使用 setup_timer
),它将调用负责读取硬件的函数,设置用于此的 GPIO,并创建一个等待队列(使用 init_waitqueue_head
) 从计时器处理程序向 struct file_operations
中的 .poll
处理程序发出信号。这部分似乎还可以。
有一个 .unlocked_ioctl
处理程序来设置和获取条件,但这部分正在工作。
我的 .read
方法来自 struct file_operations
只是将一个字节的状态发送给用户 space;它从不阻塞,因为总有一个有效的(包括 "waiting more data from the sensors" 的 'W')。
打开设备后,我会启用定时器。它的处理函数在 10 ms 后被调用,从 HW 读取数据,通过过滤器 运行s,并再次将定时器设置为 运行(使用 mod_timer
);如果过滤后的数据符合我的条件,它会更改状态,将标志 poll_evt_waiting
设置为 1,并在与来自 struct file_operations
的 .poll
方法共享的队列上调用 wake_up_interruptible
。这个方法就是:
static unsigned int firflt_file_poll(struct file *filp, poll_table *wait)
{
unsigned int mask = 0;
poll_wait(filp, &firflt_queue, wait);
if (poll_evt_waiting != 0) {
mask = POLLIN | POLLRDNORM;
poll_evt_waiting = 0;
}
return mask;
}
问题是:我的用户 space 守护程序中的 poll()
从未收到来自驱动程序的通知!我的方法有什么明显的错误吗?特别是关于等待队列?我以前从未实现过 poll() 的 "other side",并从 "Linux Device Drivers",2005 版
获得了所有相关信息
如果连续读取设备文件描述符,我可以看到用户 space 的状态发生变化,但这会使我的守护程序处于繁忙循环中,这对于慢 CPU 来说太过分了.我真的需要让它在民意调查中等待,直到有新的东西出现。
此外,我对等待队列所做的唯一操作是用 init_waitqueue_head
初始化它,当状态改变时用 poll_evt_waiting
唤醒它,然后将它传递给 poll_wait
在我的.poll
处理程序。这种方法合理吗?
在轮询队列上调用 wake_up_interruptible()
只是强制 .poll
方法 再次调用 。用户 space 进程接收通知 仅当 .poll
方法 returns 掩码 已设置轮询位时。
检查你的 .poll
方法实际上 returns 非零掩码。
我正在为连接到带有慢速 ARM SoC 的开发板的自定义实验室硬件编写一个 Linux 字符驱动程序,但在尝试从内核 space 到用户 space.
基本上,我定期(每 10 毫秒)从 HW 读取数据,通过内核中的一些过滤器 运行ning 处理这些数据 space(这部分没问题),并通知用户space 当满足某些条件时。我的方法是让用户 space 守护进程使用 poll()
系统调用等待来自驱动程序的通知(自然,因为我也在监视那里的网络套接字)。
在驱动程序初始化时,我创建了定时器(使用
setup_timer
),它将调用负责读取硬件的函数,设置用于此的 GPIO,并创建一个等待队列(使用init_waitqueue_head
) 从计时器处理程序向struct file_operations
中的.poll
处理程序发出信号。这部分似乎还可以。有一个
.unlocked_ioctl
处理程序来设置和获取条件,但这部分正在工作。我的
.read
方法来自struct file_operations
只是将一个字节的状态发送给用户 space;它从不阻塞,因为总有一个有效的(包括 "waiting more data from the sensors" 的 'W')。打开设备后,我会启用定时器。它的处理函数在 10 ms 后被调用,从 HW 读取数据,通过过滤器 运行s,并再次将定时器设置为 运行(使用
mod_timer
);如果过滤后的数据符合我的条件,它会更改状态,将标志poll_evt_waiting
设置为 1,并在与来自struct file_operations
的.poll
方法共享的队列上调用wake_up_interruptible
。这个方法就是:static unsigned int firflt_file_poll(struct file *filp, poll_table *wait) { unsigned int mask = 0; poll_wait(filp, &firflt_queue, wait); if (poll_evt_waiting != 0) { mask = POLLIN | POLLRDNORM; poll_evt_waiting = 0; } return mask; }
问题是:我的用户 space 守护程序中的 poll()
从未收到来自驱动程序的通知!我的方法有什么明显的错误吗?特别是关于等待队列?我以前从未实现过 poll() 的 "other side",并从 "Linux Device Drivers",2005 版
如果连续读取设备文件描述符,我可以看到用户 space 的状态发生变化,但这会使我的守护程序处于繁忙循环中,这对于慢 CPU 来说太过分了.我真的需要让它在民意调查中等待,直到有新的东西出现。
此外,我对等待队列所做的唯一操作是用 init_waitqueue_head
初始化它,当状态改变时用 poll_evt_waiting
唤醒它,然后将它传递给 poll_wait
在我的.poll
处理程序。这种方法合理吗?
在轮询队列上调用 wake_up_interruptible()
只是强制 .poll
方法 再次调用 。用户 space 进程接收通知 仅当 .poll
方法 returns 掩码 已设置轮询位时。
检查你的 .poll
方法实际上 returns 非零掩码。