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
18volatile uint32 b32;
19volatile int32 c32;
20
21/* add and sub a random number in a loop. Must get 0 at the end */
22pthread_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
38volatile int64 a64;
39/* add and sub a random number in a loop. Must get 0 at the end */
40pthread_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*/
69pthread_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*/
97pthread_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
119void 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