1
2 #include "config.h"
3 #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
12 #undef PLAT_x86_darwin
13 #undef PLAT_amd64_darwin
14 #undef PLAT_x86_linux
15 #undef PLAT_amd64_linux
16 #undef PLAT_ppc32_linux
17 #undef PLAT_ppc64be_linux
18 #undef PLAT_arm_linux
19 #undef PLAT_s390x_linux
20 #undef PLAT_mips32_linux
21 #undef PLAT_tilegx_linux
22
23 #if defined(__APPLE__) && defined(__i386__)
24 # define PLAT_x86_darwin 1
25 #elif defined(__APPLE__) && defined(__x86_64__)
26 # define PLAT_amd64_darwin 1
27 #elif defined(__linux__) && defined(__i386__)
28 # define PLAT_x86_linux 1
29 #elif defined(__linux__) && defined(__x86_64__)
30 # define PLAT_amd64_linux 1
31 #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
32 # define PLAT_ppc32_linux 1
33 #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
34 # define PLAT_ppc64_linux 1
35 #elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__)
36 # define PLAT_arm_linux 1
37 #elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__)
38 # define PLAT_arm64_linux 1
39 #elif defined(__linux__) && defined(__s390x__)
40 # define PLAT_s390x_linux 1
41 #elif defined(__linux__) && defined(__mips__)
42 # define PLAT_mips32_linux 1
43 #elif defined(__linux__) && defined(__tilegx__)
44 # define PLAT_tilegx_linux 1
45 #endif
46
47
48 #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
49 || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin)
50 # define XCHG_M_R(_addr,_lval) \
51 __asm__ __volatile__( \
52 "xchgl %0, %1" \
53 : /*out*/ "+r"(_lval) \
54 : /*in*/ "m"(_addr) \
55 : "memory", "cc" \
56 )
57 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
58 __asm__ __volatile__( \
59 "lock xchgl %0, %1" \
60 : /*out*/ "+r"(_lval) \
61 : /*in*/ "m"(_addr) \
62 : "memory", "cc" \
63 )
64
65 #elif defined(PLAT_s390x_linux)
66 # define XCHG_M_R(_addr,_lval) \
67 do { \
68 __asm__ __volatile__( \
69 "0: l 0,%[global]\n\t" \
70 " cs 0,%[local],%[global]\n\t" \
71 " bne 0b\n\t" \
72 " lr %[local],0\n\t" \
73 : /*out*/ [global]"+m"(_addr), [local]"+d"(_lval) \
74 : /*in*/ \
75 : "0", "memory", "cc" \
76 ); \
77 } while (0)
78
79 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
80 XCHG_M_R(_addr,_lval)
81
82 #elif defined(PLAT_mips32_linux) || defined(PLAT_mips64_linux)
83 # define XCHG_M_R(_addr,_lval) \
84 __asm__ __volatile__( \
85 "move $12, %2\n" \
86 "move $13, %1\n" \
87 "ll $14, 0($13)\n" \
88 "sc $12, 0($13)\n" \
89 "move %0, $14\n" \
90 : /*out*/ "=r"(_lval) \
91 : /*in*/ "r"(&_addr), "r"(_lval) \
92 : "$12", "$13", "$14", "memory", "cc" \
93 )
94
95 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
96 XCHG_M_R(_addr,_lval)
97
98 #elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux) \
99 || defined(PLAT_arm_linux) || defined(PLAT_arm64_linux)
100 # if defined(HAVE_BUILTIN_ATOMIC)
101 # define XCHG_M_R(_addr,_lval) \
102 do { \
103 int tmp; \
104 while ((tmp = *(int*)(& _addr)), \
105 ! __sync_bool_compare_and_swap((int*)&_addr, tmp, _lval)) \
106 ; \
107 _lval = tmp; \
108 } while (0)
109 # else
110 # warning "XCHG_M_R() implementation is missing. Either" \
111 "provide one or use a newer gcc version."
112 # define XCHG_M_R(_addr,_lval) \
113 do { int tmp = *(int*)(& _addr); \
114 *(int*)(& _addr) = (_lval); \
115 _lval = tmp; \
116 } while (0)
117 # endif
118 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
119 XCHG_M_R(_addr,_lval)
120
121 #elif defined(PLAT_tilegx_linux)
122 # define XCHG_M_R(_addr,_lval) \
123 _lval = __insn_exch4(&_addr, _lval)
124
125 # define XCHG_M_R_with_redundant_LOCK(_addr,_lval) \
126 XCHG_M_R(_addr, _lval)
127 #else
128 # error "Unsupported architecture"
129
130 #endif
131
132 int x = 0;
133
child_fn(void * arg)134 void* child_fn ( void* arg )
135 {
136 int v = 12345;
137 XCHG_M_R_with_redundant_LOCK(x, v);
138 assert(v == 0 || v == 6789);
139 return NULL;
140 }
141
main(void)142 int main ( void )
143 {
144 int v = 6789;
145 pthread_t child;
146
147 if (pthread_create(&child, NULL, child_fn, NULL)) {
148 perror("pthread_create");
149 exit(1);
150 }
151
152 XCHG_M_R(x, v);
153 assert(v == 0 || v == 12345);
154
155 if (pthread_join(child, NULL)) {
156 perror("pthread join");
157 exit(1);
158 }
159
160 if (v == 0 || v == 12345)
161 printf("success\n");
162 else
163 printf("failure\n");
164
165 return v;
166 }
167