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