套接字之select系统调用

select是IO多路复用的一种方式,用来等待一个列表中的多个描述符的可读可写状态;

 1 SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
 2         fd_set __user *, exp, struct timeval __user *, tvp)
 3 {
 4     struct timespec64 end_time, *to = NULL;
 5     struct timeval tv;
 6     int ret;
 7 
 8     if (tvp) {
 9         if (copy_from_user(&tv, tvp, sizeof(tv)))
10             return -EFAULT;
11 
12         to = &end_time;
13         if (poll_select_set_timeout(to,
14                 tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),
15                 (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))
16             return -EINVAL;
17     }
18 
19     ret = core_sys_select(n, inp, outp, exp, to);
20     ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);
21 
22     return ret;
23 }

本文主要分析socket的select操作,所以对于select系统调用前面通用的部分,我们只分析其调用关系,如下,可见在do_select函数中,会调用文件操作的poll函数;

1  /**
2   * select系统调用函数调用关系
3   * sys_select
4   *   |-->core_sys_select
5   *       |-->do_select
6   *           |-->f_op->poll 调用文件的poll操作
7   */

socket文件操作结构实现如下,我们本文重点分析poll操作,即sock_poll函数;

 1 /*
 2  *    Socket files have a set of 'special' operations as well as the generic file ones. These don't appear
 3  *    in the operation structures but are done directly via the socketcall() multiplexor.
 4  */
 5 /* socket文件操作函数 */
 6 static const struct file_operations socket_file_ops = {
 7     .owner =    THIS_MODULE,
 8     .llseek =    no_llseek,
 9     .read_iter =    sock_read_iter,
10     .write_iter =    sock_write_iter,
11     .poll =        sock_poll,
12     .unlocked_ioctl = sock_ioctl,
13 #ifdef CONFIG_COMPAT
14     .compat_ioctl = compat_sock_ioctl,
15 #endif
16     .mmap =        sock_mmap,
17     .release =    sock_close,
18     .fasync =    sock_fasync,
19     .sendpage =    sock_sendpage,
20     .splice_write = generic_splice_sendpage,
21     .splice_read =    sock_splice_read,
22 };

sock_poll函数在获取到socket之后,会调用其操作中的poll函数,其中tcp为tcp_poll,udp为udp_poll;

 1 /* No kernel lock held - perfect */
 2 static unsigned int sock_poll(struct file *file, poll_table *wait)
 3 {
 4     unsigned int busy_flag = 0;
 5     struct socket *sock;
 6 
 7     /*
 8      *      We can't return errors to poll, so it's either yes or no.
 9      */
10     /* 获取到socket */
11     sock = file->private_data;
12 
13     if (sk_can_busy_loop(sock->sk)) {
14         /* this socket can poll_ll so tell the system call */
15         busy_flag = POLL_BUSY_LOOP;
16 
17         /* once, only if requested by syscall */
18         if (wait && (wait->_key & POLL_BUSY_LOOP))
19             sk_busy_loop(sock->sk, 1);
20     }
21 
22     /* 执行socket操作中的poll,tcp为tcp_poll,udp为udp_poll */
23     return busy_flag | sock->ops->poll(file, sock, wait);
24 }

tcp_poll的代码分析会在阅读tcp源码时补充;

猜你喜欢

转载自www.cnblogs.com/wanpengcoder/p/11749272.html