linux系统下select和poll的实现机理
1.用户层应用程序调用select()
2.核心层调用sys_select() ------> do_select()
最终调用文件描述符fd对应的struct file类型变量的struct file_operations *f_op的poll函数。
poll指向的函数返回当前可否读写的信息。
1)如果当前可读写,返回读写信息。
2)如果当前不可读写,则阻塞进程,并等待驱动程序唤醒,重新调用poll函数,或超时返回。
核心层的相关函数(select.c):
do_select( ... )
{
poll_table *wait;
...
for (;;)
{
set_current_state(TASK_INTERRUPTIBLE);
for (i = 0 ; i < n; i++)
{
unsigned long mask;
struct file *file;
...
file = fget(i);
mask = POLLNVAL;
mask = file->f_op->poll(file, wait);
if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off)))
retval++;
if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(fds,off))) {
retval++;
}
if (retval || !__timeout || signal_pending(current))
break;
__timeout = schedule_timeout(__timeout); // 此处阻塞,等待驱动wake_up_interruptible
}
current->state = TASK_RUNNING;
}
3.驱动需要实现poll函数。
当驱动发现有数据可以读写时,通知核心层,核心层重新调用poll指向的函数查询信息。
例如:
static unsigned int test_poll(struct file *file, poll_table * wait)
{
poll_wait(file, &queue, wait); // 此处将当前进程加入到等待队列中,但并不阻塞
return POLLIN |POLLRDNORM |...;
}
static void test_...(...)
{
wake_up_interruptible(&queue->proc_list);
}
static void test_init(...)
{
init_waitqueue_head(&queue->proc_list);
}