⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch06s03.html

📁 介绍Linux设备驱动开发
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>6.3.&#160;poll 和 select-Linux设备驱动第三版(中文版)-开发频道-华星在线</title>
<meta name="description" content="驱动开发-开发频道-华星在线" />
<meta name="keywords" content="Linux设备驱动,中文版,第三版,ldd,linux device driver,驱动开发,电子版,程序设计,软件开发,开发频道" />
<meta name="author" content="华星在线 www.21cstar.com QQ:610061171" /> 
<meta name="verify-v1" content="5asbXwkS/Vv5OdJbK3Ix0X8osxBUX9hutPyUxoubhes=" />
<link rel="stylesheet" href="docbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.69.0">
<link rel="start" href="index.html" title="Linux 设备驱动 Edition 3">
<link rel="up" href="ch06.html" title="第&#160;6&#160;章&#160;高级字符驱动操作">
<link rel="prev" href="ch06s02.html" title="6.2.&#160;阻塞 I/O">
<link rel="next" href="ch06s04.html" title="6.4.&#160;异步通知">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">6.3.&#160;poll 和 select</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="ch06s02.html">上一页</a>&#160;</td>
<th width="60%" align="center">第&#160;6&#160;章&#160;高级字符驱动操作</th>
<td width="20%" align="right">&#160;<a accesskey="n" href="ch06s04.html">下一页</a>
</td>
</tr>
</table>
<hr>
</div>
<div class="sect1" lang="zh-cn">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="pollandselect.sect1"></a>6.3.&#160;poll 和 select</h2></div></div></div>
<p>使用非阻塞 I/O 的应用程序常常使用 poll, select, 和 epoll 系统调用. poll, select 和 epoll 本质上有相同的功能: 每个允许一个进程来决定它是否可读或者写一个或多个文件而不阻塞. 这些调用也可阻塞进程直到任何一个给定集合的文件描述符可用来读或写. 因此, 它们常常用在必须使用多输入输出流的应用程序, 而不必粘连在它们任何一个上. 相同的功能常常由多个函数提供, 因为 2 个是由不同的团队在几乎相同时间完成的: select 在 BSD Unix 中引入, 而 poll 是 System V 的解决方案. epoll 调用<sup>[<a name="id436502" href="#ftn.id436502">23</a>]</sup>添加在 2.5.45, 作为使查询函数扩展到几千个文件描述符的方法.</p>
<p>支持任何一个这些调用都需要来自设备驱动的支持. 这个支持(对所有 3 个调用)由驱动的 poll 方法调用. 这个方法由下列的原型:</p>
<pre class="programlisting">
unsigned int (*poll) (struct file *filp, poll_table *wait); 
</pre>
<p>这个驱动方法被调用, 无论何时用户空间程序进行一个 poll, select, 或者 epoll 系统调用, 涉及一个和驱动相关的文件描述符. 这个设备方法负责这 2 步:</p>
<div class="itemizedlist"><ul type="disc">
<li><p>1. 在一个或多个可指示查询状态变化的等待队列上调用 poll_wait. 如果没有文件描述符可用作 I/O, 内核使这个进程在等待队列上等待所有的传递给系统调用的文件描述符. </p></li>
<li><p>2. 返回一个位掩码, 描述可能不必阻塞就立刻进行的操作.</p></li>
</ul></div>
<p>这 2 个操作常常是直接的, 并且趋向与各个驱动看起来类似. 但是, 它们依赖只能由驱动提供的信息, 因此, 必须由每个驱动单独实现.</p>
<p>poll_table 结构, 给 poll 方法的第 2 个参数, 在内核中用来实现 poll, select, 和 epoll 调用; 它在 &lt;linux/poll.h&gt;中声明, 这个文件必须被驱动源码包含. 驱动编写者不必要知道所有它内容并且必须作为一个不透明的对象使用它; 它被传递给驱动方法以便驱动可用每个能唤醒进程的等待队列来加载它, 并且可改变 poll 操作状态. 驱动增加一个等待队列到 poll_table 结构通过调用函数 poll_wait:</p>
<pre class="programlisting">
 void poll_wait (struct file *, wait_queue_head_t *, poll_table *); 
</pre>
<p>poll 方法的第 2 个任务是返回位掩码, 它描述哪个操作可马上被实现; 这也是直接的. 例如, 如果设备有数据可用, 一个读可能不必睡眠而完成; poll 方法应当指示这个时间状态. 几个标志(通过 &lt;linux/poll.h&gt; 定义)用来指示可能的操作:</p>
<div class="variablelist"><dl>
<dt><span class="term">POLLIN <span></span></span></dt>
<dd><p>如果设备可被不阻塞地读, 这个位必须设置.</p></dd>
<dt><span class="term">POLLRDNORM <span></span></span></dt>
<dd><p>这个位必须设置, 如果"正常"数据可用来读. 一个可读的设备返回(	POLLIN|POLLRDNORM ).</p></dd>
<dt><span class="term">POLLRDBAND <span></span></span></dt>
<dd><p>这个位指示带外数据可用来从设备中读取. 当前只用在 Linux 内核的一个地方( DECnet 代码 )并且通常对设备驱动不可用.</p></dd>
<dt><span class="term">POLLPRI <span></span></span></dt>
<dd><p>高优先级数据(带外)可不阻塞地读取. 这个位使 select 报告在文件上遇到一个异常情况, 因为 selct 报告带外数据作为一个异常情况.</p></dd>
<dt><span class="term">POLLHUP<span></span></span></dt>
<dd><p>当读这个设备的进程见到文件尾, 驱动必须设置 POLLUP(hang-up). 一个调用 select 的进程被告知设备是可读的, 如同 selcet 功能所规定的.</p></dd>
<dt><span class="term">POLLERR <span></span></span></dt>
<dd><p>一个错误情况已在设备上发生. 当调用 poll, 设备被报告位可读可写, 因为读写都返回一个错误码而不阻塞.</p></dd>
<dt><span class="term">POLLOUT <span></span></span></dt>
<dd><p>这个位在返回值中设置, 如果设备可被写入而不阻塞.</p></dd>
<dt><span class="term">POLLWRNORM<span></span></span></dt>
<dd><p>这个位和 POLLOUT 有相同的含义, 并且有时它确实是相同的数. 一个可写的设备返回( POLLOUT|POLLWRNORM).</p></dd>
<dt><span class="term">POLLWRBAND<span></span></span></dt>
<dd><p>如同 POLLRDBAND , 这个位意思是带有零优先级的数据可写入设备. 只有 poll 的数据报实现使用这个位, 因为一个数据报看传送带外数据.</p></dd>
</dl></div>
<p>应当重复一下 POLLRDBAND 和 POLLWRBAND 仅仅对关联到 socket 的文件描述符有意义: 通常设备驱动不使用这些标志.</p>
<p>poll 的描述使用了大量在实际使用中相对简单的东西. 考虑 poll 方法的 scullpipe 实现:</p>
<pre class="programlisting">
static unsigned int scull_p_poll(struct file *filp, poll_table *wait)
{
        struct scull_pipe *dev = filp-&gt;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(&amp;dev-&gt;sem);
        poll_wait(filp, &amp;dev-&gt;inq,  wait);
        poll_wait(filp, &amp;dev-&gt;outq, wait);
        if (dev-&gt;rp != dev-&gt;wp)
                mask |= POLLIN | POLLRDNORM;  /* readable */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -