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

📄 ch14.html

📁 介绍Linux内核驱动编程的一本书 最主要的是有源代码,都是可用的 学习操作系统很好
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Referencecountmanipulation.sect"></a>14.1.1.3.&#160;引用计数的操作</h4></div></div></div><p>一个 kobject 的其中一个关键函数是作为一个引用计数器, 给一个它被嵌入的对象. 只要对这个对象的引用存在, 这个对象( 和支持它的代码) 必须继续存在. 来操作一个 kobject 的引用计数的低级函数是:</p><pre class="programlisting">struct kobject *kobject_get(struct kobject *kobj);void kobject_put(struct kobject *kobj);</pre><p>一个对 kobject_get 的成功调用递增 kobject 的 引用计数并且返回一个指向 kobject 的指针. 如果, 但是, 这个 kobject 已经在被销毁的过程中, 这个操作失败, 并且 kobject_get 返回 NULL. 这个返回值必须总是被测试, 否则可能导致无法结束的令人不愉快的竞争情况.</p><p>当一个引用被释放, 对 kobject_put 的调用递减引用计数, 并且可能地, 释放这个对象. 记住 kobject _init 设置这个引用计数为 1; 因此当你创建一个 kobject, 你应当确保对应地采取 kobject_put 调用, 当这个初始化引用不再需要.</p><p>注意, 在许多情况下, 在 kobject 自身中的引用计数可能不足以阻止竞争情况. 一个 kobject 的存在( 以及它的包含结构 ) 可能非常, 例如, 需要创建这个 kobject 的模块的继续存在. 在这个 kobject 仍然在被传送时不能卸载那个模块. 这是为什么我们上面看到的 cdev 结构包含一个 struct module 指针. struct cdev 的引用计数实现如下:</p><pre class="programlisting">struct kobject *cdev_get(struct cdev *p) { struct module *owner = p-&gt;owner; struct kobject *kobj; if (owner &amp;&amp; !try_module_get(owner)) return NULL; kobj = kobject_get(&amp;p-&gt;kobj); if (!kobj) module_put(owner); return kobj;}</pre><p>创建一个对 cdev 结构的引用还需要创建一个对拥有它的模块的引用. 因此, cdev_get 使用 try_module_get 来试图递增这个模块的使用计数. 如果这个操作成功, kobject_get 被同样用来递增 kobject 的引用计数. 那个操作可能失败, 当然, 因此这个代码检查自 kobject_get 的返回值并且释放它的对模块的引用如果事情没有解决.</p></div><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Releasefunctionsandkobjecttypes.sect"></a>14.1.1.4.&#160;释放函数和 kobject 类型</h4></div></div></div><p>讨论中仍然缺失的一个重要事情是当一个 kobject 的引用计数到 0 时会发生什么. 创建 kobject 的代码通常不知道什么时候要发生这个情况; 如果它知道, 在第一位使用一个引用计数就没有意义了. 即便当引入 sysfs 时可预测的对象生命周期变得更加复杂; 用户空间程序可保持一个对 kobject 的引用( 通过保持一个它的关联的 sysfs 文件打开 )一段任意的时间.</p><p>最后的结果是一个被 kobject 保护的结构无法在任何一个单个的, 可预测的驱动生命周期中的点被释放, 但是可以在必须准备在 kobject 的引用计数到 0 的任何时刻运行的代码中. 引用计数不在创建 kobject 的代码的直接控制之下. 因此这个代码必须被异步通知, 无论何时对它的 kobject 的最后引用消失.</p><p>这个通知由 kobject 的一个释放函数来完成. 常常地, 这个方法有一个形式如下:</p><pre class="programlisting">void my_object_release(struct kobject *kobj){ struct my_object *mine = container_of(kobj, struct my_object, kobj); /* Perform any additional cleanup on this object, then... */ kfree(mine);}</pre><p>要强调的重要一点是: 每个 kobject 必须有一个释放函数, 并且这个 kobject 必须持续( 以一致的状态 ) 直到这个方法被调用. 如果这些限制不满足, 代码就有缺陷. 当这个对象还在使用时被释放会有风险, 或者在最后引用被返回后无法释放对象.</p><p>有趣的是, 释放方法没有存储在 kobject 自身里面; 相反, 它被关联到包含 kobject 的结构类型中. 这个类型被跟踪, 用一个 struct kobj_type 结构类型, 常常简单地称为一个 "ktype". 这个结构看来如下:</p><pre class="programlisting">struct kobj_type { void (*release)(struct kobject *); struct sysfs_ops *sysfs_ops; struct attribute **default_attrs;};</pre><p>在 struct kobj_type 中的 release 成员是, 当然, 一个指向这个 kobject 类型的 release 方法的指针. 我们将回到其他 2 个成员( sysfs_ops 和 default_attrs )在本章后面.</p><p>每一个 kobject 需要有一个关联的 kobj_type 结构. 易混淆地, 指向这个结构的指针能在 2 个不同的地方找到. kobject 结构自身包含一个成员(称为 ktype)包含这个指针. 但是, 如果这个 kobject 是一个 kset 的成员, kobj_type 指针由 kset 提供. ( 我们将在下一节查看 ksets. ) 其间, 这个宏定义:</p><pre class="programlisting">struct kobj_type *get_ktype(struct kobject *kobj); finds the kobj_type pointer for a given kobject. </pre></div></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="KobjectHierachiesKsetsandSubsystems.sect"></a>14.1.2.&#160;kobject 层次, kset, 和子系统</h3></div></div></div><p>kobject 结构常常用来连接对象到一个层级的结构中, 匹配正被建模的子系统的结构. 有 2 个分开的机制对于这个连接: parent 指针和 ksets.</p><p>在结构 kobject 中的 parent 成员是一个指向其他对象的指针 -- 代表在层次中之上的下一级. 如果, 例如, 一个 kobject 表示一个 USB 设备, 它的 parent 指针可能指示这个设备被插入的 hub.</p><p>parent 指针的主要用途是在 sysfs 层次中定位对象. 我们将看到这个如何工作, 在"低级 sysfs 操作"一节中.</p><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Ksets.sect"></a>14.1.2.1.&#160;Ksets 对象</h4></div></div></div><p>很多情况, 一个 kset 看来象一个 kobj_type 结构的扩展; 一个 kset 是一个嵌入到相同类型结构的 kobject 的集合. 但是, 虽然 struct kobj_type 关注的是一个对象的类型, struct kset 被聚合和集合所关注. 这 2 个概念已被分开以至于一致类型的对象可以出现在不同的集合中.</p><p>因此, 一个 kset 的主要功能是容纳; 它可被当作顶层的给 kobjects 的容器类. 实际上, 每个 kset 在内部容纳它自己的 kobject, 并且它可以, 在许多情况下, 如同一个 kobject 相同的方式被对待. 值得注意的是 ksets 一直在 sysfs 中出现; 一旦一个 kset 已被建立并且加入到系统, 会有一个 sysfs 目录给它. kobjects 没有必要在 sysfs 中出现, 但是每个是 kset 成员的 kobject 都出现在那里.</p><p>增加一个 kobject 到一个 kset 常常在一个对象创建时完成; 它是一个 2 步的过程. kobject 的 kset 成员必须 ???; 接着kobject 应当被传递到:</p><pre class="programlisting">int kobject_add(struct kobject *kobj); </pre><p>如常, 程序员应当小心这个函数可能失败(在这个情况下它返回一个负错误码)并且相应地反应. 有一个内核提供的方便函数:</p><pre class="programlisting">extern int kobject_register(struct kobject *kobj); </pre><p>这个函数仅仅是一个 kobject_init 和 kobject_add 的结合.</p><p>当一个 kobject 被传递给 kobject_add, 它的引用计数被递增. kset 中容纳的, 毕竟, 是一个对这个对象的引用. 某种意义上, kobject 可能要必须从 kset 中移出来清除这个引用; 完成这个使用:</p><pre class="programlisting">void kobject_del(struct kobject *kobj); </pre><p>还有一个 kobject_unregister 函数, 是 kobject_del 和 kobject_put 的结合.</p><p>一个 kset 保持它的子女在一个标准的内核链表中. 在大部分情况下, 被包含的 kobjects 也有指向这个 kset 的指针( 或者, 严格地, 它的嵌入 kobject)在它们的 parent 的成员. 因此, 典型地, 一个 kset 和它的 kobjects 看来有些象你在图 <a href="ch14.html#ldd3-14-2.fig" title="图&#160;14.2.&#160;一个简单的 kset 层次">一个简单的 kset 层次</a>中所见. 记住:</p><div class="figure"><a name="ldd3-14-2.fig"></a><p class="title"><b>图&#160;14.2.&#160;一个简单的 kset 层次</b></p><div><img src="images/snagitldd3/ldd3-14-2.png" alt="一个简单的 kset 层次"></div></div><div class="itemizedlist"><ul type="disc"><li><p>图表中的所有的被包含的 kobjects 实际上被嵌入在一些其他类型中, 甚至可能其他的 ksets.</p></li><li><p>一个 kobject 的 parent 不要求是包含 kset( 尽管任何其他的组织可能是奇怪的和稀少的).</p></li></ul></div></div><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Operationsonksets.sect"></a>14.1.2.2.&#160;ksets 之上的操作</h4></div></div></div><p>对于初始化和设置, ksets 有一个接口非常类似于 kobjects. 下列函数存在:</p><pre class="programlisting">void kset_init(struct kset *kset);int kset_add(struct kset *kset);int kset_register(struct kset *kset);void kset_unregister(struct kset *kset);</pre><p>对大部分, 这些函数只是在 kset 的嵌入对象上调用类似的 kobject_ 函数.</p><p>为管理 ksets 的引用计数, 情况大概相同:</p><pre class="programlisting">struct kset *kset_get(struct kset *kset);void kset_put(struct kset *kset);</pre><p>一个 kset 还有一个名子, 存储于嵌入的 kobject. 因此, 如果你有一个 kset 称为 my_set, 你将设置它的名子用:</p><pre class="programlisting">kobject_set_name(&amp;my_set-&gt;kobj, "The name");</pre><p>ksets 还有一个指针( 在 ktye 成员 )指向 kobject_type 结构来描述它包含的 kobject. 这个类型优先于在 kobject 自身中的 ktype 成员. 结果, 在典型的应用中, 在 struct kobject 中的 ktype 成员被留为 NULL, 因为 kset 中的相同成员是实际使用的那个.</p><p>最后, 一个 kset 包含一个子系统指针(称为 subsys). 因此是时候讨论子系统了.</p></div><div class="sect3" lang="zh-cn"><div class="titlepage"><div><div><h4 class="title"><a name="Subsystems.sect"></a>14.1.2.3.&#160;子系统</h4></div></div></div><p>一个子系统是作为一个整体对内核一个高级部分的代表. 子系统常常(但是不是一直)出现在 sysfs 层次的顶级. 一些内核中的例子子系统包括 block_subsys(/sys/block, 给块设备), devices_subsys(/sys/devices, 核心设备层次), 以及一个特殊子系统给每个内核已知的总线类型. 一个驱动作者几乎从不需要创建一个新子系统; 如果你想这样做, 再仔细想想. 你可能需要什么, 最后, 是增加一个新类别, 如同在"类别"一节中描述的.</p><p>一个子系统由一个简单结构代表:</p><pre class="programlisting">struct subsystem { struct kset kset; struct rw_semaphore rwsem; }; </pre><p>一个子系统, 因此, 其实只是一个对 kset 的包装, 有一个旗标丢在里面.</p><p>每个 kset 必须属于一个子系统. 子系统成员关系帮助建立 kset 的位置在层次中, 但是, 更重要的, 子系统的 rwsem 旗标用来串行化对 kset 的内部链表的存取. 这个成员关系由在 struct kset 中的 subsys 指针所表示. 因此, 可以从 kset 的结构找到每个 kset 的包含子系统, 但是却无法直接从子系统结构发现多个包含在子系统中的 kset. </p><p>子系统常常用一个特殊的宏声明:</p><pre class="programlisting">decl_subsys(name, struct kobj_type *type, struct kset_hotplug_ops *hotplug_ops);</pre><p>这个宏创建一个 struct subsystem 使用一个给这个宏的名子并后缀以 _subsys 而形成的名子. 这个宏还初始化内部的 kset 使用给定的 type 和 hotplug_ops. ( 我们在本章后面讨论热插拔操作). </p><p>子系统有通常的建立和拆卸函数:</p><pre class="programlisting">void subsystem_init(struct subsystem *subsys);int subsystem_register(struct subsystem *subsys);void subsystem_unregister(struct subsystem *subsys);struct subsystem *subsys_get(struct subsystem *subsys)void subsys_put(struct subsystem *subsys);</pre><p>大部分这些操作只是作用在子系统的 kset上.</p></div></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch13s06.html">上一页</a>&#160;</td><td width="20%" align="center">&#160;</td><td width="40%" align="right">&#160;<a accesskey="n" href="ch14s02.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">13.6.&#160;快速参考&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top">&#160;14.2.&#160;低级 sysfs 操作</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 + -