Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is "for_each_possible_cpu" expanded in cpufreq.c file?

I was browsing through driver/cpufreq/cpufreq.c to understand how it works. I came across this piece of code which I could not understand.

In cpufreq_core_init :

for_each_possible_cpu(cpu) {
        per_cpu(cpufreq_policy_cpu, cpu) = -1;
        init_rwsem(&per_cpu(cpu_policy_rwsem, cpu));
}

When I looked through the defined macro,

#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)

My questions:

  1. How does for_each_possible_cpu expand?
  2. Why are two others #defines are called inside?
  3. Why is the per_cpu output equated to -1?
like image 863
0x07FC Avatar asked Dec 07 '22 08:12

0x07FC


1 Answers

  1. How does it expand:

Keep in mind anytime you ask something like that wrt the Linux kernel, the answer is never easy... so... here we go:

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

You can see that this macro is really just a for loop, called with an iterator as cpu the for_each_cpu is another macro which is the looping part defined as:

#define for_each_cpu(cpu, mask)                 \
     for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)

And the cpu_possible_mask is a pointer to a struct:

extern const struct cpumask *const cpu_possible_mask;

Which is seen here (consisting of another macro):

typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;

That contains another macro (DECLARE_BITMAP) and it has another #define for NR_CPUS, that is the number of CPUs in the system, it should be system dependent and set in the kconfig. The macro in there is really just an array and an accessor:

#define DECLARE_BITMAP(name,bits) \
      unsigned long name[BITS_TO_LONGS(bits)]

So you can see that's the array and the accessor which of course consists of another #define:

#define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))

...which consists of two more #defines:

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8

Anyway... you can see that (A) this is a mess and (B) it ends up being a for loop that increments number of CPUs but also issues a second iterative action via the comma operator. How exactly the second operator words itself out is system dependent. (what's the sizeof a long on your system? what's the number of cpus on your system?)

2.Why are two others #defines are called inside?

That's kind of answered by #1. Since it expands to a for loop, you need that loop to do something.

3.Why is the per_cpu output equated to -1?

The per_cpu macro is giving a pointer to the CPU frequency policy of each CPU in the system, that is being initialized to -1. I'd have to do more research to be sure, but presumably they picked that because of the define:

#define CPUFREQ_ETERNAL                 (-1)

And the __init_rwsem is an architecture defined way of initializing the read/write semaphore used for each CPU's policy.

I don't know if that explanation helped much, but at least maybe it helps point you in a better direction. Good luck exploring the kernel.

like image 155
Mike Avatar answered Dec 08 '22 20:12

Mike