Analysis of the atomic operation ARM linux

linux ARM atomic operation source file is linux/arch/arm/include/asm/atomic.h

linux source macro expansion

By the beginning of the macro is defined as follows, linux various macro too complicated, a bit strenuous analysis

#define ATOMIC_OP(op, c_op, asm_op)					\  <-------------------|
static inline void atomic_##op(int i, atomic_t *v)			\                      |
{									\                      |
	unsigned long tmp;						\                      |
	int result;							\                      |
									\                      |
	prefetchw(&v->counter);						\                      |
	__asm__ __volatile__("@ atomic_" #op "\n"			\                      |
"1:	ldrex	%0, [%3]\n"						\                      |
"	" #asm_op "	%0, %0, %4\n"					\                      |
"	strex	%1, %0, [%3]\n"						\                      |
"	teq	%1, #0\n"						\                      |
"	bne	1b"							\                      |
	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)		\                      |
	: "r" (&v->counter), "Ir" (i)					\                      |
	: "cc");							\                      |
}                                                                                              |
                                                                                               |
#define ATOMIC_OPS(op, c_op, asm_op)					\ <-----|              |
	ATOMIC_OP(op, c_op, asm_op)					\       |--------------|
	ATOMIC_OP_RETURN(op, c_op, asm_op)					|
			                                                        |
ATOMIC_OPS(add, +=, add)		-----------------------------------------

The final function of the beginning static inline void atomic_##op(int i, atomic_t *v), replace op to add, asm_op to add is declared as:

static inline void atomic_add(int i, atomic_t *v)
{									
	unsigned long tmp;	
	int result;
									
	prefetchw(&v->counter);						
	__asm__ __volatile__("@ atomic_" #op "\n"
"1:	ldrex	%0, [%3]\n"						
"	add     %0, %0, %4\n"					
"	strex	%1, %0, [%3]\n"						
"	teq	%1, #0\n"						
"	bne	1b"							
	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
	: "r" (&v->counter), "Ir" (i)					
	: "cc");							
}

According to another GCC inline assembly replacement rule, result, tmp, v-> counter , & v-> counter, they , respectively, in order of appearance 0-% 4% replacement operands are replaced one by one:

static inline void atomic_add(int i, atomic_t *v)
{									
	unsigned long tmp;	
	int result;
									
	prefetchw(&v->counter);						
	__asm__ __volatile__(
"1:	ldrex	result, [&v->counter]\n"						
"	add	result, result, i\n"					
"	strex	tmp, result, [&v->counter]\n"						
"	teq	tmp, #0\n"						
"	bne	1b"							
	: "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)
	: "r" (&v->counter), "Ir" (i)					
	: "cc");							
}

Separately extracting assembling part

1:
	ldrex	result, [&v->counter]
	add	result, result, i
	strex	tmp, result, [&v->counter]
	teq	tmp, #0
	bne	1b

Translated into C language:

	do{
		result = v->counter;				//ldrex	result, [&v->counter]
		result = result + i;				//add	result, result, i
		tmp = (v->counter = result赋值失败?1:0);	//strex	tmp, result, [&v->counter]
	}while(tmp != 0);					//teq	tmp, #0;bne	1b

More strange sentence is tmp = (v->counter = result赋值失败?1:0);, of course, this is not a valid C statement, but it expresses what it means. It will detect the v->counter = resultphrase assignment, if successful, 0 is assigned to tmp is returned, otherwise returns 1. The focus here is to understand ldrexand strexthis is what is meant two compilation.

LDREX and instructions STREX

Starting ARMv6 architecture, ARM processor provides Exclusive accesses synchronization primitives, used to synchronize access to memory, including two instructions:

LDREX Rd [Rs]
STREX R0 Rd [Rs]

LDREX and STREX instruction, an atomic operation will be split into two memory address steps, with the atomic operation to memory. It will be appreciated to execute LDREX Rd [Rs]instruction tag access [Rs of] this memory address is exclusive state (exclusive state). Perform STREX R0 Rd [Rs]memory address [Rs of] instruction previously in the exclusive state makes transition to the normal state, and set to 0 R0. If the execution STREX R0 Rd [Rs]instruction, the memory address [Rs of] is the normal state, the instruction memory operation will fail, and R0 is set to 1.

Internal ARM To achieve this, there are many complex situations to deal with. In the ARM system, there are two different memory and antagonistic properties, i.e., shared (Shareable) and non-shared (Non-shareable). Means that the shared memory segment may be different processors access to the system, the processor may also be homogenous or heterogeneous. Rather than shared, by contrast, means that the section of the system memory can only be accessed by a processor that is not visible to other processors.

In order to achieve exclusive access, the system also features the ARM so-called exclusive monitor (Exclusive Monitor) things, its structure is as follows:

there are two types of Monitor, local and global. For non-shared memory, concerned only with local monitor can be, and will have local shared memory also requires global concern.

Each monitor is a state machine, comprising exclusive state and the open state. LDREX corresponding monitor the operation will become exclusive state, and if the monitor is now exclusive state, then the operation will monitor the implementation of STREX becomes open state, and the storage memory of this action is successful, otherwise the monitor status unchanged, storage behavior failure.

Guess you like

Origin www.cnblogs.com/thammer/p/12596119.html