poll调用深入解析(四)

2014-11-24 09:41:27 · 作者: · 浏览: 6
struct poll_wqueues *wait, s64 *timeout)
{
int count = 0;
poll_table* pt = &wait->pt;

/* Optimise the no-wait case */
if (!(*timeout))
pt = NULL;

for (;;) {
struct poll_list *walk;
long __timeout;

set_current_state(TASK_INTERRUPTIBLE);
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++) {
/*
* Fish for events. If we found one, record it
* and kill the poll_table, so we don't
* needlessly register any other waiters after
* this. They'll get immediately deregistered
* when we break out and return.
*/
if (do_pollfd(pfd, pt)) {
count++;
pt = NULL;
}
}
}
/*
* All waiters have already been registered, so don't provide
* a poll_table to them on the next loop iteration.
*/
pt = NULL;
if (!count) {
count = wait->error;
if (signal_pending(current))
count = -EINTR;
}
if (count || !*timeout)
break;

if (*timeout < 0) {
/* Wait indefinitely */
__timeout = MAX_SCHEDULE_TIMEOUT;
} else if (unlikely(*timeout >= (s64)MAX_SCHEDULE_TIMEOUT-1)) {
/*
* Wait for longer than MAX_SCHEDULE_TIMEOUT. Do it in
* a loop
*/
__timeout = MAX_SCHEDULE_TIMEOUT - 1;
*timeout -= __timeout;
} else {
__timeout = *timeout;
*timeout = 0;
}

__timeout = schedule_timeout(__timeout);
if (*timeout >= 0)
*timeout += __timeout;
}
__set_current_state(TASK_RUNNING);
return count;
}
这个函数有以下几个要注意的点:
信号处理保障。在这个函数中先将当前进程设置为可以被信号中断,就是set_current_state(TASK_INTERRUPTIBLE)这一行,后面还会检查是否有需要处理的信号signal_pending(current)。这里的意思是就算是poll调用进入到sys_poll系统调用之后,也可以接收外部信号,从而退出当前系统调用(因为我们知道一般的系统调用都不会被中断的,所以系统调用一般都尽量很快的返回)。
外部大循环退出的条件,外部大循环退出的条件只有if (count || !*timeout) break;后面的条件容易理解,就是超时,前面的count是什么意思?它在每次调用do_pollfd函数之后,都有可能会加1,其实调用do_pollfd就是检查socket描述符状态的变化,如果有变化,就会使count加1,所以在结束内部遍历之后,count保存了所有的有状态变化的socket描述符数量。
这个函数会对之前以head为头结点的链表进行遍历,然后链表上每个结点中都包含很多很多的struct pollfd进行遍历(这些struct pollfd都被存储在struct poll_list结构的数组字段struct pollfd entries里面。
然后对每个struct pollfd调用do_pollfd(这会调用很多次,根据你传入多少个socket描述符而定),这个函数需要两个参数,一个是struct pollfd,这没得说的,另一个是刚刚初始化的table,就是那个暂时只是包含__pollwait回调指针的结构,还记得吧。
我们再进入do_pollfd,了解这个函数是做什么的?
[cpp]
static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait)
{
unsigned int mask;
int fd;

mask = 0;
fd = pollfd->fd;
if (fd >= 0) {
int fput_needed;
struct file * file;

file = fget_light(fd, &fput_needed);
mask = POLLNVAL;
if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, pwait);
/* Mask out unneeded events. */
mask &= pollfd->events | POLLERR | POLLHUP;
fput_light(fil