In the ARMv8 architecture for A64, several exclusive instructions are provided to support exclusive operations.

So why did ARM introduce exclusive instructions? The main purpose of this addition is to solve the problem of lock contention in multi-core situations.
At the software level, access to shared resources is controlled by a lock. Only the program that acquires this lock can access the shared resource, while programs that do not acquire the lock cannot access it.
Once a program has acquired the lock, it must release it after finishing its access, allowing other programs to compete for the lock and access the shared resource.
The pseudocode is as follows:
// Acquire lock
get_lock:
ldr w1, [x0]
cmp w1, #1
b.ne get_lock
mov w1, #1
str w1, [x0]
// Start accessing shared resource
...
// End accessing shared resource
unlock:
mov w1, #0
str w1, [x0]
Read the lock; if it is non-zero, it indicates that the current lock is held by another program, thus the lock acquisition fails, and the program must wait for the lock to be released. If the lock value is zero, it indicates that the lock is not held by any other program, so the program sets the lock to one and then accesses the shared resource. After completing the access, the lock is set back to zero to release it.
This lock acquisition program can run quite well in a single-core environment, as only one program can execute at any given time, eliminating contention issues.
However, when using an operating system, potential issues may arise because the OS schedules applications. Suppose application A reads the lock status and finds it to be zero, indicating the lock is not held by any other program. Just as it is about to set the lock, the OS schedules application B to execute. Application B also reads the lock status, finds it to be zero, and sets the lock to access the shared resource. At this point, the OS schedules application A to execute again, which also sets the lock and accesses the shared resource. This results in two applications accessing the shared resource simultaneously, thereby nullifying the lock’s purpose.
The execution process is shown in the following table:
|
Program A |
Currently Executing |
Program B |
|
ldr w1, [x0] Lock status is 0 |
Program A |
|
|
Program B |
ldr w1, [x0] Lock status is 0 |
|
|
Program B |
str w1, [x0] Locked, lock status is 1 |
|
|
Program B |
Accessing shared resource |
|
|
b.ne get_lock At this point, lock status is 1, but A is unaware |
Program A |
|
|
str w1, [x0] Locked |
Program A |
|
|
Accessing shared resource |
Program A |
To solve this problem, one can mask interrupts when acquiring the lock, preventing the OS from scheduling, thus avoiding the aforementioned issue. The pseudocode is as follows:
get_lock:
// Disable interrupts
bl mask_int
ldr w1, [x0]
cmp w1, #1
b.ne get_lock
mov w1, #1
str w1, [x0]
// Enable interrupts
bl open_int
// Access shared resource
...
unlock:
mov w1, #0
str w1, [x0]
This approach can avoid the aforementioned issues, but acquiring a lock requires disabling and enabling interrupts, which affects the real-time response of the system.
In a single-core environment, one can disable interrupts to prevent the OS from scheduling. However, in a multi-core environment, each CPU executes in parallel, which means that the previously described situation can still occur where two programs simultaneously acquire the lock status, and masking interrupts does not help.
To solve the lock contention issue in multi-core situations, ARM introduced exclusive operations and added corresponding instructions.
The core of the exclusive operation is to maintain the lock using a state machine, which has two states: open and exclusive. To successfully lock, the state must switch from exclusive to open; all other states indicate failure.
To support exclusive operations, A64 introduced the LDXR and STXR instructions.

In A32 and T32, the LDREX and STREX instructions were also added for support.

The LDXR instruction switches the state from open to exclusive, while the STXR instruction switches the state from exclusive to open, indicating a successful store exclusive operation.

The STXR instruction differs from the ordinary STR instruction in that it has a return value indicating whether the store exclusive was successful. If successful, ws is 0; if unsuccessful, ws is 1.
With the exclusive operation instructions in place, the previous lock acquisition program is transformed into the following:
// Acquire lock
get_lock:
ldxr w1, [x0]
cmp w1, #1
b.ne get_lock
// Attempt to lock
mov w1, #1
stxr w2, w1, [x0]
cbnz w2, get_lock
// Access resource
...
unlock:
mov w1, #0
str w1, [x0]
By using the STXR instruction, one attempts to change the lock’s state. If successful, w2 will be 0, indicating that the lock has been acquired, and access to the shared resource can proceed. If unsuccessful, w2 will be 1, indicating that another program has already acquired the lock, and access to the shared resource cannot proceed, thus returning to the lock acquisition process.


