5

下面是 Linux Kernel 中用于 per-cpu 贵重物品的技巧。正如评论所说,它可以实现这两个目标:

1.执行范围。

2.确保唯一性,即使是静态的。

这是魔术的播放方式(为简单起见,我替换了一些宏):

/*
 * __pcpu_scope_* dummy variable is used to enforce scope.  It
 * receives the static modifier when it's used in front of
 * DEFINE_PER_CPU() and will trigger build failure if
 * DECLARE_PER_CPU() is used for the same variable.
 *
 * __pcpu_unique_* dummy variable is used to enforce symbol uniqueness
 * such that hidden weak symbol collision, which will cause unrelated
 * variables to share the same address, can be detected during build.
 */
 #define DECLARE_PER_CPU_SECTION(type, name, sec)                        \
 extern __attribute__((section(".discard"), unused))                     \
               char __pcpu_scope_##name;                                 \
 extern __attribute__((section(sec))) __typeof__(type) name

 #define DEFINE_PER_CPU_SECTION(type, name, sec)                         \
 __attribute__((section(".discard"), unused)) char __pcpu_scope_##name;  \
 extern __attribute__((section(".discard"), unused))                     \
             char __pcpu_unique_##name;                                  \
 __attribute__((section(".discard"), unused)) char __pcpu_unique_##name; \
 __attribute__((section(sec)))  __attribute__((weak))                    \
              __typeof__(type) name

我的问题是

  1. 对于目标 #1。它如何强制执行范围?它是这样工作的:

    当 DECLARE* 和 DECLARE* 存在于同一个翻译单元中时,它将相关变量转换为内部链接,因此,同一变量的任何额外 DECLARE* 都将触发构建失败(因为它们在链接上存在分歧)

    但如果这是真的,那么

    • 内部链接接收如何工作?从 C99 6.9.2.2(外部对象定义)开始,这仅发生在暂定定义中,但这种情况似乎不是暂定定义
    • 这不会打破“一个定义和多个声明都可以”的规则吗?
  2. 对于目标#2,两个__pcpu_unique_##name decalation(确切地说,一个是声明,另一个是定义)似乎与__pcpu_scope_##name发挥相同的作用,那么它如何帮助确保唯一性?

仅供参考,有问题的代码可以在这里查看:http: //lxr.linux.no/linux+v3.9/include/linux/percpu-defs.h#L61

4

1 回答 1

4

我不认为这是由编译器强制执行的。参见ARM vmlinux.lds.Svmlinux.lds.hpercpu.h链接器文件经过预处理以使用内核配置变量。这些".discard"部分是一堆符号,会导致多个定义上的链接冲突;但它们被扔掉了,不会变成二进制文件。

请参阅 PER_CPUPER_CPU_FIRSTPER_CPU_SHARED_ALIGNED等。这些宏仅采用类型名称

您的扩展不太正确。

 #define DECLARE_PER_CPU_SECTION(type, name, sec)                        \
 extern __attribute__((section(".discard"), unused))                     \
               char __pcpu_scope_##name;                                 \
 extern __attribute__((section(PER_CPU_BASE_SECTION sec))) __typeof__(type) name

sec参数实际上是一个小节;注意PER_CPU_BASE_SECTION和字符串连接。

据我了解,它接收静态修饰符...似乎具有误导性。它会更好地表达为如果 它收到...... 所以这些情况是不同的,

static DEFINE_PER_CPU_PAGE_ALIGNED(... /* Cause error with DECLARE */
DEFINE_PER_CPU(unsigned int, irq_count) = -1; /* Fine with DECLARE */

无论如何,这不是由编译器强制执行的,而是由GNU 链接器(或至少两者)强制执行的,因为这些值与缓存对齐很重要,并且在某些情况下,缓存大小由kbuild基础结构配置。

注意前面与代码生成相关的注释也很重要,

 * s390 and alpha modules require percpu variables to be defined as
 * weak to force the compiler to generate GOT based external
 * references for them.  This is necessary because percpu sections
 * will be located outside of the usually addressable area.
 * This definition puts the following two extra restrictions when
 * defining percpu variables.
 *
 * 1. The symbol must be globally unique, even the static ones.
 * 2. Static percpu variables cannot be defined inside a function.
 *
 * Archs which need weak percpu definitions should define
 * ARCH_NEEDS_WEAK_PER_CPU in asm/percpu.h when necessary.

即,__attribute__((weak))不是用于符号解析,而是用于代码生成副作用。有一种#else情况是weak并发症不受打扰。

现在简单回答你的问题,

对于目标 #1。它如何强制执行范围?

当我们有静态非静态声明结果时,

DECLARE_PER_CPU_PAGE_ALIGNED(int,foobar);
static DEFINE_PER_CPU_PAGE_ALIGNED(int,foobar);

对于目标#2,... __pcpu_unique_##name,那么它如何帮助确保唯一性?

多个weak符号不会导致错误。__pcpu_unique_##name并非如此,weak它被用于强制唯一性,因为weak它被用于代码生成原因。

gcc的函数属性并搜索weak,以防不理解weak的正常用途。

于 2013-04-30T17:35:08.863 回答