The Master said, “I have never seen a man so good as a womanizer.” The Analects of Confucius: A rare chapter
A hundred blog series. This is:V34. Xx HongMeng kernel source code analysis (atomic operation) | who escort for atomic operations
This article explains atomic operations
Before reading this article, it is recommended to read hongmeng kernel source code analysis (total directory) series.
The basic concept
In an operating system that supports multitasking, modifying data in an area of memory involves three steps: read, modify, and write. However, the data in the same memory area may be accessed by multiple tasks at the same time. If the data is interrupted by other tasks in the process of data modification, the execution result of the operation will be unpredictable.
The method of switch interrupt can guarantee the result of multi-task, but it will obviously affect the system performance.
The ARMv6 architecture introduces LDREX and STREX instructions to support more rigorous non-blocking synchronization of shared memory. The atomic operation thus implemented ensures that the read-modify-write operation on the same data will not be interrupted during its execution, i.e. the atomicity of the operation.
When multiple tasks add, subtract, or swap the same memory data, atomic operations are used to ensure predictable results.
The essence of the spin lock is atomic operation of a variable, and must be achieved through assembly code, that is to say, LDREX and STREX instructions ensure the underlying implementation of atomic operations. Review the assembly code for applying and releasing a spin lock.
ArchSpinLock request lock code
FUNCTION(ArchSpinLock) @hold on to lock mov R1, #1 @r1=1
1: @ Function of the loop, since SEV is a broadcast event. [r0] @r0 = &lock->rawLock CMP r2, #0@ r2 and0Strexeq r2, R1, [r0]@ At this time, the CPU is awakened, try lock->rawLock=1, r2=0Cmpeq r2, #0At sign and let's see if R2 is equal to0If it is equal, the lock BNE is obtained1bIf @ is not equal, continue to enter the loop DMB @ with DMB instruction to isolate, to ensure that the buffer data has been implemented in RAM BXLR @ must be locked, jump back to call ArchSpinLock functionCopy the code
ArchSpinUnlock releases the lock code
FUNCTION(ArchSpinUnlock) @release lock mov R1, #0 @r1=0DMB @ Data store isolation to ensure that cached data has been implemented into RAM STR R1, [r0] @ command lock->rawLock =0DSB @ data synchronization isolation SEv @ broadcast events to each CPU, wake up the sleeping CPU Bx lr @ jump back to call ArchSpinLock functionCopy the code
Operation mechanism
Hongmeng provides users with a set of atomic operation interfaces by encapsulating LDREX and STREX in ARMv6 architecture.
-
LDREX Rx, [Ry] reads the value in memory and marks exclusive access to this segment of memory:
- Read 4 bytes of memory data pointed to by register Ry and save to register Rx.
- Add an exclusive access tag to the memory region pointed to by Ry.
-
STREX Rf, Rx, [Ry] check whether memory has an exclusive access mark, if so, update the memory value and empty the mark, otherwise do not update memory:
- There are exclusive access flags
- Update the value in register Rx to the memory pointed to by register Ry.
- The flag register Rf is set to 0.
- There are no exclusive access tags
- Memory is not updated.
- The flag register Rf is set to 1.
- There are exclusive access flags
-
Judge flag register When the flag register is 0, exit the loop and the atomic operation ends. When the flag register is 1, the loop continues and the atomic operation is repeated.
Feature list
Atomic data contains two types: Atomic (signed 32 bits) and Atomic64 (signed 64 bits). Atomic operation module provides users with the following functions, interface details can be viewed source code.
LOS_AtomicAdd, LOS_AtomicSub, LOS_AtomicRead, LOS_AtomicSet understand function assembly code is the key to understanding atomic operations.
LOS_AtomicAdd
// Add data in memory
STATIC INLINE INT32 LOS_AtomicAdd(Atomic *v, INT32 addVal)
{
INT32 val;
UINT32 status;
do {
__asm__ __volatile__("ldrex %1, [%2]\n"
"Add %1, %1, %3\n"
"Strex %0, %1, [%2]"
: "=&r"(status),"=&r"(val)
: "r"(v),"r"(addVal)
: "cc");
} while(__builtin_expect(status ! =0.0));
return val;
}
Copy the code
This is a section of C language embedded assembly, one by one interpretation
-
- First the
status
val
v
addVal
The value of is taken over by general purpose registers (R0~R3).
- First the
-
- %2 represents the input parameter v, and [%2] represents the value of the parameter v to the address, *v, which is the exclusive function
-
- %0 to %3 correspond
status
val
v
addVal
- %0 to %3 correspond
-
- Ldrex %1, [%2] : val = *v;
-
- Add %1, %1, %3 = val + addVal;
-
- Strex %0, %1, [%2] *v = val;
-
- Status indicates whether the update is successful. If the update is successful, the value is 0. If the update is not successful, the value is 1
-
-
__builtin_expect is the judgment statement that ends the loop, telling the compiler which branch is most likely to be executed. This command is written as __builtin_expect(EXP, N).
The probability that e to the N is equal to N is high.
__builtin_expect(status! = 0, 0)
If strex is not strex (status == 0), the strex will be strex (status == 0).
-
-
- “=&r”(val) the decorated operator serves as output, passing the value of the register back to val, which is the return value of the function
-
- “Cc” declares the above information to the compiler.
LOS_AtomicSub
// Subtract memory data
STATIC INLINE INT32 LOS_AtomicSub(Atomic *v, INT32 subVal)
{
INT32 val;
UINT32 status;
do {
__asm__ __volatile__("ldrex %1, [%2]\n"
"Sub %1, %1, %3\n"
"Strex %0, %1, [%2]"
: "=&r"(status),"=&r"(val)
: "r"(v),"r"(subVal)
: "cc");
} while(__builtin_expect(status ! =0.0));
return val;
}
Copy the code
Interpretation of the
- with
LOS_AtomicAdd
Interpretation of the
volatile
The important point here is that volatile tells the compiler that the variable it defines is subject to change at any time, so that the compiled program reads directly from the address of the variable every time it needs to store or read the variable. Without the volatile keyword, the compiler may optimize reading and storage, may temporarily use a value in a register, and may be inconsistent if the variable is updated by another program.
// Read memory data
STATIC INLINE INT32 LOS_AtomicRead(const Atomic *v)
{
return* (volatile INT32 *)v;
}
// Write memory data
STATIC INLINE VOID LOS_AtomicSet(Atomic *v, INT32 setVal)
{
*(volatile INT32 *)v = setVal;
}
Copy the code
Programming instance
Call the interface related to atomic operation and observe the result:
1. Create two tasks
- Task 1 adds the global variable 100 times with LOS_AtomicAdd.
- Task 2 subtracted the global variable 100 times using LOS_AtomicSub.
2. After the subtask is complete, print the values of global variables in the main task.
#include "los_hwi.h"
#include "los_atomic.h"
#include "los_task.h"
UINT32 g_testTaskId01;
UINT32 g_testTaskId02;
Atomic g_sum;
Atomic g_count;
UINT32 Example_Atomic01(VOID)
{
int i = 0;
for(i = 0; i < 100; ++i) {
LOS_AtomicAdd(& g_sum,1);
}
LOS_AtomicAdd(& g_count,1);
return LOS_OK;
}
UINT32 Example_Atomic02(VOID)
{
int i = 0;
for(i = 0; i < 100; ++i) {
LOS_AtomicSub(& g_sum,1);
}
LOS_AtomicAdd(& g_count,1);
return LOS_OK;
}
UINT32 Example_TaskEntry(VOID)
{
TSK_INIT_PARAM_S stTask1={0};
stTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Atomic01;
stTask1.pcName = "TestAtomicTsk1";
stTask1.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
stTask1.usTaskPrio = 4;
stTask1.uwResved = LOS_TASK_STATUS_DETACHED;
TSK_INIT_PARAM_S stTask2={0};
stTask2.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Atomic02;
stTask2.pcName = "TestAtomicTsk2";
stTask2.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
stTask2.usTaskPrio = 4;
stTask2.uwResved = LOS_TASK_STATUS_DETACHED;
LOS_TaskLock(a);LOS_TaskCreate(& g_testTaskId01, & stTask1);LOS_TaskCreate(& g_testTaskId02, & stTask2);LOS_TaskUnlock(a);while(LOS_AtomicRead(&g_count) ! =2);
dprintf("g_sum = %d\n", g_sum);return LOS_OK;
}
Copy the code
results
g_sum = 0
Copy the code
Intensive reading of the kernel source code
Four code stores synchronous annotation kernel source code, >> view the Gitee repository
Analysis of 100 blogs. Dig deep into the core
Add comments to hongmeng kernel source code process, sort out the following article. Content based on the source code, often in life scene analogy as much as possible into the kernel knowledge of a scene, with a pictorial sense, easy to understand memory. It’s important to speak in a way that others can understand! The 100 blogs are by no means a bunch of ridiculously difficult concepts being put forward by Baidu. That’s not interesting. More hope to make the kernel become lifelike, feel more intimate. It’s hard, it’s hard, but there’s no turning back. 😛 and code bugs need to be constantly debug, there will be many mistakes and omissions in the article and annotation content, please forgive, but will be repeatedly amended, continuous update. Xx represents the number of modifications, refined, concise and comprehensive, and strive to create high-quality content.
Compile build | The fundamental tools | Loading operation | Process management |
---|---|---|---|
Compile environment The build process Environment script Build tools Designed.the gn application Ninja ninja |
Two-way linked list Bitmap management In the stack way The timer Atomic operation Time management |
The ELF format The ELF parsing Static link relocation Process image |
Process management Process concept Fork Special process Process recycling Signal production Signal consumption Shell editor Shell parsing |
Process of communication | Memory management | Ins and outs | Task management |
spinlocks The mutex Process of communication A semaphore Incident control The message queue |
Memory allocation Memory management Memory assembly The memory mapping Rules of memory Physical memory |
Total directory Scheduling the story Main memory slave The source code comments Source structure Static site |
The clock task Task scheduling Task management The scheduling queue Scheduling mechanism Thread concept Concurrent parallel The system calls Task switching |
The file system | Hardware architecture | ||
File concept The file system The index node Mount the directory Root file system Character device VFS File handle Pipeline file |
Compilation basis Assembly and the cords Working mode register Anomaly over Assembly summary Interrupt switch Interrupt concept Interrupt management |
HongMeng station | into a little bit every day, the original is not easy, welcome to reprint, please indicate the source.