为什么要包装函数?

Why wrap functions?

为什么 Linux 内核有时会实现一个函数的多个版本,这些函数的名称非常相似,只是包装了另一个函数?例如,here:

static void clocksource_select(void)
{
    __clocksource_select(false);
}

static void clocksource_select_fallback(void)
{
    __clocksource_select(true);
}

你举的例子不是一个很好的例子,因为它与Linux内核无关。这只是基本的软件工程。

当您有两个功能需要非常接近的功能时,您可以采用多种途径。

  1. 您可以实现该功能两次。我们不喜欢这样做,因为它会造成代码重复。这也意味着如果你需要在代码的公共区域更改一些东西,你需要记住在两个地方进行更改。

  2. 您可以将公共代码拆分成它自己的函数,然后从每个函数中调用该函数。这是最好的解决方案如果可能的话。问题是这并不总是可能的。这可能是不可能的,因为公共代码需要太多的上下文,或者因为它需要分散到整个函数中。这将我们带到:

  3. 创建一个内部 "common" 函数,用一个参数告诉要提供的功能。只需编写代码,然后在两个函数需要执行不同操作的地方放置一个 if。这是内核在您的示例中采用的路径。

话虽如此,还有另一种情况,特定于 Linux 内核,其中两个功能确实看起来几乎相同。在i386平台上,stat系统调用实现的不是两次,而是三次:

  • oldstat 系统调用号 18
  • stat 系统调用号 106
  • stat64 系统调用编号 195

原因是 Linux 内核承诺完全向后兼容其用户 space 内核接口。当一个函数由于某种原因必须被取代时,就像 stat 发生的不是一次,而是 两次 (如果算上 fstatat 是三次),旧系统呼叫条目需要保留并保持可操作性。

但是,如果您查看实际实现,您会发现它们之间几乎没有区别,而且它们最终都调用了几乎相同的函数。