内核代码中使用了一些显著的习惯用语,本节将介绍常用的几个。当你通读源程序代码时,真正重要的问题是并不在这些习惯用语本身,而是这种类型的习惯用语的确存在,而且是不断被使用和发展的。如果你需要编写内核代码,你应该注意到内核中所使用的习惯用语,并把这些习惯用语应用到你的代码中。当通读本书(或者代码)时,注意你还能找到多少习惯用语。
为了讨论这些习惯用语,我们首先需要对它们进行命名。为了便于讨论,笔者创造了这些名字。而在实际中,大家不一定非要参考这些用语,它们只是对内核工作方式的描述而已。
一个普通的习惯用语笔者称之为“资源获取”(resource acquisition idiom)。在这个用语中,一个函数必须实现一系列资源的获取,包括内存、锁等等(这些资源的类型未必相同)。只有成功地获取当前所需要的资源之后,才能处理后面的资源请求。最后,该函数还必须释放所有已经获取的资源,而不必对没有获取的资源进行考虑。
我采用“错误变量”这一用语(error variable idiom)来辅助说明资源获取用语,它使用一个临时变量来记录函数的期望返回值。当然,相当多的函数都能实现这个功能。但是错误变量的不同点在于它通常是用来处理由于速度的因素而变得非常复杂的流程控制中的问题。错误变量有两个典型的值,0(表示成功)和负数(表示有错)。
这两个用语结合使用,我们就可以十分自然地得到符合模式的代码如下:
Int f (void)
{
int err;
resource *r1, *r2;
err = -ERR1 /*assume failure*/
r1=acquire_ resource();
if (!r1) /*not aquired*/
goto out /*returns -ERR1*/
Got resource r1,try for r2.*/
err = - ERR2;
r2 = acquire_ resource2();
if (!r2) /*not aquired*/
goto out1 /*returns –ERR2*/
/*have both r1 and r2.*/
err = 0;
/* … use r1 and r2 … */
out2:
release_resource(r2)
out2:
release_resource(r2)
out:
return err;
}
(注意变量err是使用错误变量的一个明确实例,同样,诸如out之类的标号则指明了资源获取用语的使用。)
如果执行到标号out2,则都已经获取了r1和r2资源,而且也都需要进行释放。如果执行到标号out1(不管是顺序执行还是使用goto语句进行跳转到),则r2资源是无效的(也可能刚被释放),但是r1资源却是有效的,而且必需在此将其释放。同理,如果标号out能被执行,则r1和r2资源都无效,err所返回的是错误或成功标志。
在这个简单的例子中,对于err的一些赋值是没有必要的。在实践中,实际代码必须遵守这种模式。这样做的原因主要在于同一行中可能包含有多种测试,而这些测试应该返回相同的错误代码,因此对错误变量统一赋值要比多次赋值更为简单。
文章评论(0条评论)
登录后参与讨论