poll源码分析--基于3.10.0-693.11.1

本文深入分析了Linux下的poll系统调用,从do_sys_poll函数开始,探讨了poll性能问题的原因,并详细解释了poll初始化、等待队列的唤醒、do_pollfd的执行过程以及与文件系统交互的细节。通过分析,揭示了poll如何注册进程到等待队列,如何处理事件,以及如何在有事件发生时唤醒进程。
摘要由CSDN通过智能技术生成

poll epoll是linux下服务器高性能况下的基础组件,对其进行深入分析对于写代码和查bug都是极好的,现在就来分析下这个poll的实现。

我们依然从函数调用开始分析,先分析poll的系统调用实现

SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds,
		int, timeout_msecs)
{
   
	struct timespec end_time, *to = NULL;
	int ret;

	//如果传了超时时间,则在这里获取墙上时间
	if (timeout_msecs >= 0) {
   
		to = &end_time;
		poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC,
			NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC));
	}

	ret = do_sys_poll(ufds, nfds, to);   //实际干活函数

	//如果调用执行中有信号到来,就填充当前线程的restart_block,用于重启系统调度。系统调用返回用户层前会处理信号。
	if (ret == -EINTR) {
   
		struct restart_block *restart_block;

		restart_block = &current_thread_info()->restart_block;
		restart_block->fn = do_restart_poll;
		restart_block->poll.ufds = ufds;
		restart_block->poll.nfds = nfds;

		if (timeout_msecs >= 0) {
   
			restart_block->poll.tv_sec = end_time.tv_sec;
			restart_block->poll.tv_nsec = end_time.tv_nsec;
			restart_block->poll.has_timeout = 1;
		} else
			restart_block->poll.has_timeout = 0;

		ret = -ERESTART_RESTARTBLOCK    //这个返回值是不会用户层看到的,在信号处理结束前会调用restart_syscall来重启这个调用
	}
	return ret;
}

看do_sys_poll的实现,这个函数结构还是比较简单的

int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
		struct timespec *end_time)
{
   
	struct poll_wqueues table;
 	int err = -EFAULT, fdcount, len, size;
	/* Allocate small arguments on the stack to save memory and be
	   faster - use long to make sure the buffer is aligned properly
	   on 64 bit archs to avoid unaligned access */
	   //一部分fds存在栈中,可以在fds少的时候减少一次内存申请
	long stack_pps[POLL_STACK_ALLOC/sizeof(long)];
	struct poll_list *const head = (struct poll_list *)stack_pps;
 	struct poll_list *walk = head;
 	unsigned long todo = nfds;

	if (nfds > rlimit(RLIMIT_NOFILE))
		return -EINVAL;

	len = min_t(unsigned int, nfds, N_STACK_PPS);
	for (;;) {
   
		walk->next = NULL;
		walk->len = len;
		if (!len)
			break;

		//第一次内存拷贝
		if (copy_from_user(walk->entries, ufds + nfds-todo,
					sizeof(struct pollfd) * walk->len))
			goto out_fds;

		todo -= walk->len;
		if (!todo)
			break;

		len = min
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值