This blog is original, follow the cc3.0 protocol, reprint please indicate the source: http://blog.csdn.net/lux_veritas/article/details/8977510
Certificate --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Per_cpu macro is very common in Linux kernel. Here, we will analyze the features of the per_cpu macro implementation based on the kernel version of linux2.6.36:
When config_smp is enabled, the implementation of the per_cpu macro is as follows. The function is to calculate the internal data offset based on the CPU value (Per_cpu_offset (CPU)), Returns the VaR pointer to add the address after the offset:
#define per_cpu(var, cpu) \(*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))
Shift_percpu_ptr
The macro is defined as follows. First, verify
_ P
Is it
Percpu
Variable pointer, and then
_ P
Value addition
_ Offset
. The analysis is as follows:
/* Weird cast keeps both GCC and sparse happy. */#define SHIFT_PERCPU_PTR(__p, __offset)({\__verify_pcpu_ptr((__p));\ //1RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)); \ //2})
// 1 verify the macro of the pointer:
/* * Macro which verifies @ptr is a percpu pointer without evaluating * @ptr. This is to be used in percpu accessors to verify that the * input parameter is a percpu pointer. */#define __verify_pcpu_ptr(ptr)do {\const void __percpu *__vpp_verify = (typeof(ptr))NULL;\(void)__vpp_verify;\} while (0)
// 2 macro used to increment the pointer:
/** This macro obfuscates arithmetic on a variable address so that GCC * shouldn't recognize the original var, and make assumptions about it. ** this is needed because the C standard makes it undefined to do * pointer arithmetic on "objects" outside their boundaries and the * GCC optimizers assume this is the case. in particle they * assume such arithmetic does not wrap. ** A miscompilation has been observed because of this on PPC. * to work around it we hide the relationship of the pointer and the object * using this macro. ** versions of the ppc64 compiler before 4.1 had a bug where use of * reloc_hide cocould trash r30. the bug can be worked around by changing * the inline assembly constraint from = g to = r, in this particle * case either is valid. */# define reloc_hide (PTR, off) \ ({unsigned long _ PTR; \__ ASM _ ("": "= r" (_ PTR ): "0" (PTR); \ // _ PTR is stored in the Register, and PTR is stored in the register where _ PTR is located, that is, the assignment of PTR to _ PTR is completed, finally, return the value of _ PTR (typeof (PTR) (_ PTR + (off);}) // the entire implementation adds off the PTR value and returns it to PTR.
The macro definition of per_cpu_offset is as follows:
/* * per_cpu_offset() is the offset that has to be added to a * percpu variable to get to the instance for a certain processor. * * Most arches use the __per_cpu_offset array for those offsets but * some arches have their own ways of determining the offset (x86_64, s390). */#define per_cpu_offset(x) (__per_cpu_offset(x))#define __per_cpu_offset(__cpu) \(trap_block[(__cpu)].__per_cpu_base)struct trap_per_cpu trap_block[NR_CPUS];
Reference:
[1] http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s6
[2] http://www.yubo.org/xen/code.php? File = linux-2.6.18-xen.hg/include/Linux/compiler-gcc.h & begin = 20 & End = 23 & lang = CPP & num = 1 & version = 3.4 & Title = reloc_hide ()