驱动IO模型-select
新人学习,欢迎指正

部分select.c代码
		    应用层
select(maxfd+1,&rfds,NULL,NULL,NULL);
-------------------(系统调用)------------------------------
kernel-3.4.39/arch/arm/kernel$ vi calls.S
//系统调用相关的汇编文件
CALL(sys_select)
VFS:vi -t sys_select
->SYSCALL_DEFINE5宏,5代表有五个参数,替换得到sys_select
	SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp,\
	fd_set __user *, outp,fd_set __user *, exp, \
	struct timeval __user *, tvp)
->
	#define SYSCALL_DEFINE5(select, ...)
	SYSCALL_DEFINEx(5, _select, __VA_ARGS__)
->
	#define SYSCALL_DEFINEx(x,_select, ...)
	__SYSCALL_DEFINEx(x, _select, __VA_ARGS__)
->
	#define __SYSCALL_DEFINEx(x, _select, ...) 
	long sys_select(int n, fd_set __user * inp,
	fd_set __user *outp,fd_set __user *exp,
	struct timeval __user * tvp)
	{
	ret = core_sys_select(n, inp, outp, exp, to);
	}
	--------------------------------------------------------------
	core_sys_select(n, inp, outp, exp, to);
	//1.校验最大的文件描述符
		struct fdtable *fdt;
	fdt = files_fdtable(current->files);
	max_fds = fdt->max_fds;
	if (n > max_fds)
		n = max_fds;
	//2.分配文件描述符的内存
	bits = kmalloc(6 * size, GFP_KERNEL);
	fds.in      = bits;
	fds.out     = bits +   size;
	fds.ex      = bits + 2*size;
	//在内核空间分配的读表,写表,其他表的首地址
	fds.res_in  = bits + 3*size;
	fds.res_out = bits + 4*size;
	fds.res_ex  = bits + 5*size;
	//在内核空间分配的准备好的读表,写表,其他表的首地址
	//3.将用户空间的读表,写表,其他的表拷贝到内核空间
	if ((ret = get_fd_set(n, inp, fds.in)) ===>copy_from_user
		(ret = get_fd_set(n, outp, fds.out))
		(ret = get_fd_set(n, exp, fds.ex)))
	//4.文件描述符的检查,如果所有的文件描述符的数据
	都没有准备好,进程休眠,否则将准备好的文件描
	述符放入到fds.res_in,fds.res_out,fds.res_ex
	ret = do_select(n, &fds, end_time);
	//5.判断是否是信号唤醒的进程
	ret = -ERESTARTNOHAND;
	if (signal_pending(current))
		goto out;    ====>信号唤醒的就跳过拷贝
			ret = 0;
	//6.如果不是信号唤醒的休眠,将文件描述符拷贝到用户空间
	if (set_fd_set(n, inp, fds.res_in) ||
	set_fd_set(n, outp, fds.res_out) || ====>copy_to_user
	set_fd_set(n, exp, fds.res_ex))
	ret = -EFAULT;
---------------------------------------------------------------------
驱动:
unsigned int (*poll) (struct file *file,\
			struct poll_table_struct *wait);	
部分do_select代码
int do_select(int n, fd_set_bits *fds, struct timespec *end_time)
{
	struct poll_wqueues table;
	poll_table *wait;
	int retval, i;
	unsigned long slack = 0;
	retval = max_select_fd(n, fds);
	//通过文件描述符表中的对应的被设置
	//为1的位来校验最大的文件描述符的值
	n = retval;
	//将校验完的文件描述符赋值给n
	poll_initwait(&table);
	//poll相关结构体的初始化
	//只需要关心函数指针的初始化过程就行了
	//函数指针,执行的是__pollwait
	//在__pollwait会拿到你提交的等待队列头,然后
	//在等待队列头后面添加当前进程的等待队列项
	retval = 0;
	//retval是用来判断是否需要退出文件描述符遍历
	//的循环的。
	for (;;)
	{
		unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
		inp = fds->in;
		outp = fds->out;
		exp = fds->ex;
		rinp = fds->res_in;
		routp = fds->res_out;
		rexp = fds->res_ex;
		//定义6个指针,将结构体中的6个指针
		//赋值给这6个指针变量
		for (i = 0; i < n; ++rinp, ++routp, ++rexp)
		{
			//用来取第几个unsigned long类型的数据
			unsigned long in, out, ex, all_bits, bit = 1, mask, j;
			unsigned long res_in = 0, res_out = 0, res_ex = 0;
			const struct file_operations *f_op = NULL;
			struct file *file = NULL;
			in = *inp++;
			out = *outp++;
			ex = *exp++;
			all_bits = in | out | ex;
			if (all_bits == 0)
			{
				i += BITS_PER_LONG;
				continue;
			}
			for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1)
			{
				//用来unsigned long类型中的第几位的
				file = fget_light(i, &fput_needed);
				//这里的i就是获取到的文件描述符,fget_light
				//通过文件描述符找到file结构体
				//fd->fd_array[fd]->struct file
				//POLLIN
				if (file)
				{
					f_op = file->f_op;
					if (f_op && f_op->poll)
					{
						mask = (*f_op->poll)(file, wait);
					}
					//如果file存在,并且fops存在,并且fops中的
					//poll函数存在,就调用这个存在的poll函数
					//就会得到mask
					if ((mask & POLLIN_SET) && (in & bit))
					{
						res_in |= bit;
						//将当前的文件描述符放到
						//要返回的文件描述符表中
						retval++;
					}
					if ((mask & POLLOUT_SET) && (out & bit))
					{
						res_out |= bit;
						retval++;
					}
					if ((mask & POLLEX_SET) && (ex & bit))
					{
						res_ex |= bit;
						retval++;
					}
					//如果mask中的POLLIN/POLLOUT/POLLEX被置位了
					//将这些文件描述符放到准备好的文件描述表中
					//并且将retval这个变量加1,只要retval不为0,
					//死循环就会被退出
				}
			}
		}
		if (retval || timed_out || signal_pending(current))
			break;
		//如果retval不为0,或者超时时间到了或者信号到来了
		//这个死循环就会被退出
		if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,
								   to, slack))
		//如果上述的条件都不满足,循环没有退出,进程
		//就进入休眠状态
	}
	return retval;
}
}
驱动IO模型-select的更多相关文章
- Linux 网络编程的5种IO模型:信号驱动IO模型
		Linux 网络编程的5种IO模型:信号驱动IO模型 背景 上一讲 Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 我们讲解了多路复用等方面的知识,以及有关例程. ... 
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)
		IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ... 
- Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)
		Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 背景 我们在上一讲 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO中,对于其中的 阻塞/非阻塞IO 进行了 ... 
- 几种服务器端IO模型的简单介绍及实现
		一些概念: 同步和异步 同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发I/O操作并等待或者轮询的去查看I/O操作是否就绪,而异步是指用户进程触发I/O操作以后便开始做自己的事情,而 ... 
- JAVA基础知识之网络编程——-网络通信模型(IO模型)
		<Unix网络编程:卷1>中介绍了5中I/O模型,JAVA作为运行在宿主机上的程序,底层也遵循这5中I/O模型规则.这5中I/O模型分别是: 阻塞式IO 非阻塞式IO I/O复用 信号驱动 ... 
- Linux Network IO Model、Socket IO Model - select、poll、epoll
		目录 . 引言 . IO机制简介 . 阻塞式IO模型(blocking IO model) . 非阻塞式IO模型(noblocking IO model) . IO复用式IO模型(IO multipl ... 
- linux第7天  I/O的五种模型, select
		服务器端避免僵尸进程的方法: 1)通过忽略SIGCHLD信号,解决僵尸进程 signal(SIGCHLD, SIG_IGN) 2)通过wait方法,解决僵尸进程 signal(SIGCHLD, han ... 
- 浅析IO模型
		也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗.在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型.下面本文先从同步和异步的概念 说起, ... 
- IO模型分析
		html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ... 
随机推荐
- Cookie和Session得使用理解
			Cookie 饼干 什么是Cokkie? 1.Cookie 翻译过来是饼干的意思. 2.Cookie 是服务器通知客户端保存键值对的一种技术. 3.客户端有了 Cookie 后,每次请求都发送给服务器 ... 
- Git(7)-- 查看提交历史(git log 命令详解)
			@ 目录 1.git clone 2.git log 3.git log -p 4.git log --stat 5.git log --pretty=oneline 6.git log --pret ... 
- 附件携马之CS免杀shellcode过国内主流杀软
			0x01 写在前面 其实去年已经写过类似的文章,但是久没用了,难免有些生疏.所谓温故而知新,因此再详细的记录一下,一方面可以给各位看官做个分享,另一方面等到用时也不至于出现临阵磨枪的尴尬场面. 0x0 ... 
- 003 TCP/IP协议详解(一)
			TCP/IP TCP/IP 意味着 TCP 和 IP 在一起协同工作. TCP 负责应用软件(比如你的浏览器)和网络软件之间的通信. IP 负责计算机之间的通信. TCP 负责将数据分割并装入 IP ... 
- Docker小白到实战之容器数据卷,整理的明明白白
			前言 上一篇把常用命令演示了一遍,其中也提到容器的隔离性,默认情况下,容器内应用产生的数据都是由容器本身独有,如果容器被删除,对应的数据文件就会跟着消失.从隔离性的角度来看,数据就应该和容器共存亡:但 ... 
- commandBinding 的命令
			<Window x:Class="WpfApplication1.Window29" xmlns="http://schemas.microsoft.com/win ... 
- Saruman's Army
			直线上有N个点. 点i的位置是Xi.从这N个点中选择若干个,给它们加上标记. 对每一个点,其距离为R以内的区域里必须有带有标记的点(自己本身带有标记的点, 可以认为与其距离为 0 的地方有一个带有标记 ... 
- mzy,struts学习(三):action中获得servlet中三域一参的三种方法
			package com.mzy.servlet; import java.util.Arrays; import java.util.Map; import javax.servlet.Servlet ... 
- Struts2之处理请求参数
			时间:2017-1-11 11:05 --Struts2中获取请求参数(重点)1.Struts2是一个MVC框架,那么分别表示什么? View:JSP Model:Action Co ... 
- FXGL游戏开发-JavaFX游戏框架
			FXGL 是一个JavaFX 游戏开发的框架,这个框架有两个版本,其中基于JDK1.8的版本已经不再维护,目前最新的是基于JDK11的版本,也就是Openjfx的版本. FXGL 提供了各种游戏范例: ... 
