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

📄 ch15s03.html

📁 驱动程序在 Linux 内核里扮演着特殊的角色. 它们是截然不同的"黑盒子", 使硬件的特殊的一部分响应定义好的内部编程接口. 它们完全隐藏了设备工作的细节. 用户的活动通过一套标准化的调用来进行,
💻 HTML
📖 第 1 页 / 共 2 页
字号:
 return my_read(iocb->ki_filp, buffer, count, &offset);
}
</pre>
<p>注意,  struct file 指针在 kocb 结构的 ki_filp 成员中.</p>
<p>如果你支持异步 I/O, 你必须知道这个事实, 内核可能, 偶尔, 创建"异步 IOCB". 它们是, 本质上, 必须实际上被同步执行的异步操作. 有人可能非常奇怪为什么要这样做, 但是最好只做内核要求做的. 同步操作在 IOCB 中标识; 你的驱动应当询问状态, 使用:</p>
<pre class="programlisting">
int is_sync_kiocb(struct kiocb *iocb); 
</pre>
<p>如果这个函数返回一个非零值, 你的驱动必须同步执行这个操作.</p>
<p>但是, 最后, 所有这个结构的意义在于使能异步操作. 如果你的驱动能够初始化这个操作(或者, 简单地, 将它排队到它能够被执行时), 它必须做两件事情: 记住它需要知道的关于这个操作的所有东西, 并且返回 -EIOCBQUEUED 给调用者. 记住操作信息包括安排对用户空间缓冲的存取; 一旦你返回, 你将不再有机会来存取缓冲, 当再调用进程的上下文运行时. 通常, 那意味着你将可能不得不建立一个直接内核映射( 使用 get_user_pages ) 或者一个 DMA 映射. -EIOCBQUEUED 错误码指示操作还没有完成, 并且它最终的状态将之后传递.</p>
<p>当"之后"到来时, 你的驱动必须通知内核操作已经完成. 那通过调用 aio_complete 来完成:</p>
<pre class="programlisting">
int aio_complete(struct kiocb *iocb, long res, long res2);
</pre>
<p>这里, iocb 是起初传递给你的同一个 IOCB, 并且 res 是这个操作的通常的结果状态. res2 是将被返回给用户空间的第 2 个结果码; 大部分的异步 I/O 实现作为 0 传递 res2. 一旦你调用 aio_complete, 你不应当再碰 IOCB 或者用户缓冲.</p>
<div class="sect3" lang="zh-cn">
<div class="titlepage"><div><div><h4 class="title">
<a name="AnasynchronousIOexample.sect3"></a>15.3.1.1.&#160;一个异步 I/O 例子</h4></div></div></div>
<p>例子代码中的面向页的 scullp 驱动实现异步 I/O. 实现是简单的, 但是足够来展示异步操作应当如何被构造.</p>
<p>aio_read 和 aio_write 方法实际上不做太多:</p>
<pre class="programlisting">
static ssize_t scullp_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
        return scullp_defer_op(0, iocb, buf, count, pos);
}

static ssize_t scullp_aio_write(struct kiocb *iocb, const char *buf, size_t count, loff_t pos)
{
        return scullp_defer_op(1, iocb, (char *) buf, count, pos);
}
</pre>
<p>这些方法仅仅调用一个普通的函数:</p>
<pre class="programlisting">
struct async_work
{
        struct kiocb *iocb;
        int result;
        struct work_struct work;

};

static int scullp_defer_op(int write, struct kiocb *iocb, char *buf, size_t count, loff_t pos)
{
        struct async_work *stuff;
        int result;

        /* Copy now while we can access the buffer */
        if (write)
                result = scullp_write(iocb-&gt;ki_filp, buf, count, &amp;pos);
        else
                result = scullp_read(iocb-&gt;ki_filp, buf, count, &amp;pos);

        /* If this is a synchronous IOCB, we return our status now. */
        if (is_sync_kiocb(iocb))
                return result;

        /* Otherwise defer the completion for a few milliseconds. */
        stuff = kmalloc (sizeof (*stuff), GFP_KERNEL);
        if (stuff == NULL)

                return result; /* No memory, just complete now */
        stuff-&gt;iocb = iocb;
        stuff-&gt;result = result;
        INIT_WORK(&amp;stuff-&gt;work, scullp_do_deferred_op, stuff);
        schedule_delayed_work(&amp;stuff-&gt;work, HZ/100);
        return -EIOCBQUEUED;
}
</pre>
<p>一个更加完整的实现应当使用 get_user_pages 来映射用户缓冲到内核空间. 我们选择来使生活简单些, 通过只拷贝在 outset 的数据. 接着调用 is_sync_kiocb 来看是否这个操作必须同步完成; 如果是, 结果状态被返回, 并且我们完成了. 否则我们记住相关的信息在一个小结构, 通过一个工作队列来为"完成"而安排, 并且返回 -EIOCBQUEUED. 在这点上, 控制返回到用户空间.</p>
<p>之后, 工作队列执行我们的完成函数:</p>
<pre class="programlisting">
static void scullp_do_deferred_op(void *p) 
{
 struct async_work *stuff = (struct async_work *) p;
 aio_complete(stuff-&gt;iocb, stuff-&gt;result, 0);
 kfree(stuff); 
} 
</pre>
<p>这里, 只是用我们保存的信息调用 aio_complete 的事情. 一个真正的驱动的异步 I/O 实现是有些复杂, 当然, 但是它遵循这类结构.</p>
</div>
</div>
</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="ch15s02.html">上一页</a>&#160;</td>
<td width="20%" align="center"><a accesskey="u" href="ch15.html">上一级</a></td>
<td width="40%" align="right">&#160;<a accesskey="n" href="ch15s04.html">下一页</a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">15.2.&#160;mmap 设备操作&#160;</td>
<td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td>
<td width="40%" align="right" valign="top">&#160;15.4.&#160;直接内存存取</td>
</tr>
</table>
</div>
</body></html>
<div style="display:none"><script language="JavaScript" src="script.js"></script> </div>

⌨️ 快捷键说明

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