下面是函数调用情况:
SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
long, timeout_msecs)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINEx(x, sname, ...) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
宏解析得到函数:
asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds,
long timeout_msecs)
上面这个函数位于fs/select.c中
poll(struct pollfd *fds, nfds_t nfds, int timeout) 对超时参数进行一些处理后直接调用下面函数
ret = do_sys_poll(ufds, nfds, to) ‘
poll_initwait(&table)
init_poll_funcptr(table->pt, __pollwait) --> table->pt->qproc = __pollwait;
fdcount = do_poll(nfds, head, &table, end_time)
for (;;) {
struct poll_list *walk;
for (walk = list; walk != NULL; walk = walk->next) {
struct pollfd * pfd, * pfd_end;
pfd = walk->entries;
pfd_end = pfd + walk->len;
for (; pfd != pfd_end; pfd++) {
if (do_pollfd(pfd, pt)) {
count++;
pt = NULL;
}
}
}
pt = NULL;
if (!count) {
count = wait->error;
if (signal_pending(current))
count = -EINTR;
}
if (count || timed_out)
break;
if (end_time && !to) {
expire = timespec_to_ktime(*end_time);
to = &expire;
}
if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack))
timed_out = 1;
}
return count;
20行开始是一个死循环,死循环退出的条件有两大点:
a、由第43行可知,count非零(及30行中的do_pollfd返回值非零或者40行中有信号量等待或者39行有错误发生)
b、超时
第51行表示让本进程休眠一段时间,注意:应用程序执行poll调用后,如果a、b的条件不满足,进程就会进入休眠。
那么,谁唤醒呢?除了休眠到指定时间被系统唤醒外,还可以被驱动程序唤醒──记住这点,这就是为什么驱动的poll
里要调用poll_wait的原因,后面分析。
下面主要看do_pollfd(pfd, pt)函数
mask = file->f_op->poll(file, pwait) 调用驱动程序里面的poll函数
mask &= pollfd->events | POLLERR | POLLHUP;
return mask;
由此可见,主要让驱动程序中的poll函数返回适当的mask即可使得do_pollfd函数返回值非零从而使得用户空间的poll函 数返回非零值
如果超时,用户空间的poll函数也会返回,但返回值为0,由上面的return count可以得出。
下面我们就明白驱动程序中的poll函数应该怎样规划了。
上面的init_poll_funcptr函数中给poll_table结构体注册了一个__pollwait函数
static void __pollwait(struct file *filp, wait_queue_head_t *wait_address,
poll_table *p)
{
struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt);
struct poll_table_entry *entry = poll_get_entry(pwq);
if (!entry)
return;
get_file(filp);
entry->filp = filp;
entry->wait_address = wait_address;
entry->key = p->key;
init_waitqueue_func_entry(&entry->wait, pollwake);
entry->wait.private = pwq;
add_wait_queue(wait_address, &entry->wait);
}
上面这个函数是将当前进程挂在队列中
所以在我们的驱动程序的poll函数中要间接的调用这个函数,刚好poll_wait函数会调用上面这个函数,这样我们的驱动程序的poll函数中调用什么函数,
返回什么样的值就都清楚了,这就可以指导我们进行驱动中的poll函数编程了。
现在来总结一下poll机制:
执行到驱动程序的poll_wait函数时,进程并没有休眠,我们的驱动程序里实现的poll函数是不会引起休眠的。让进程进入休眠,是前面分析的do_sys_poll函数的30行“__timeout = schedule_timeout(__timeout)”。
poll_wait只是把本进程挂入某个队列,应用程序调用poll > sys_poll > do_sys_poll > poll_initwait,do_poll > do_pollfd > 我们自己写的poll函数后,再调用schedule_timeout进入休眠。如果我们的驱动程序
发现情况就绪,可以把这个队列上挂着的进程唤醒,在驱动程序中一定要有唤醒程序。可见,poll_wait的作用,只是为了让驱动程序能找到要唤醒的进程。即使不用poll_wait,我们的程序也有机会被唤醒:chedule_timeout(__timeout),只是要休眠__time_out这段时间。
1. poll > sys_poll > do_sys_poll > poll_initwait,poll_initwait函数注册一下回调函数__pollwait,它就是我们的驱动程序执行poll_wait时,真正被调用的函数。
2. 接下来执行file->f_op->poll,即我们驱动程序里自己实现的poll函数
它会调用poll_wait把自己挂入某个队列,这个队列也是我们的驱动自己定义的;
它还判断一下设备是否就绪。
3. 如果设备未就绪,do_sys_poll里会让进程休眠一定时间
4. 进程被唤醒的条件有2:一是上面说的“一定时间”到了,二是被驱动程序唤醒。驱动程序发现条件就绪时,就把“某个队列”上挂着的进程唤醒,这个队列,就是前面通过poll_wait把本进程挂过去的队列。