Linux Kernel2.6.9内核源码分析--poll

旧城冷巷雨未停 提交于 2020-01-28 15:06:22

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;
	}
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!