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

📄 ch05s03.html

📁 介绍Linux内核驱动编程的一本书 最主要的是有源代码,都是可用的 学习操作系统很好
💻 HTML
📖 第 1 页 / 共 2 页
字号:
    int quantum; /* the current quantum size */    int qset; /* the current array size */    unsigned long size; /* amount of data stored here */    unsigned int access_key; /* used by sculluid and scullpriv */    struct semaphore sem; /* mutual exclusion semaphore */    struct cdev cdev; /* Char device structure */};</pre><p>到结构的底部是一个称为 sem 的成员, 当然, 它是我们的旗标. 我们已经选择为每个虚拟 scull 设备使用单独的旗标. 使用一个单个的全局的旗标也可能会是同样正确. 通常各种 scull 设备不共享资源, 然而, 并且没有理由使一个进程等待, 而另一个进程在使用不同 scull 设备. 不同设备使用单独的旗标允许并行进行对不同设备的操作, 因此, 提高了性能.</p><p>旗标在使用前必须初始化. scull 在加载时进行这个初始化, 在这个循环中:</p><pre class="programlisting">for (i = 0; i &lt; scull_nr_devs; i++) {    scull_devices[i].quantum = scull_quantum;    scull_devices[i].qset = scull_qset;    init_MUTEX(&amp;scull_devices[i].sem);    scull_setup_cdev(&amp;scull_devices[i], i);}</pre><p>注意, 旗标必须在 scull 设备对系统其他部分可用前初始化. 因此, init_MUTEX 在 scull_setup_cdev 前被调用. 以相反的次序进行这个操作可能产生一个竞争情况, 旗标可能在它准备好之前被存取.</p><p>下一步, 我们必须浏览代码, 并且确认在没有持有旗标时没有对 scull_dev 数据结构的存取. 因此, 例如, scull_write 以这个代码开始:</p><pre class="programlisting">if (down_interruptible(&amp;dev-&gt;sem))    return -ERESTARTSYS;</pre><p>注意对 down_interruptible 返回值的检查; 如果它返回非零, 操作被打断了. 在这个情况下通常要做的是返回 -ERESTARTSYS. 看到这个返回值后, 内核的高层要么从头重启这个调用要么返回这个错误给用户. 如果你返回 -ERESTARTSYS, 你必须首先恢复任何用户可见的已经做了的改变, 以保证当重试系统调用时正确的事情发生. 如果你不能以这个方式恢复, 你应当替之返回 -EINTR. </p><p>scull_write 必须释放旗标, 不管它是否能够成功进行它的其他任务. 如果事事都顺利, 执行落到这个函数的最后几行:</p><pre class="programlisting">out: up(&amp;dev-&gt;sem); return retval; </pre><p>这个代码释放旗标并且返回任何需要的状态. 在 scull_write 中有几个地方可能会出错; 这些地方包括内存分配失败或者在试图从用户空间拷贝数据时出错. 在这些情况中, 代码进行了一个 goto out, 以确保进行正确的清理.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="ReaderWriterSemphores.sect"></a>5.3.3.&#160;读者/写者旗标</h3></div></div></div><p>旗标为所有调用者进行互斥, 不管每个线程可能想做什么. 然而, 很多任务分为 2 种清楚的类型: 只需要读取被保护的数据结构的类型, 和必须做改变的类型. 允许多个并发读者常常是可能的, 只要没有人试图做任何改变. 这样做能够显著提高性能; 只读的任务可以并行进行它们的工作而不必等待其他读者退出临界区.</p><p>Linux 内核为这种情况提供一个特殊的旗标类型称为 rwsem (或者" reader/writer semaphore"). rwsem 在驱动中的使用相对较少, 但是有时它们有用.</p><p>使用 rwsem 的代码必须包含 &lt;linux/rwsem.h&gt;. 读者写者旗标 的相关数据类型是 struct rw_semaphore; 一个 rwsem 必须在运行时显式初始化:</p><pre class="programlisting">void init_rwsem(struct rw_semaphore *sem); </pre><p>一个新初始化的 rwsem 对出现的下一个任务( 读者或者写者 )是可用的. 对需要只读存取的代码的接口是:</p><pre class="programlisting">void down_read(struct rw_semaphore *sem);int down_read_trylock(struct rw_semaphore *sem);void up_read(struct rw_semaphore *sem);</pre><p>对 down_read 的调用提供了对被保护资源的只读存取, 与其他读者可能地并发地存取. 注意 down_read 可能将调用进程置为不可中断的睡眠. down_read_trylock 如果读存取是不可用时不会等待; 如果被准予存取它返回非零, 否则是 0. 注意 down_read_trylock 的惯例不同于大部分的内核函数, 返回值 0 指示成功. 一个使用 down_read 获取的 rwsem 必须最终使用 up_read 释放.</p><p>读者的接口类似:</p><pre class="programlisting">void down_write(struct rw_semaphore *sem);int down_write_trylock(struct rw_semaphore *sem);void up_write(struct rw_semaphore *sem);void downgrade_write(struct rw_semaphore *sem);</pre><p>down_write, down_write_trylock, 和 up_write 全部就像它们的读者对应部分, 除了, 当然, 它们提供写存取. 如果你处于这样的情况, 需要一个写者锁来做一个快速改变, 接着一个长时间的只读存取, 你可以使用 downgrade_write 在一旦你已完成改变后允许其他读者进入.</p><p>一个 rwsem 允许一个读者或者不限数目的读者来持有旗标. 写者有优先权; 当一个写者试图进入临界区, 就不会允许读者进入直到所有的写者完成了它们的工作. 这个实现可能导致读者饥饿 -- 读者被长时间拒绝存取 -- 如果你有大量的写者来竞争旗标. 由于这个原因, rwsem 最好用在很少请求写的时候, 并且写者只占用短时间.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch05s02.html">上一页</a>&#160;</td><td width="20%" align="center"><a accesskey="u" href="ch05.html">上一级</a></td><td width="40%" align="right">&#160;<a accesskey="n" href="ch05s04.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">5.2.&#160;并发和它的管理&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top">&#160;5.4.&#160;Completions 机制</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 + -