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

📄 ch15s03.html

📁 Linux设备驱动经典
💻 HTML
📖 第 1 页 / 共 2 页
字号:
 return my_read(iocb-&gt;ki_filp, buffer, count, &amp;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 + -