.date.percpu是汇编中的一个数据段:
#define DEFINE_PER_CPU(type, name) __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name
|
上面这段宏,将被扩展为:
_attribute__((__section__(".data.percpu"))) __typeof__(struct runqueue) per_cpu__runqueues
|
就是在 .data.percpu段中定义了一个类型为 struct runqueue 的变量 per_cpu__runqueues ;
这个变量就是一个偏移量,标识该变量的地址。
而 ## 作为连接符, 把宏参数 name 链接成变量 per_cpu__name;
在系统启动后,start_kernel()函数会对每个cpu进行设置:
- 为每一个cpu分配一段专有数据区,然后把 .data.percpu段中的数据拷贝到其中,每个cpu各一份。
- 由于复制给了每个cpu各一份,所以存取其中的值就不能再直接用per_cpu__runqueues做偏移量了,而要 + __per_cpu_offset[i],i表示cpuid。
如何存取per cpu的变量:- 对于 __get_cpu_var(runqueues),等效扩展为:
__per_cpu_offset[smp_processor_id()] + per_cpu__runqueues
|
这正好是上述per_cpu__runqueues变量在对应CPU的专有数据区中的新地址。
由于不同的per cpu变量有不同的偏移量,并且不同的CPU其专有数据区首地址不同,
因此,通过__get_cpu_var()便访问到了不同的变量。
likely() && unlikely()
#define likely(x) __buildin_expect(!!(x),1) /*x 大多数不为0*/
#define unlikely(x) __buildin_expect(!!(x),0) /*x 大多数为0*/
|
这是gcc的扩展,目的是增加条件分支预测的准确性,cpu会提前装载后面的指令,遇到条件转移指令时会提前预测并装载某个分支的指令。
unlikely
表示你可以确认该条件是极少发生的;
相反likely表示该条件多数情况下会发生。编译器会产生相应的代码来优化cpu执行效率。
cpumask_of_cpu(cpu)
根据处理器编号cpu,将处理器位图的相应位置置为1(其它位为0):
既:如果CPU == 3,则cpumask_of_cpu(cpu)把cpu位图第三位置1,其他为置0.
#define cpumask_of_cpu(cpu) \
({ \
typeof(_unused_cpumask_arg_) m; \
if (sizeof(m) == sizeof(unsigned long)) { \
m.bits[0] = 1UL<<(cpu); \
} else { \
cpus_clear(m); \
cpu_set((cpu), m); \
} \
m; \
})
|
阅读(1004) | 评论(0) | 转发(0) |