“是怎么回事?”;对于“每个”可能的“cpu”;是否在cpufreq.c文件中展开?

“是怎么回事?”;对于“每个”可能的“cpu”;是否在cpufreq.c文件中展开?,c,linux-kernel,linux-device-driver,C,Linux Kernel,Linux Device Driver,我浏览了driver/cpufreq/cpufreq.c以了解它是如何工作的。我偶然发现了这段我无法理解的代码 在cpufreq\u core\u init中: for_each_possible_cpu(cpu) { per_cpu(cpufreq_policy_cpu, cpu) = -1; init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); } 当我查看定义的宏时 #define for_each_possib

我浏览了driver/cpufreq/cpufreq.c以了解它是如何工作的。我偶然发现了这段我无法理解的代码

cpufreq\u core\u init
中:

for_each_possible_cpu(cpu) {
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
        init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
}
当我查看定义的宏时

#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)

#define per_cpu(var, cpu) \
        (*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))

#define init_rwsem(sem)                                         \
do {                                                            \
        static struct lock_class_key __key;                     \
                                                                \
        __init_rwsem((sem), #sem, &__key);                      \
} while (0)
我的问题是:

  • 每个cpu的
    如何扩展
  • 为什么另外两个
    #defines
    在内部调用
  • 为什么每个cpu的
    输出等于-1

  • 对于_,每个cpu在cpumask.h中定义,并接受两个参数-一个迭代器和一个掩码。掩码是一个cpumask_t左值,它定义了要迭代的CPU集。因此,对于_,每个_可能的_cpu()都会迭代内核启动时可能出现的所有cpu

    每CPU变量是包含系统上每个处理器一个对象的数据数组。 per_cpu宏定义将创建名称,该名称将为系统上的每个处理器保存一个给定类型的对象。以这种方式定义的变量实际上是一个值数组。要获取特定处理器的值,可以使用per_cpu()宏;它作为左值工作,因此类似以下代码的代码可以工作: 每cpu(cpufreq\u策略,cpu)=-1

  • 它如何扩展:
  • 请记住,每当你问Linux内核类似的问题时,答案总是不容易的。。。所以我们开始:

    #define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask)
    
    您可以看到,这个宏实际上只是一个for循环,用迭代器调用为
    cpu
    for\u每个\u cpu
    是另一个宏,它是循环部分,定义为:

    #define for_each_cpu(cpu, mask)                 \
         for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
    
    如下所示(由另一个宏组成):

    它包含另一个宏(
    DECLARE_BITMAP
    ),并且它还有另一个
    \define
    for
    NR_CPU
    ,即系统中的CPU数量,它应该依赖于系统并在kconfig中设置。其中的宏实际上只有一个数组和一个访问器:

    #define DECLARE_BITMAP(name,bits) \
          unsigned long name[BITS_TO_LONGS(bits)]
    
    因此,您可以看到这是数组和访问器,它当然由另一个
    #define
    组成:

    #define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
    
    …由另外两个定义组成:

    #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
    #define BITS_PER_BYTE 8
    
    无论如何。。。您可以看到:(A)这是一个混乱,(B)它最终成为一个
    for
    循环,它增加了CPU的数量,但也通过逗号运算符发出了第二个迭代操作。第二个运算符自身的确切输出方式取决于系统。(您的系统上的long大小是多少?系统上的CPU数量是多少?)

    2.为什么其他两个定义被称为内部定义

    答案是#1。因为它扩展为一个
    for
    循环,所以您需要该循环来做一些事情

    3.为什么每个cpu的输出等于-1

    per_cpu
    宏给出一个指针,指向系统中每个cpu的cpu频率策略,该策略将被初始化为
    -1
    。我必须做更多的研究才能确定,但他们选择这一点大概是因为定义:

    #define CPUFREQ_ETERNAL                 (-1)
    
    \uuuu init\u rwsem
    是一种体系结构定义的方式,用于初始化用于每个CPU策略的读/写信号量


    我不知道这个解释是否有多大帮助,但至少它可以帮助你找到更好的方向。祝您在探索内核时好运。

    Mike answer几乎涵盖了它,除了一点有趣的地方,即用于变量
    cpu可能的掩码的宏(与Mike解释的类型相反)

    因此在
    cpu.c
    中:

    const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
    EXPORT_SYMBOL(cpu_possible_mask);
    
    to_cpumask
    cpumask.h
    中定义如下:

    #define to_cpumask(bitmap)                                              \
            ((struct cpumask *)(1 ? (bitmap)                                \
                                 : (void *)sizeof(__check_is_bitmap(bitmap))))
    
    static inline int __check_is_bitmap(const unsigned long *bitmap)
    {
            return 1;
    }
    
    它看起来很奇怪,因为函数
    check\u是\u bitmap
    一直返回
    1
    ,而且它的结果甚至没有在调用它的宏中使用!编译器将最终优化最终二进制文件中的调用。那么那里可能会发生什么呢

    实际上,该调用不用于运行时,而是用于在编译时检查宏参数
    bitmap
    是否实际为
    unsigned long*
    类型(因此才是只执行该操作的函数的名称)。如果
    bitmap
    的类型错误,将发出警告,内核构建中的编译警告总是一个严重问题


    <> P>本质上,Linux内核家伙把一个普通的非类型宏转换成一个类型化的宏,通常是用C++在模板中完成的。非常整洁。

    谢谢。这确实有助于我理解。我需要探索更多才能理解更多。谢谢你的回答。对于((cpu)=0;(cpu)<1;(cpu)++,(void)mask)
    的内部
    循环条件
    (cpu)<1
    仍然有点混乱。@Mike我刚刚再次检查了每个\u cpu
    宏的
    include/linux/cpumask.h
    中还有另一个定义。这里使用的示例适用于CPU只有一个内核的情况,如果NR_CPU==1
    ,则使用
    控制该内核。谢谢您的回答。但是((cpu)=0;(cpu)<1;(cpu)+,(void)mask)
    的for循环条件
    (cpu)<1
    内部的
    。不确定你对此是否有任何见解?
    
    const struct cpumask *const cpu_possible_mask = to_cpumask(cpu_possible_bits);
    EXPORT_SYMBOL(cpu_possible_mask);
    
    #define to_cpumask(bitmap)                                              \
            ((struct cpumask *)(1 ? (bitmap)                                \
                                 : (void *)sizeof(__check_is_bitmap(bitmap))))
    
    static inline int __check_is_bitmap(const unsigned long *bitmap)
    {
            return 1;
    }