1.IO multiplexing、select 、core_sys_select

Linux IO复用:select、poll与epoll解析
本文详细介绍了Linux系统中的IO复用技术,包括select、poll和epoll的工作原理。通过sys_select系统调用的代码分析,展示了如何在内核层面处理多个IO请求的监听和响应。在IO复用中,进程不会直接阻塞于具体的IO操作,而是阻塞在select等系统调用上,待数据准备好后才进行实际的IO操作。核心函数core_sys_select负责参数拷贝和结果返回。此外,还讨论了select的执行流程,包括当有信号发生时系统调用如何处理。

1. 什么是IO multiplexing?

IO multiplexing是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。在Linux系统中,常用的IO multiplexing手段有 select、poll 和 epoll。

IO multiplexing 主要用于处理网络请求,例如可以把多个请求句柄添加到 select 中进行监听,当有请求可进行IO的时候就会告知进程,并且把就绪的请求句柄保存下来,进程只需要对这些就绪的请求进行IO操作即可。下面通过一幅图来展示 select 的使用方式

2.IO multiplexing的基本原理

进程中阻塞select的系统调用,而不是阻塞I/O调用。
阻塞select系统调用等待socket可读,当select返回该socket可读时,用户进程激活,便调用recvfrom将数据报复制到的应用程序缓区中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNKVK2j5-1608088631639)(https://notes.shichao.io/unp/figure_6.3.png)]

3.Select process执行流


3.1 sys_selcet

下面为sys_select系统调用的代码

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 there is a timeout value*/
		if (copy_from_user(&tv, tvp, sizeof(tv))) 
			return -EFAULT;

		to = &end_time;
		/* set timeout, if Invalid time,then return -EINVAL*/
		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, 1, ret);

	return ret;
}

3.2 core_sys_select

该函数的主要作用是将用户空间的参数拷贝到内核,及将系统调用的返回值拷贝到用户空间

int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
			   fd_set __user *exp, struct timespec *end_time)
{
	fd_set_bits fds;
	
    /*
      计算max_fds,依据它使用kmalloc为fd_set_bits类型的变量分配内存:bits,该变量存储readfds、writefds、exceptfds共计6个集合        
    */
    ......(Part omitted)
    
    / *  get_fd_set just calls copy_from_user to copy FD_SET from user space * /
	if ((ret = get_fd_set(n, inp, fds.in)) ||
	    (ret = get_fd_set(n, outp, fds.out)) ||
	    (ret = get_fd_set(n, exp, fds.ex)))
		goto out;
	zero_fd_set(n, fds.res_in);  //clear
	zero_fd_set(n, fds.res_out);
	zero_fd_set(n, fds.res_ex);

	ret = do_select(n, &fds, end_time);

	if (ret < 0)  // nagetive,error
		goto out;
	if (!ret) {
		ret = -ERESTARTNOHAND;
		if (signal_pending(current)) // 检测到有信号则系统调用退出,返回用户空间执行信号处理函数
			goto out;
		ret = 0;
	}
    / *Copy the result set back to user space* / 
	if (set_fd_set(n, inp, fds.res_in) ||
	    set_fd_set(n, outp, fds.res_out) ||
	    set_fd_set(n, exp, fds.res_ex))
		ret = -EFAULT;

out:
	if (bits != stack_fds)
		kfree(bits);      /* corresponding to kmalloc above */ 
out_nofds:
	return ret;
}


参考

Select system call source code analysis
Chapter 6. I/O Multiplexing: The select and poll Functions

这是一个 **Makefile** 文件,用于 **自动化编译 C 语言项目**。它的作用是定义如何将多个 `.c` 源文件编译成一个可执行程序(在这个例子中是 `server`),并支持不同的服务器实现方式(多进程、多线程、I/O 多路复用)。 --- ## ✅ 逐行解释 Makefile 的含义 ```makefile CC = gcc ``` - 定义变量 `CC`,表示编译器为 `gcc`(GNU Compiler Collection)。 ```makefile CFLAGS = -Wall -Wextra -g ``` - 定义 `CFLAGS`,是编译时的选项: - `-Wall`:开启所有警告信息; - `-Wextra`:开启额外的警告; - `-g`:生成调试信息(方便使用 `gdb` 调试)。 ```makefile LDFLAGS_PROCESS = LDFLAGS_THREAD = -pthread LDFLAGS_SELECT = ``` - 定义链接器标志(linker flags): - `LDFLAGS_THREAD = -pthread`:多线程版本需要链接 `pthread` 库; - 其他版本不需要额外链接库,所以为空。 ```makefile all: server ``` - 定义默认目标为 `server`,即运行 `make` 时默认执行 `make server`。 ```makefile server: main.o multi_process_server.o multi_thread_server.o io_multiplexing_server.o $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS_THREAD) ``` - 定义目标 `server`,它依赖于四个 `.o` 文件(目标文件): - `main.o` - `multi_process_server.o` - `multi_thread_server.o` - `io_multiplexing_server.o` - `$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS_THREAD)`: - `$^` 表示所有依赖文件(即上面列出的 `.o` 文件); - `$@` 表示目标文件名(即 `server`); - 最终执行的命令是:用 `gcc` 编译这些 `.o` 文件,链接 `-pthread`,生成 `server` 可执行文件。 ```makefile main.o: main.c $(CC) $(CFLAGS) -c $< -o $@ ``` - 定义如何从 `main.c` 编译出 `main.o`: - `-c` 表示只编译不链接; - `$<` 表示第一个依赖项(即 `main.c`); - `-o $@` 表示输出到 `main.o`。 其他 `.o` 文件的规则类似: ```makefile multi_process_server.o: multi_process_server.c $(CC) $(CFLAGS) -c $< -o $@ multi_thread_server.o: multi_thread_server.c $(CC) $(CFLAGS) -c $< -o $@ io_multiplexing_server.o: io_multiplexing_server.c $(CC) $(CFLAGS) -c $< -o $@ ``` ```makefile clean: rm -f *.o server ``` - 定义 `clean` 目标,用于清理编译产生的 `.o` 文件和 `server` 可执行文件。 --- ## ✅ Makefile 的整体流程图 ``` main.c multi_process_server.c multi_thread_server.c io_multiplexing_server.c | v gcc -c → main.o multi_process_server.o multi_thread_server.o io_multiplexing_server.o | v gcc -pthread main.o ... → server ``` --- ## ✅ 使用方法 ```bash # 编译整个项目 make # 启动服务器,支持三种模式 ./server process # 多进程版本 ./server thread # 多线程版本 ./server select # I/O 多路复用版本 # 清理编译文件 make clean ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值