歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux per_cpu機制的詳解

Linux per_cpu機制的詳解

日期:2017/2/28 16:05:35   编辑:Linux教程
針對IA64體系結構

在Linux操作系統中,特別是針對SMP或者NUMA架構的多CPU系統的時候,描述每個CPU的私有數據的時候,Linux操作系統提供了per_cpu機制。

per_cpu機制就是讓每個CPU都有自己的私有數據段,便於保護與訪問。

通過宏DEFINE_PER_CPU,定義這種私有數據,只不過這種私有數據放在特定的數據段中。
#define DEFINE_PER_CPU(type, name) \
__attribute__((__section__(".data.percpu"))) \
PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
在GCC中__typeof__相當於typeof(檢查數據類型),用__typeof__為了兼容性。

例如1:在Linux操作系統中,用於描述每個IA64CPU信息的數據結構的定義:
DEFINE_PER_CPU(struct cpuinfo_ia64, cpu_info);

例如2:描述每個CPU的狀態的變量的定義:*
* State for each CPU
*/
DEFINE_PER_CPU(int, cpu_state);

系統如何為每個CPU保留這些私有數據的?
在start_kernel函數中調用執行函數setup_per_cpu_areas( ),setup_per_cpu_areas( )定義如下:
static void __init setup_per_cpu_areas(void)
{
unsigned long size, i;
char *ptr;
unsigned long nr_possible_cpus = num_possible_cpus();
/* Copy section for each CPU (we discard the original) */
size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE);
ptr = alloc_bootmem_pages(size * nr_possible_cpus);
for_each_possible_cpu(i) {
__per_cpu_offset = ptr - __per_cpu_start;
memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
ptr += size;
}
}
setup_per_cpu_areas( )的功能就是將.data.percpu中的數據拷貝到每個CPU的數據段中,每個CPU一份。
其中CPU n 對應的專有數據區的首地址為__per_cpu_offset[n]。

在Linux操作系統中,在系統啟動的時候會生成以__per_cpu_start標識開頭和__per_cpu_end標識結尾的數據段,在執行完函數setup_per_cpu_areas( )後,將.data.percpu中的數據拷貝到每個CPU數據段後,這個數據段就會釋放(free)掉。
.data.percpu定義如下(在arch/ia64/kernel/vmlinux.lds.S):
{
__per_cpu_start = .;
*(.data.percpu)
*(.data.percpu.shared_aligned)
__per_cpu_end = .;
}

如何存取每個CPU的這些私有數據呢?
第一種方法:取制定cpu的制定變量
/*
* A percpu variable may point to a discarded regions. The following are
* established ways to produce a usable pointer from the percpu variable
* offset.
*/
#define per_cpu(var, cpu) \
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), per_cpu_offset(cpu)))
|
|
#define SHIFT_PERCPU_PTR(__p, __offset) RELOC_HIDE((__p), (__offset))
|
|
#define RELOC_HIDE(ptr, off) \
({ unsigned long __ptr; \
__asm__ ("" : "=r"(__ptr) : "0"(ptr)); \
(typeof(ptr)) (__ptr + (off)); })
第二種方法:取當前CPU的制定變量
#define __get_cpu_var(var) \
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), my_cpu_offset))
第三種方法:讀後寫的方式讀取當前CPU的制定變量
#define __raw_get_cpu_var(var) \
(*SHIFT_PERCPU_PTR(&per_cpu_var(var), __my_cpu_offset))
Copyright © Linux教程網 All Rights Reserved