套接字之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源码时补充;

原文地址:https://www.cnblogs.com/wanpengcoder/p/11749272.html

时间: 2024-08-30 07:12:59

套接字之select系统调用的相关文章

Linux 套接字编程 - select

select 可以感知文件表述符集合中的变化,如果办fd0(即标准输入)放入select的read fd set,发现只有按回车的时候select才会返回.查了下要把终端的缓冲大小设为1,这样就能实现击键后马上反应了. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <termio.h> #include <sys/

套接字之recv系统调用

recv系统调用对sys_recvfrom进行了简单的封装,只是其中不包含地址信息,其只需要从建立连接的另一端接收信息: 1 /* 2 * Receive a datagram from a socket. 3 */ 4 5 SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size, 6 unsigned int, flags) 7 { 8 return sys_recvfrom(fd, ubuf, size, flags,

套接字之send系统调用

send系统调用只是对sendto系统调用进行了封装,传递的参数不包含目的地址信息,数据会发送到已经建立连接的另一端的地址: 1 /* 2 * Send a datagram down a socket. 3 */ 4 5 SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, 6 unsigned int, flags) 7 { 8 return sys_sendto(fd, buff, len, flags, NULL

套接字之close系统调用

close系统调用用于关闭文件描述符,其系统调用实现如下所示: 1 / 2 * Careful here! We test whether the file pointer is NULL before 3 * releasing the fd. This ensures that one clone task can't release 4 * an fd while another clone is opening it. 5 */ 6 SYSCALL_DEFINE1(close, unsi

套接字之sendmsg系统调用

sendmsg系统调用允许在用户空间构造消息头和控制信息,用此函数可以发送多个数据缓冲区的数据,并支持控制信息:当调用进入内核后,会将用户端的user_msghdr对应拷贝到内核的msghdr中,然后进行数据发送: 1 SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) 2 { 3 /* 不支持64位采用32位兼容标记 */ 4 if (flags & MSG_CMSG_

套接字之sendto系统调用

sendto系统调用用于向指定的目的地址发送数据,其系统调用的流程比较容易理解,如下面所示,其主要完成 (1)将用户数据组织成msghdr,(2)而后调用socket操作的sendmsg:ipv4对应的sendmsg实现为inet_sendmsg,该函数进行端口自动绑定检查和绑定后,调用传输层的sendmsg函数发送数据,比如tcp会调用tcp_sendmsg函数,这里不详细介绍,读到tcp模块在进行补充: 1 /* 2 * Send a datagram to a given address.

套接字之recvmsg系统调用

recvmsg系统调用允许用户指定msghdr结构来接收数据,可以将数据接收到多个缓冲区中,并且可以接收控制信息:接收信息过程与其他接收系统调用核心一致,都是调用传输层的接收函数进行数据接收: 1 SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, 2 unsigned int, flags) 3 { 4 /* 不支持64位采用32位兼容标记 */ 5 if (flags & MSG_CMSG_COMPAT) 6

套接字之recvfrom系统调用

recvfrom系统调用通过用户传入的接收空间构造msghdr,并且调用sock_recvmsg,该函数调用socket操作的recvmsg函数sock->ops->recvmsg,ipv4对应的是inet_recvmsg,该函数调用传输层的sk->sk_prot->recvmsg来接收数据,如tcp则调用tcp_recvmsg,接收完成之后记录地址结构长度信息: 1 /* 2 * Receive a frame from the socket and optionally rec

高性能网络编程 - select系统调用

IO复用使得程序能够同时监听多个文件描述符,比如客户端需要同时处理用户输入和网络连接,服务器端需要同时处理监听套接字和连接套接字,select系统调用可以使得我们监听自己感兴趣描述符,可读,可写,异常等事件.select能处理的异常只有带外数据.能同时处理描述符的数量受限于FD_SETSIZE的大小(一般1024).下面这个程序展示了它的一般用法. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #i