Synchronization and mutual exclusion variables _percpu

The key variable is the percpu: requirements according to the number of CPU generates multiple copies in memory, and to correct each variable to address the CPU and the CPU number in accordance with the variable name.

Using per-cpu variable has the following advantages: the required data is likely present in the processor's cache, it can be accessed more quickly. If more than one CPU may also access variables in a multiprocessor system, it will cause some communications problems, the use of variable percpu just avoid this problem.

Here the reader need only remember percpu Each CPU has a variable on the line, after reading this article, come back and read the bold front, I believe there will be more profound understanding.

First look at how to define a variable percpu:

DEFINE_PER_CPU(int, cpu_number);

#define DEFINE_PER_CPU(type, name) \
    __attribute__((__section__(".data.percpu"))) __typeof__(type) per_cpu__##name

Percpu above code defines a variable of type int, the name for per_cpu_cpu_number. __typeof __ (type) is obtained int, and per_cpu __ ## name is obtained per_cpu_cpu_number, and by this __section__ .data.percpu named variables into data segments. Thus at compile time all the variables are unified into .data.percpu percpu data segment, when the kernel starts, CPU .data.percpu copy for each section separately from the data in accordance with the detected number of cpu. start_kernel function calls setup_per_cpu_areas () to complete this work, setup_per_cpu_areas defined as follows:

// __ per_cpu_offset array corresponds to the Save CPU percpu segments offset relative ptr 
unsigned long __per_cpu_offset [NR_CPUS] __read_mostly; 

static void the __init setup_per_cpu_areas (void) 
{ 
	unsigned long size, I; 
	char * ptr; 
    Number of CPU taken // 
	unsigned long = num_possible_cpus nr_possible_cpus (); 

	/ * the Copy sectionTop for each CPU (WE discard the Original) * / 
    / * segment size calculation per CPU percpu required. 
     * 
     * @PERCPU_ENOUGH_ROOM: __ per_cpu_end - __per_cpu_start + PERCPU_MODULE_RESERVE 
     * @ALIGN (): make up percpu aligned segment size 
     * / 
	size = the ALIGN (PERCPU_ENOUGH_ROOM, PAGE_SIZE); 
	// allocate memory 
    ptr = alloc_bootmem_pages (size * nr_possible_cpus) ;
 
	for_each_possible_cpu (I) {
        / * __Per_cpu_start terms for each CPU is a fixed value, it __per_cpu_end are generated by the linker 
         * calculated with respect to each CPU __per_cpu_start real storage address offset percpu linear segment 
         * Please refer to the schematic below code 
         * memcpy copy all variables percpu each CPU to its own percpu segment 
         * / 
		__per_cpu_offset [I] = PTR - __per_cpu_start; 
		the memcpy (PTR, __per_cpu_start, __per_cpu_end - __per_cpu_start); 
		PTR + = size; 
	} 
}

1552095558772

So how to access the source code at compile time variable percpu it ? Kernel defines several macros to achieve access to percpu variables:

// smp_processor_id () can return the ID of the currently active processor, as cpu following parameters. 
per_cpu #define (var, CPU) (* ({\ 
	extern int _ ## simple_identifier var (void); \ 
	RELOC_HIDE (## & per_cpu __ var, __per_cpu_offset (CPU));}))

Here we give an example will be described: Suppose Access per_cpu (var, 1), since percpu variables when defining unwound from DEFINE_PER_CPU into per_cpu_var, so RELOC_HIDE first parameter is a compile-time per_cpu_var address, the second parameter __per_cpu_offset ( cpu) calculated for the front setup_per_cpu_areas, which represents the first address of the difference copy runtime data area head address and percpu compile identified, adding the two values ​​is the address actually stored percpu variables. Diagram is as follows:

1552104630074

In more (Geng) new kernel (2.6.32), the definition of variables percpu (DEFINE_PER_CPU) and the access (per_cpu (var, cpu)) does not change the way, mainly initialized array __per_cpu_offset changed, see arch \ x86 \ kernel \ setup_percpu.c in function: setup_per_cpu_areas (). And you can refer to the following links:

Guess you like

Origin www.cnblogs.com/still-smile/p/11655208.html
Recommended