linux poll 和 select
使用非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一个 或多个文件而不阻塞. 这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来 读或写. 因此, 它们常常用在必须使用多输入输出流的应用程序, 而不必粘连在它们任何 一个上. 相同的功能常常由多个函数提供, 因为 2 个是由不同的团队在几乎相同时间完 成的: select 在 BSD Unix 中引入, 而 poll 是 System V 的解决方案. epoll 调用[23]23 添加在 2.5.45, 作为使查询函数扩展到几千个文件描述符的方法.
支持任何一个这些调用都需要来自设备驱动的支持. 这个支持(对所有 3 个调用)由驱动 的 poll 方法调用. 这个方法由下列的原型:
unsigned int (*poll) (struct file *filp, poll_table *wait);
这个驱动方法被调用, 无论何时用户空间程序进行一个 poll, select, 或者 epoll 系统 调用, 涉及一个和驱动相关的文件描述符. 这个设备方法负责这 2 步:
- 1. 在一个或多个可指示查询状态变化的等待队列上调用 poll_wait. 如果没有文 件描述符可用作 I/O, 内核使这个进程在等待队列上等待所有的传递给系统调用的 文件描述符.
- 2. 返回一个位掩码, 描述可能不必阻塞就立刻进行的操作.
这 2 个操作常常是直接的, 并且趋向与各个驱动看起来类似. 但是, 它们依赖只能由驱 动提供的信息, 因此, 必须由每个驱动单独实现.
poll_table 结构, 给 poll 方法的第 2 个参数, 在内核中用来实现 poll, select, 和 epoll 调用; 它在 <linux/poll.h>中声明, 这个文件必须被驱动源码包含. 驱动编写者 不必要知道所有它内容并且必须作为一个不透明的对象使用它; 它被传递给驱动方法以便 驱动可用每个能唤醒进程的等待队列来加载它, 并且可改变 poll 操作状态. 驱动增加一 个等待队列到 poll_table 结构通过调用函数 poll_wait:
void poll_wait (struct file *, wait_queue_head_t *, poll_table *);
poll 方法的第 2 个任务是返回位掩码, 它描述哪个操作可马上被实现; 这也是直接的. 例如, 如果设备有数据可用, 一个读可能不必睡眠而完成; poll 方法应当指示这个时间 状态. 几个标志(通过 <linux/poll.h> 定义)用来指示可能的操作:
实际上, epoll 是一组 3 个调用, 都可用来获得查询功能. 但是, 由于我们的目的, 我们可认为它是一个调用.
POLLIN
如果设备可被不阻塞地读, 这个位必须设置.
POLLRDNORM
这个位必须设置, 如果"正常"数据可用来读. 一个可读的设备返回 ( POLLIN|POLLRDNORM ).
POLLRDBAND
这个位指示带外数据可用来从设备中读取. 当前只用在 Linux 内核的一个地方 ( DECnet 代码 )并且通常对设备驱动不可用.
POLLPRI
高优先级数据(带外)可不阻塞地读取. 这个位使 select 报告在文件上遇到一个异 常情况, 因为 selct 报告带外数据作为一个异常情况.
POLLHUP
当读这个设备的进程见到文件尾, 驱动必须设置 POLLUP(hang-up). 一个调用 select 的进程被告知设备是可读的, 如同 selcet 功能所规定的.
POLLERR
一个错误情况已在设备上发生. 当调用 poll, 设备被报告位可读可写, 因为读写 都返回一个错误码而不阻塞.
POLLOUT
这个位在返回值中设置, 如果设备可被写入而不阻塞.
POLLWRNORM
这个位和 POLLOUT 有相同的含义, 并且有时它确实是相同的数. 一个可写的设备 返回( POLLOUT|POLLWRNORM).
POLLWRBAND
如同 POLLRDBAND , 这个位意思是带有零优先级的数据可写入设备. 只有 poll 的 数据报实现使用这个位, 因为一个数据报看传送带外数据.
应当重复一下 POLLRDBAND 和 POLLWRBAND 仅仅对关联到 socket 的文件描述符有意义: 通常设备驱动不使用这些标志.
poll 的描述使用了大量在实际使用中相对简单的东西. 考虑 poll 方法的 scullpipe 实 现:
static unsigned int
scull_p_poll(struct file *filp, poll_table *wait)
{
struct scull_pipe *dev = filp->private_data;
unsigned int mask = 0;
/*
* The buffer is
circular; it is considered full
* if "wp"
is right behind "rp" and empty if the
* two are equal.
*/
down(&dev->sem);
poll_wait(filp,
&dev->inq, wait); poll_wait(filp, &dev->outq, wait); if
(dev->rp != dev->wp)
mask |=
POLLIN | POLLRDNORM; /* readable */ if
(spacefree(dev))
mask |= POLLOUT | POLLWRNORM; /* writable */
up(&dev->sem); return mask;
}
这个代码简单地增加了 2
个 scullpipe 等待队列到 poll_table, 接着设置正确的掩码
位, 根据数据是否可以读或写.
所示的
poll 代码缺乏文件尾支持, 因为 scullpipe 不支持文件尾情况. 对大部分真实 的设备, poll 方法应当返回 POLLHUP 如果没有更多数据(或者将)可用.
如果调用者使用 select 系统调用, 文件被报告为可读. 不管是使用 poll 还是 select, 应用程序知道它 能够调用 read 而不必永远等待,
并且 read 方法返回 0 来指示文件尾.
例如, 对于 真正的 FIFO, 读者见到一个文件尾当所有的写者关闭文件, 而在 scullpipe 中读者永远见不到文件尾. 这个做法不同是因为 FIFO 是用作一个 2 个进程的通讯通道, 而 scullpipe 是一个垃圾桶,
人人都可以放数据只要至少有一个读者. 更多地, 重新实
现内核中已有的东西是没有意义的, 因此我们选择在我们的例子里实现一个不同的做法.
与 FIFO 相同的方式实现文件尾就意味着检查 dev->nwwriters, 在 read 和 poll 中, 并且报告文件尾(如刚刚描述过的)如果没有进程使设备写打开. 不幸的是,
使用这个实现 方法, 如果一个读者打开 scullpipe 设备在写者之前, 它可能见到文件尾而没有机会来 等待数据. 解决这个问题的最好的方式是在 open 中实现阻塞, 如同真正的
FIFO 所做的; 这个任务留作读者的一个练习.
linux poll 和 select的更多相关文章
- linux epoll,poll,select
epoll函数用法,还有点poll和select 1,LT的epoll是select和poll函数的改进版. 特点是,读完缓冲区后,如果缓冲区还有内容的话,epoll_wait函数还会返回,直到把缓冲 ...
- poll和select
都允许进程决定是否可以对一个或者多个打开的文件做非阻塞的读取或写入.这些调用也会阻塞进程,直到给定的文件描述符集合中的任何一个可读取或写入.常常用于那些要使用多个输入或输出流而又不会阻塞与其中任意一个 ...
- Linux poll机制
1.用户空间调用(参考 poll(2) - Linux man page) int poll(struct pollfd *fds, nfds_t nfds, int timeout); it wai ...
- 四、poll()、select()和epoll()
在用户程序中,poll()和select()系统调用用于对设备进行无阻塞访问.poll()和select()最终会调用设备驱动中的poll()函数,在我所使用的Linux内核中,还有扩展的poll() ...
- linux poll函数
poll函数与select函数差不多 函数原型: #include <poll.h> int poll(struct pollfd fd[], nfds_t nfds, int timeo ...
- 【Pyhton Network】使用poll()或select()实现非阻塞传输
通常情况下,socket上的I/O会阻塞.即除非操作结束,否则程序不会照常进行.而以下集中情况需要在非阻塞模式下进行:1. 网络接口在等待数据时是活动的,可以做出相应:2. 在不使用线程或进程的情况下 ...
- linux c中select使用技巧
1.select函数作为定时器使用 it_value.tv_sec = 0; it_value.tv_usec = 100000: select(1,NULL,NULL,NULL,& ...
- linux c语言 select函数用法
linux c语言 select函数用法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<unis ...
- linux c中select使用方法
1.select函数作为定时器使用 it_value.tv_sec = 0; it_value.tv_usec = 100000: select(1,NULL,NULL,NULL,& ...
随机推荐
- Permutations 全排列 回溯
Given a collection of numbers, return all possible permutations. For example,[1,2,3] have the follow ...
- MySQL非安装版安装
1 数据库的打开方式(非安装版本) 1.解压mysql-5.7.12-winx64.zip到一个路径上没有空格没有汉字的目录中 2.复制my-default.ini重命名为my.ini 3.命令行进入 ...
- 【风马一族_软件】微软卸载工具_msicuu2.exe
msicuu2.exe是微软的Windows Installer清理工具,可以用来清理微软安装包软件产生的垃圾,当然也可以拿来作为修复相关软件的卸载准备使用 下载链接:http://files.cnb ...
- Oracle函数——MINUS
解释 “minus”直接翻译为中文是“减”的意思,在Oracle中也是用来做减法操作的,只不过它不是传统意义上对数字的减法,而是对查询结果集的减法.A minus B就意味着将结果集A去除结果集B中所 ...
- sql函数的使用——转换函数
转换函数用于将数据类型从一种转为另外一种,在某些情况下,oracle server允许值的数据类型和实际的不一样,这时oracle server会隐含的转化数据类型,比如: create table ...
- oracle 表空间/用户 增加删除
create temporary tablespace user_temp tempfile 'C:\dmp\user_temp.dbf' size 50m autoextend on next 50 ...
- Python基础:06条件和循环
1:条件表达式(三元操作符) Python 在很长的一段时间里没有条件表达式(C ? X : Y), 或称三元运算符.人们试着用 and 和 or 来模拟它, 但大多都是错误的. 根据 FAQ , 正 ...
- 使用 Captcha 扩展包 为 Laravel 5 应用生成验证码
http://laravelacademy.org/post/3910.html 1.安装 我们通过 Composer 安装 Captcha 扩展包: composer require mews/ca ...
- Hbase数据模型物理视图
- python基础之逻辑题(1)
python基础之逻辑题(1) 1.用一行代码实现数值交换? 2.求结果--fromkeys? 3.1,2,3,4,5能组成多少个互不相同且无重复的三位数? 4.有两个字符串列表a和b,每个字符串是逗 ...