From mboxrd@z Thu Jan 1 00:00:00 1970 From: Richard Earnshaw To: nobody@gcc.gnu.org Cc: gcc-prs@gcc.gnu.org Subject: Re: libstdc++/3584: arm-specific atomic operations not atomic Date: Wed, 11 Jul 2001 08:46:00 -0000 Message-id: <20010711154603.7493.qmail@sourceware.cygnus.com> X-SW-Source: 2001-07/msg00298.html List-Id: The following reply was made to PR libstdc++/3584; it has been noted by GNATS. From: Richard Earnshaw To: robin.farine@terminus.org Cc: gcc-gnats@gcc.gnu.org, acnrf@dial.eunet.ch, Richard.Earnshaw@arm.com Subject: Re: libstdc++/3584: arm-specific atomic operations not atomic Date: Wed, 11 Jul 2001 16:38:26 +0100 robin.farine@terminus.org said: > Routines such as atomic_add() that reads a memory location, apply an > operation to the read value, uses the swp instruction to update the > memory location and swp again if the value read the 2nd time does > equal the initial value introduce a race condition. I agree. I can think of two possible solutions; which is best depends on the potential uses of these operations. The first one reserves a value (say INT_MIN, chosen because it is a simple immediate constant on the ARM, and a relatively unlikely value in normal signed-arithmetic operations); if the atomic memory location ever contains this value, then another atomic operation is in progress on the memory location, and the requester must spin until that value is not already stored there. The code for atomic add would then be. @ r0 = address, r1 = increment. mov r2, #INT_MIN 0: swp r3, r2, [r0] cmp r3, #INT_MIN beq 0b @ already locked. @ We now have the lock add r3, r3, r1 cmp r3, #INT_MIN @ Paranoia -- INT_MIN is reserved. addeq r3, #1 str r3, [r0] @ save, and release the lock. Similar sequences could be written for the other operations. The second avoids reserving a value, but requires a larger object for the "lock". It would also require special code to initialize and read any value from an _Atomic_word object. This would break the current include/bits/basic_string.h implementation, which contains _Atomic_word _M_references; bool _M_is_leaked() const { return _M_references < 0; } bool _M_is_shared() const { return _M_references > 0; } ... I guess we could fix this by making _Atomic_word a class which defined these operations. The code for this variant would be: @ r0 = address (struct {int lock, int value}), r1 = increment. mov r2, #INT_MIN 0: swp r3, r2, [r0] cmp r3, #INT_MIN beq 0b @ already locked @ We now have the lock ldr r2, [r0, #4] add r2, r2, r1 str r2, [r0, #4] str r3, [r0] @ Release the lock. mov r2