summaryrefslogtreecommitdiff
path: root/unittest
diff options
context:
space:
mode:
authorDavi Arnaut <davi.arnaut@oracle.com>2010-07-23 09:37:10 -0300
committerDavi Arnaut <davi.arnaut@oracle.com>2010-07-23 09:37:10 -0300
commit93e38e8a3ea9fdbd88a34da487cb2ccbfdaf8c11 (patch)
tree49a56f15656733bfb1bab6fc971e59860daa8979 /unittest
parent9deafdd2db229886f37bdfae719936757caa3e1d (diff)
downloadmariadb-git-93e38e8a3ea9fdbd88a34da487cb2ccbfdaf8c11.tar.gz
Bug#22320: my_atomic-t unit test fails
Bug#52261: 64 bit atomic operations do not work on Solaris i386 gcc in debug compilation One of the various problems was that the source operand to CMPXCHG8b was marked as a input/output operand, causing GCC to use the EBX register as the destination register for the CMPXCHG8b instruction. This could lead to crashes as the EBX register is also implicitly used by the instruction, causing the value to be potentially garbaged and a protection fault once the value is used to access a position in memory. Another problem was the lack of proper clobbers for the atomic operations and, also, a discrepancy between the implementations for the Compare and Set operation. The specific problems are described and fixed by Kristian Nielsen patches: Patch: 1 Fix bugs in my_atomic_cas*(val,cmp,new) that *cmp is accessed after CAS succeds. In the gcc builtin implementation, problem was that *cmp was read again after atomic CAS to check if old *val == *cmp; this fails if CAS is successful and another thread modifies *cmp in-between. In the x86-gcc implementation, problem was that *cmp was set also in the case of successful CAS; this means there is a window where it can clobber a value written by another thread after successful CAS. Patch 2: Add a GCC asm "memory" clobber to primitives that imply a memory barrier. This signifies to GCC that any potentially aliased memory must be flushed before the operation, and re-read after the operation, so that read or modification in other threads of such memory values will work as intended. In effect, it makes these primitives work as memory barriers for the compiler as well as the CPU. This is better and more correct than adding "volatile" to variables. include/atomic/gcc_builtins.h: Do not read from *cmp after the operation as it might be already gone if the operation was successful. include/atomic/nolock.h: Prefer system provided atomics over the broken x86 asm. include/atomic/x86-gcc.h: Do not mark source operands as input/output operands. Add proper memory clobbers. include/my_atomic.h: Add notes about my_atomic_add and my_atomic_cas behaviors. unittest/mysys/my_atomic-t.c: Remove work around, if it fails, there is either a problem with the atomic operations code or the specific compiler version should be black-listed.
Diffstat (limited to 'unittest')
-rw-r--r--unittest/mysys/my_atomic-t.c19
1 files changed, 6 insertions, 13 deletions
diff --git a/unittest/mysys/my_atomic-t.c b/unittest/mysys/my_atomic-t.c
index 9853d3cf964..95799be7bb1 100644
--- a/unittest/mysys/my_atomic-t.c
+++ b/unittest/mysys/my_atomic-t.c
@@ -15,13 +15,6 @@
#include "thr_template.c"
-/* at least gcc 3.4.5 and 3.4.6 (but not 3.2.3) on RHEL */
-#if __GNUC__ == 3 && __GNUC_MINOR__ == 4
-#define GCC_BUG_WORKAROUND volatile
-#else
-#define GCC_BUG_WORKAROUND
-#endif
-
volatile uint32 b32;
volatile int32 c32;
my_atomic_rwlock_t rwl;
@@ -29,8 +22,8 @@ my_atomic_rwlock_t rwl;
/* add and sub a random number in a loop. Must get 0 at the end */
pthread_handler_t test_atomic_add(void *arg)
{
- int m= (*(int *)arg)/2;
- GCC_BUG_WORKAROUND int32 x;
+ int m= (*(int *)arg)/2;
+ int32 x;
for (x= ((int)(intptr)(&m)); m ; m--)
{
x= (x*m+0x87654321) & INT_MAX32;
@@ -52,8 +45,8 @@ volatile int64 a64;
/* add and sub a random number in a loop. Must get 0 at the end */
pthread_handler_t test_atomic_add64(void *arg)
{
- int m= (*(int *)arg)/2;
- GCC_BUG_WORKAROUND int64 x;
+ int m= (*(int *)arg)/2;
+ int64 x;
for (x= ((int64)(intptr)(&m)); m ; m--)
{
x= (x*m+0xfdecba987654321LL) & INT_MAX64;
@@ -128,8 +121,8 @@ pthread_handler_t test_atomic_fas(void *arg)
*/
pthread_handler_t test_atomic_cas(void *arg)
{
- int m= (*(int *)arg)/2, ok= 0;
- GCC_BUG_WORKAROUND int32 x, y;
+ int m= (*(int *)arg)/2, ok= 0;
+ int32 x, y;
for (x= ((int)(intptr)(&m)); m ; m--)
{
my_atomic_rwlock_wrlock(&rwl);