blob: 48fc1b1a9e396ced1c9312548f404eb1e1b7c7b0 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
bart7b35d212008-06-26 08:58:25 +00002#include "config.h"
sewardjb4112022007-11-09 22:49:28 +00003#include <pthread.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <assert.h>
7
8/* Simple test program, no race. Parent and child both modify x and
9 use the hardware bus lock (implicitly, since XCHG r,m on x86/amd64
10 does not require an explicit LOCK prefix.). */
11
sewardj8777f732010-01-02 10:43:23 +000012#undef PLAT_x86_darwin
13#undef PLAT_amd64_darwin
sewardjb4112022007-11-09 22:49:28 +000014#undef PLAT_x86_linux
15#undef PLAT_amd64_linux
16#undef PLAT_ppc32_linux
carlldd690bf2014-08-07 23:49:27 +000017#undef PLAT_ppc64be_linux
sewardj8777f732010-01-02 10:43:23 +000018#undef PLAT_arm_linux
sewardjb5b87402011-03-07 16:05:35 +000019#undef PLAT_s390x_linux
sewardj5db15402012-06-07 09:13:21 +000020#undef PLAT_mips32_linux
sewardj8eb8bab2015-07-21 14:44:28 +000021#undef PLAT_x86_solaris
22#undef PLAT_amd64_solaris
sewardjb4112022007-11-09 22:49:28 +000023
sewardj6e9de462011-06-28 07:25:29 +000024#if defined(__APPLE__) && defined(__i386__)
sewardj8777f732010-01-02 10:43:23 +000025# define PLAT_x86_darwin 1
26#elif defined(__APPLE__) && defined(__x86_64__)
27# define PLAT_amd64_darwin 1
28#elif defined(__linux__) && defined(__i386__)
29# define PLAT_x86_linux 1
30#elif defined(__linux__) && defined(__x86_64__)
31# define PLAT_amd64_linux 1
32#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
33# define PLAT_ppc32_linux 1
34#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
35# define PLAT_ppc64_linux 1
sewardj23ed6302014-03-18 23:02:59 +000036#elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__)
sewardj8777f732010-01-02 10:43:23 +000037# define PLAT_arm_linux 1
sewardj23ed6302014-03-18 23:02:59 +000038#elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__)
39# define PLAT_arm64_linux 1
sewardjb5b87402011-03-07 16:05:35 +000040#elif defined(__linux__) && defined(__s390x__)
41# define PLAT_s390x_linux 1
sewardj5db15402012-06-07 09:13:21 +000042#elif defined(__linux__) && defined(__mips__)
43# define PLAT_mips32_linux 1
sewardj8eb8bab2015-07-21 14:44:28 +000044#elif defined(__sun__) && defined(__i386__)
45# define PLAT_x86_solaris 1
46#elif defined(__sun__) && defined(__x86_64__)
47# define PLAT_amd64_solaris 1
sewardjb4112022007-11-09 22:49:28 +000048#endif
49
50
sewardjf5b5f842010-01-04 10:47:25 +000051#if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
sewardj8eb8bab2015-07-21 14:44:28 +000052 || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \
53 || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris)
sewardjb4112022007-11-09 22:49:28 +000054# define XCHG_M_R(_addr,_lval) \
55 __asm__ __volatile__( \
56 "xchgl %0, %1" \
57 : /*out*/ "+r"(_lval) \
58 : /*in*/ "m"(_addr) \
59 : "memory", "cc" \
60 )
61# define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
62 __asm__ __volatile__( \
63 "lock xchgl %0, %1" \
64 : /*out*/ "+r"(_lval) \
65 : /*in*/ "m"(_addr) \
66 : "memory", "cc" \
67 )
sewardjb8544e22008-10-21 23:12:56 +000068
florianbed336a2011-09-09 18:37:55 +000069#elif defined(PLAT_s390x_linux)
70# define XCHG_M_R(_addr,_lval) \
71 do { \
72 __asm__ __volatile__( \
73 "0: l 0,%[global]\n\t" \
74 " cs 0,%[local],%[global]\n\t" \
75 " bne 0b\n\t" \
76 " lr %[local],0\n\t" \
77 : /*out*/ [global]"+m"(_addr), [local]"+d"(_lval) \
78 : /*in*/ \
79 : "0", "memory", "cc" \
80 ); \
81 } while (0)
82
83# define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
84 XCHG_M_R(_addr,_lval)
85
sewardj5db15402012-06-07 09:13:21 +000086#elif defined(PLAT_mips32_linux) || defined(PLAT_mips64_linux)
87# define XCHG_M_R(_addr,_lval) \
88 __asm__ __volatile__( \
89 "move $12, %2\n" \
90 "move $13, %1\n" \
91 "ll $14, 0($13)\n" \
92 "sc $12, 0($13)\n" \
93 "move %0, $14\n" \
94 : /*out*/ "=r"(_lval) \
95 : /*in*/ "r"(&_addr), "r"(_lval) \
96 : "$12", "$13", "$14", "memory", "cc" \
97 )
98
99# define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
100 XCHG_M_R(_addr,_lval)
101
bart5df26092008-06-26 08:34:53 +0000102#elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux) \
sewardj23ed6302014-03-18 23:02:59 +0000103 || defined(PLAT_arm_linux) || defined(PLAT_arm64_linux)
sewardjb8544e22008-10-21 23:12:56 +0000104# if defined(HAVE_BUILTIN_ATOMIC)
105# define XCHG_M_R(_addr,_lval) \
106 do { \
107 int tmp; \
108 while ((tmp = *(int*)(& _addr)), \
109 ! __sync_bool_compare_and_swap((int*)&_addr, tmp, _lval)) \
110 ; \
111 _lval = tmp; \
112 } while (0)
113# else
114# warning "XCHG_M_R() implementation is missing. Either" \
115 "provide one or use a newer gcc version."
116# define XCHG_M_R(_addr,_lval) \
117 do { int tmp = *(int*)(& _addr); \
118 *(int*)(& _addr) = (_lval); \
119 _lval = tmp; \
120 } while (0)
121# endif
bart5df26092008-06-26 08:34:53 +0000122# define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
123 XCHG_M_R(_addr,_lval)
sewardjb8544e22008-10-21 23:12:56 +0000124
sewardjb4112022007-11-09 22:49:28 +0000125#else
sewardjb8544e22008-10-21 23:12:56 +0000126# error "Unsupported architecture"
127
sewardjb4112022007-11-09 22:49:28 +0000128#endif
129
130int x = 0;
131
132void* child_fn ( void* arg )
133{
134 int v = 12345;
135 XCHG_M_R_with_redundant_LOCK(x, v);
136 assert(v == 0 || v == 6789);
137 return NULL;
138}
139
140int main ( void )
141{
142 int v = 6789;
143 pthread_t child;
144
145 if (pthread_create(&child, NULL, child_fn, NULL)) {
146 perror("pthread_create");
147 exit(1);
148 }
149
150 XCHG_M_R(x, v);
151 assert(v == 0 || v == 12345);
152
153 if (pthread_join(child, NULL)) {
154 perror("pthread join");
155 exit(1);
156 }
157
158 if (v == 0 || v == 12345)
159 printf("success\n");
160 else
161 printf("failure\n");
162
163 return v;
164}