Linux Kernel2.6.9内核源码分析–poll
long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout)
poll对应的系统调用为sys_poll,以下是参数说明:
struct pollfd __user * ufds:为struct pollfd的数组,里面有文件描述符,event 和revent,其中event为要监听的event类型,revent为监听的结果
unsigned int nfds:为struct pollfd的数组中的元素个数
long timeout:超时时间
asmlinkage long sys_poll(struct pollfd __user * ufds, unsigned int nfds, long timeout)
{
.............
poll_initwait(&table);
..........
while(i!=0) {
struct poll_list *pp;
pp = kmalloc(sizeof(struct poll_list)+
sizeof(struct pollfd)*
(i>POLLFD_PER_PAGE?POLLFD_PER_PAGE:i),
GFP_KERNEL);
.............
if (copy_from_user(pp->entries, ufds + nfds-i,
sizeof(struct pollfd)*pp->len)) {
err = -EFAULT;
goto out_fds;
}
i -= pp->len;
}
fdcount = do_poll(nfds, head, &table, timeout);
..............
}
poll大体流程上和select差不多,详细细节可参考前面两篇博客eventpoll,select:
1.初始化一个poll_wqueues table,注册回调函数__pollwait
2.将用户struct pollfd * ufds 数组形成一个struct poll_list *pp 链表
3.调用do_poll 依次执行file->f_op->poll 进行事件查询
static int do_poll(unsigned int nfds, struct poll_list *list,struct poll_wqueues *wait, long timeout)
{
int count = 0;
poll_table* pt = &wait->pt;
if (!timeout)
pt = NULL;
for (;;) {
struct poll_list *walk;
set_current_state(TASK_INTERRUPTIBLE);
walk = list;
while(walk != NULL) {
do_pollfd( walk->len, walk->entries, &pt, &count);
walk = walk->next;
}
pt = NULL;
if (count || !timeout || signal_pending(current))
break;
count = wait->error;
if (count)
break;
timeout = schedule_timeout(timeout);
}
__set_current_state(TASK_RUNNING);
return count;
}
其核心函数为do_pollfd,从最后可以看到将侦测到的mask赋值给revent: fdp->revents = mask;
static void do_pollfd(unsigned int num, struct pollfd * fdpage,
poll_table ** pwait, int *count)
{
int i;
for (i = 0; i < num; i++) {
int fd;
unsigned int mask;
struct pollfd *fdp;
mask = 0;
fdp = fdpage+i;
fd = fdp->fd;
if (fd >= 0) {
struct file * file = fget(fd);
mask = POLLNVAL;
if (file != NULL) {
mask = DEFAULT_POLLMASK;
if (file->f_op && file->f_op->poll)
mask = file->f_op->poll(file, *pwait);
mask &= fdp->events | POLLERR | POLLHUP;
fput(file);
}
if (mask) {
*pwait = NULL;
(*count)++;
}
}
fdp->revents = mask;
}
}
来源:CSDN
作者:年轻态程序猿
链接:https://blog.csdn.net/weixin_38537730/article/details/104099183