Linux设备驱动程序 之 poll和select

使用非阻塞IO的应用程序经常使用select,poll,epoll系统调用;它们的功能本质上是一样的:都允许进程决定是否可以对一个或者多个打开的文件做非阻塞的读取或者写入;这些电泳也会阻塞进程,直到给定的文件描述符中的任何一个可读取或者写入;因此,它们常常用于那些需要使用多个输入或者输出流而又不会阻塞于其中任何一个流的应用程序中;同一功能之所以要由多个独立的函数提供,是因为其中两个几乎是由两个不同的Unix团体分别实现的:select在BSD中引入,而poll由SystemV引入;epoll系统调用则用于将poll函数扩展到能够处理数千个文件描述符;

poll在file_operations结构中的定义如下:

1 unsigned int (*poll) (struct file *, struct poll_table_struct *);

1

unsigned int (*poll) (struct file *, struct poll_table_struct *);

当用户空间程序在驱动程序关联的文件描述符上执行select,poll,epoll系统调用时,该驱动程序的方法将被调用;该poll函数的功能分为两步:

1. 在一个或者多个可指示poll状态变化的等待队列上调用poll_wait;如果当前没有文件描述符可用来执行IO,则内核将进程在传递到该系统调用的所有文件描述符对应的等待队列上等待;

1 static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)

2. 返回一个用来描述操作是否可以立即无阻塞执行的位掩码;

POLLIN-如果设备可以无阻塞的读取,就设置该位;

POLLRDNORM-如果通常的数据已经就绪,就可以读取,就应该设置该位;一个可读设备返回POLLIN|POLLRDNORM;

POLLRDBAND-指示可以从设备读取out-of-band带外数据;

POLLPRI-可以无阻塞的读取高优先级(即out-of-band)的数据;设置该位会导致select报告文件发生一个异常,这是由于select把out-of-band数据作为异常对待;

POLLHUP-当读取设备的进程到达文件尾时,驱动程序必须设置POLLHUP位,调用select的进程会被告知设备是可读的;

POLLERR-设备发生了错误;如果调用poll,就会报告设备既可以读也可以写,因为读写都会无阻塞的返回一个错误码;

POLLOUT-如果设备可以无阻塞的写入,就在返回值中设置该位;

POLLWRNORM-该位和POLLOUT的意义一样,有时其实就是同一个数字;一个可写的设备将返回POLLOUT|POLLWRNORM;

POLLWRBAND-与POLLRDBAND类似,这一位标识具有非零优先级的数据可以被写入设备;只有数据报的poll实现中使用了这一位,因为数据报可以传输out-of-band数据;

POLLRDBAND和POLLWRBAND只在于套接字相关的文件描述符中才有意义,设备驱动程序通常用不到这两个标记;

随意从内核摘取了一段代码,对上面描述的两个步骤体现的很明确;

 1 static unsigned int evdev_poll(struct file *file, poll_table *wait)
 2 {
 3     struct evdev_client *client = file->private_data;
 4     struct evdev *evdev = client->evdev;
 5     unsigned int mask;
 6
 7     poll_wait(file, &evdev->wait, wait);
 8
 9     if (evdev->exist && !client->revoked)
10         mask = POLLOUT | POLLWRNORM;
11     else
12         mask = POLLHUP | POLLERR;
13
14     if (client->packet_head != client->tail)
15         mask |= POLLIN | POLLRDNORM;
16
17     return mask;
18 }

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

时间: 2024-10-27 09:11:21

Linux设备驱动程序 之 poll和select的相关文章

LINUX设备驱动程序笔记(三)字符设备驱动程序

      <一>.主设备号和次设备号        对字符设备的访问时通过文件系统内的设备名称进行的.那些设备名称简单称之为文件系统树的节点,它们通常位于/dev目录.字符设备驱动程序的设备文件可通过ls -l命令输出的第一列中的'c'来识别.块设备同样位于/dev下,由字符'b'标识 crw-rw----  1 root root    253,   0 2013-09-11 20:33 usbmon0 crw-rw----  1 root root    253,   1 2013-09

linux设备驱动程序中的阻塞、IO多路复用与异步通知机制

一.阻塞与非阻塞 阻塞与非阻塞是设备访问的两种方式.在写阻塞与非阻塞的驱动程序时,经常用到等待队列. 阻塞调用是指调用结果返回之前,当前线程会被挂起,函数只有在得到结果之后才会返回. 非阻塞指不能立刻得到结果之前,该函数不会阻塞当前进程,而会立刻返回. 函数是否处于阻塞模式和驱动对应函数中的实现机制是直接相关的,但并不是一一对应的,例如我们在应用层设置为阻塞模式,如果驱动中没有实现阻塞,函数仍然没有阻塞功能. 二.等待队列 在linux设备驱动程序中,阻塞进程可以使用等待队列来实现. 在内核中,

