1 | /* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. |
2 | |
3 | This program is free software; you can redistribute it and/or modify |
4 | it under the terms of the GNU General Public License as published by |
5 | the Free Software Foundation; version 2 of the License. |
6 | |
7 | This program is distributed in the hope that it will be useful, |
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | GNU General Public License for more details. |
11 | |
12 | You should have received a copy of the GNU General Public License |
13 | along with this program; if not, write to the Free Software |
14 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
15 | |
16 | #include "thr_template.c" |
17 | |
18 | volatile uint32 b32; |
19 | volatile int32 c32; |
20 | |
21 | /* add and sub a random number in a loop. Must get 0 at the end */ |
22 | pthread_handler_t test_atomic_add(void *arg) |
23 | { |
24 | int m= (*(int *)arg)/2; |
25 | int32 x; |
26 | for (x= ((int)(intptr)(&m)); m ; m--) |
27 | { |
28 | x= (x*m+0x87654321) & INT_MAX32; |
29 | my_atomic_add32(&bad, x); |
30 | my_atomic_add32(&bad, -x); |
31 | } |
32 | pthread_mutex_lock(&mutex); |
33 | if (!--running_threads) pthread_cond_signal(&cond); |
34 | pthread_mutex_unlock(&mutex); |
35 | return 0; |
36 | } |
37 | |
38 | volatile int64 a64; |
39 | /* add and sub a random number in a loop. Must get 0 at the end */ |
40 | pthread_handler_t test_atomic_add64(void *arg) |
41 | { |
42 | int m= (*(int *)arg)/2; |
43 | int64 x; |
44 | for (x= ((int64)(intptr)(&m)); m ; m--) |
45 | { |
46 | x= (x*m+0xfdecba987654321LL) & INT_MAX64; |
47 | my_atomic_add64(&a64, x); |
48 | my_atomic_add64(&a64, -x); |
49 | } |
50 | pthread_mutex_lock(&mutex); |
51 | if (!--running_threads) |
52 | { |
53 | bad= (a64 != 0); |
54 | pthread_cond_signal(&cond); |
55 | } |
56 | pthread_mutex_unlock(&mutex); |
57 | return 0; |
58 | } |
59 | |
60 | |
61 | /* |
62 | 1. generate thread number 0..N-1 from b32 |
63 | 2. add it to bad |
64 | 3. swap thread numbers in c32 |
65 | 4. (optionally) one more swap to avoid 0 as a result |
66 | 5. subtract result from bad |
67 | must get 0 in bad at the end |
68 | */ |
69 | pthread_handler_t test_atomic_fas(void *arg) |
70 | { |
71 | int m= *(int *)arg; |
72 | int32 x; |
73 | |
74 | x= my_atomic_add32(&b32, 1); |
75 | |
76 | my_atomic_add32(&bad, x); |
77 | |
78 | for (; m ; m--) |
79 | x= my_atomic_fas32(&c32, x); |
80 | |
81 | if (!x) |
82 | x= my_atomic_fas32(&c32, x); |
83 | |
84 | my_atomic_add32(&bad, -x); |
85 | |
86 | pthread_mutex_lock(&mutex); |
87 | if (!--running_threads) pthread_cond_signal(&cond); |
88 | pthread_mutex_unlock(&mutex); |
89 | return 0; |
90 | } |
91 | |
92 | /* |
93 | same as test_atomic_add, but my_atomic_add32 is emulated with |
94 | my_atomic_cas32 - notice that the slowdown is proportional to the |
95 | number of CPUs |
96 | */ |
97 | pthread_handler_t test_atomic_cas(void *arg) |
98 | { |
99 | int m= (*(int *)arg)/2, ok= 0; |
100 | int32 x, y; |
101 | for (x= ((int)(intptr)(&m)); m ; m--) |
102 | { |
103 | y= my_atomic_load32(&bad); |
104 | x= (x*m+0x87654321) & INT_MAX32; |
105 | do { |
106 | ok= my_atomic_cas32(&bad, &y, (uint32)y+x); |
107 | } while (!ok) ; |
108 | do { |
109 | ok= my_atomic_cas32(&bad, &y, y-x); |
110 | } while (!ok) ; |
111 | } |
112 | pthread_mutex_lock(&mutex); |
113 | if (!--running_threads) pthread_cond_signal(&cond); |
114 | pthread_mutex_unlock(&mutex); |
115 | return 0; |
116 | } |
117 | |
118 | |
119 | void do_tests() |
120 | { |
121 | plan(5); |
122 | |
123 | b32= c32= 0; |
124 | test_concurrently("my_atomic_add32" , test_atomic_add, THREADS, CYCLES); |
125 | b32= c32= 0; |
126 | test_concurrently("my_atomic_fas32" , test_atomic_fas, THREADS, CYCLES); |
127 | b32= c32= 0; |
128 | test_concurrently("my_atomic_cas32" , test_atomic_cas, THREADS, CYCLES); |
129 | |
130 | { |
131 | /* |
132 | If b is not volatile, the wrong assembly code is generated on OSX Lion |
133 | as the variable is optimized away as a constant. |
134 | See Bug#62533 / Bug#13030056. |
135 | Another workaround is to specify architecture explicitly using e.g. |
136 | CFLAGS/CXXFLAGS= "-m64". |
137 | */ |
138 | volatile int64 b=0x1000200030004000LL; |
139 | a64=0; |
140 | my_atomic_add64(&a64, b); |
141 | ok(a64==b, "add64" ); |
142 | } |
143 | a64=0; |
144 | test_concurrently("my_atomic_add64" , test_atomic_add64, THREADS, CYCLES); |
145 | } |
146 | |