diff options
author | karoly <karoly@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2015-10-16 18:53:35 +0000 |
---|---|---|
committer | karoly <karoly@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2015-10-16 18:53:35 +0000 |
commit | a8fe62a18c7aa20f2ac7d89ebacde3f29735630b (patch) | |
tree | be43677fc6e477c61787646dc68c42344ad456c8 /rtl/arm | |
parent | a11b000d9674a5e7833d80fde959efa6714a48a3 (diff) | |
download | fpc-a8fe62a18c7aa20f2ac7d89ebacde3f29735630b.tar.gz |
fix InterlockedCompareExchange on ARM-Linux: kuser_cmpxchg destroys r3, which needs to be restored, if we have to loop
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@32063 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'rtl/arm')
-rw-r--r-- | rtl/arm/arm.inc | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/rtl/arm/arm.inc b/rtl/arm/arm.inc index bfdb7fc94a..ba70889392 100644 --- a/rtl/arm/arm.inc +++ b/rtl/arm/arm.inc @@ -970,8 +970,6 @@ asm {$else} {$ifdef SYSTEM_HAS_KUSER_CMPXCHG} stmfd r13!, {r4, lr} - mvn r3, #0x0000f000 - sub r3, r3, #0x3F mov r4, r2 // Swap parameters around mov r2, r0 @@ -979,9 +977,13 @@ asm // r1 and r2 will not be clobbered by kuser_cmpxchg // If we have to loop, r0 will be set to the original Comperand + // kuser_cmpxchg is documented to destroy r3, therefore setting + // r3 must be in the loop .Linterlocked_compare_exchange_loop: + mvn r3, #0x0000f000 + sub r3, r3, #0x3F {$ifdef CPUARM_HAS_BLX} - blx r3 // Call kuser_cmpxchg, sets C-Flag on success + blx r3 // Call kuser_cmpxchg, sets C-Flag on success {$else} mov lr, pc {$ifdef CPUARM_HAS_BX} @@ -997,11 +999,11 @@ asm // The loop case is HIGHLY unlikely, it would require that we got rescheduled between // calling kuser_cmpxchg and the ldr. While beeing rescheduled another process/thread // would have the set the value to our comperand - ldr r0, [r2] // Load the currently set value + ldr r0, [r2] // Load the currently set value cmp r0, r4 // Return if Comperand != current value, otherwise loop again ldmnefd r13!, {r4, pc} // If we need to loop here, we have to - b .Linterlocked_compare_exchange_loop + b .Linterlocked_compare_exchange_loop {$else} // lock |