LINUX设备驱动程序(第3版)pdf高清版免费下载

下载地址:网盘下载 备用地址:网盘下载 内容简介编辑<LINUX设备驱动程序(第3版)>已针对Linux内核的2610版本彻底更新过了.内核的这个版本针对常见任务完成了合理化设计及相应的简化,如即插即用.利用sysfs文件系统和用户空间交互,以及标准总线上的多设备管理等等.要阅读并理解本书,您不必首先成为内核黑客:只要您理解C语言并具有Unix系统调用的一些背景知识即可.您将学到如何为字符设备.块设备和网络接口编写驱动程序.为此,<LINUX设备驱动程序(第3版)>提供了完整的示例

转:《Linux设备驱动程序3》源码目录结构和源码分析经典链接

转自:http://blog.csdn.net/geng823/article/details/37567557 [原创][专栏]<Linux设备驱动程序>--- LDD3源码目录结构和源码分析经典链接 [专栏]Linux设备驱动程序学习(总目录) [专栏]LDD3源码分析链接(总目录) 1. LDD3源码分析之hello.c与Makefile模板 2. LDD3源码分析之字符设备驱动程序 其他错误: 我的Linux内核为 3.2.0-65-generic-pae,在scull目录下make时

linux设备驱动程序该添加哪些头文件以及驱动常用头文件介绍(转)

原文链接:http://blog.chinaunix.net/uid-22609852-id-3506475.html 驱动常用头文件介绍 #include <linux/***.h> 是在linux-2.6.29/include/linux下面寻找源文件.#include <asm/***.h> 是在linux-2.6.29/arch/arm/include/asm下面寻找源文件.#include <mach/***.h> 是在linux-2.6.29/arch/ar

Linux设备驱动程序学习笔记(一)

1.设备驱动程序扮演的角色:       设备程序是一个独立的“黑盒子”,使其某个特定硬件响应一个定义良好的内部编程接口,这些接口完全隐藏了设备的工作细节.用户的操作通过一组标准化的调用执行,而这些调用独立于特定的驱动程序.将这些调用映射到作用于实际硬件的设备特有操作上,则是设备驱动程序的任务.2.驱动程序的作用:        驱动程序应该处理如何使用硬件可用的问题,而将怎样使用硬件的问题留给上层应用.(提供机制,而不是策略)3.内核功能划分:        进程管理    内存管理    文

LINUX设备驱动程序笔记(一)设备驱动程序简介

<一>:设备驱动程序的作用 从一个角度看,设备驱动程序的作用在于提供机制,而不是策略.在编写驱动程序时,程序员应该特别注意下面这个基本概念:编写访问硬件的内核代码时,不要给用户强加任何特定策略.因为不同的用户有不同的需求,驱动程序应该处理如何使硬件可用的问题,而将怎样使用硬件的问题留给上层应用程序. 从另一个角度来看驱动程序,它还可以看作是应用程序和实际设备之间的一个软件层. 总的来说,驱动程序设计主要还是综合考虑下面三个方面的因素:提供给用户尽量多的选项.编写驱动程序要占用的时间以及尽量保持

LINUX设备驱动程序笔记(二)构造和运行模块

         <一>:设置测试系统 首先准备好一个内核源码树,构造一个新内核,然后安装到自己的系统中.           <二>:HelloWorld模块 #include <linux/init.h> //定义了驱动的初始化和退出相关的函数 #include <linux/module.h> //定义了内核模块相关的函数.变量及宏 MODULE_LICENSE("Dual BSD/GPL"); //该宏告诉内核,该模块采用自由许可

LINUX设备驱动程序笔记(四)并发和竞态

       <一>.并发及其管理 大部分竞态可通过使用内核的并发控制原语,并应用几个基本的原理来避免.第一个规则是,只要可能,就应该避免资源的共享,这种思想的明显应用就是避免使用全局变量.但硬件资源本质上就是共享的,软件资源经常需要对其他执行线程可用.全局变量并不是共享数据的唯一途径,只要我们的代码将一个指针传递给了内核的其他部分,一个新的共享就可能建立.在单个执行线程之外共享硬件或软件资源的任何时候,因为另外一个线程可能产生对该资源的不一致观察,因此必须显示地管理对该资源的访问.访问管理的