内核源码IO多路复用之select

1. 简介:

        本文将基于内核2.6.32版本,了解select运作的原理。

2. 数据结构:

        select基于位图的,因此对于三种事件(读写超时)的位图集合都是使用unsigned long的数组来表示。

        __kernel_fd_set就是fd_set,其内在就是一个数组,每个unsigned long在不同机器上表示长度不同,总大小1024,写死在内核,因此如果修改select监听的总fd数需要重新编译内核。

        这里出现的几个宏比较常用到,__NFDBITS表示一个unsigned long能表示多少个位,__FD_SETSIZE表示监听的fd数量,__FD_SET_LONGS表示unsigned long数组的大小。对应FD的事件置位只要将相应的位图置位即可。

        select中监听的fd应该都是fd号小于1024的,位图的使用都是直接使用fd号当做位图的下标进行处理的,如果fd号大于1024可能会导致异常。

#undef __NFDBITS
#define __NFDBITS	(8 * sizeof(unsigned long))

#undef __FD_SETSIZE
#define __FD_SETSIZE	1024

#undef __FDSET_LONGS
#define __FDSET_LONGS	(__FD_SETSIZE/__NFDBITS)

#undef __FDELT
#define	__FDELT(d)	((d) / __NFDBITS)

#undef __FDMASK
#define	__FDMASK(d)	(1UL << ((d) % __NFDBITS))

typedef struct {
	unsigned long fds_bits [__FDSET_LONGS];
} __kernel_fd_set;
3.  select 实现

        函数系统调用的入口在fs/select.c中,系统调用处主要是对超时时间的处理,从用户空间拷贝到内核空间,并检查其合法性。主要流程在core_sys_select。函数poll_select_copy_remaining主要对结果数据进行处理,把数据从内核空间拷贝回用户空间。

SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
		fd_set __user *, exp, struct timeval __user *, tvp)
{
	struct timespec end_time, *to = NULL;
	struct timeval tv;
	int ret;

	if (tvp) {
		if (copy_from_user(&tv, tvp, sizeof(tv)))
			return -EFAULT;

		to = &end_time;
		/* 检查超时的合法性。  */
		if (poll_select_set_timeout(to,
				tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
				(tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
			return -EINVAL;
	}

	/* 实际处理函数。  */
	ret = core_sys_select(n, inp, outp, exp, to);
	/* 数据后处理。  */
	ret = poll_select_copy_remaining(&end_time, tvp,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值