MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mysys_my_atomic-t.cc
1 /* Copyright (c) 2006, 2012, 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 // First include (the generated) my_config.h, to get correct platform defines.
17 #include "my_config.h"
18 #include <gtest/gtest.h>
19 
20 #include <my_global.h>
21 #include <my_sys.h>
22 #include <my_atomic.h>
23 
24 
25 namespace mysys_my_atomic_unittest {
26 
27 #include "thr_template.cc"
28 
29 volatile int32 b32;
30 volatile int32 c32;
32 
33 /* add and sub a random number in a loop. Must get 0 at the end */
34 pthread_handler_t test_atomic_add(void *arg)
35 {
36  int m= (*(int *)arg)/2;
37  int32 x;
38  for (x= ((int)(intptr)(&m)); m ; m--)
39  {
40  x= (x*m+0x87654321) & INT_MAX32;
41  my_atomic_rwlock_wrlock(&rwl);
42  my_atomic_add32(&bad, x);
43  my_atomic_rwlock_wrunlock(&rwl);
44 
45  my_atomic_rwlock_wrlock(&rwl);
46  my_atomic_add32(&bad, -x);
47  my_atomic_rwlock_wrunlock(&rwl);
48  }
49  mysql_mutex_lock(&mutex);
50  if (!--running_threads) mysql_cond_signal(&cond);
51  mysql_mutex_unlock(&mutex);
52  return 0;
53 }
54 
55 volatile int64 a64;
56 /* add and sub a random number in a loop. Must get 0 at the end */
57 pthread_handler_t test_atomic_add64(void *arg)
58 {
59  int m= (*(int *)arg)/2;
60  int64 x;
61  for (x= ((int64)(intptr)(&m)); m ; m--)
62  {
63  x= (x*m+0xfdecba987654321LL) & INT_MAX64;
64  my_atomic_rwlock_wrlock(&rwl);
65  my_atomic_add64(&a64, x);
66  my_atomic_rwlock_wrunlock(&rwl);
67 
68  my_atomic_rwlock_wrlock(&rwl);
69  my_atomic_add64(&a64, -x);
70  my_atomic_rwlock_wrunlock(&rwl);
71  }
72  mysql_mutex_lock(&mutex);
73  if (!--running_threads)
74  {
75  bad= (a64 != 0);
76  mysql_cond_signal(&cond);
77  }
78  mysql_mutex_unlock(&mutex);
79  return 0;
80 }
81 
82 
83 /*
84  1. generate thread number 0..N-1 from b32
85  2. add it to bad
86  3. swap thread numbers in c32
87  4. (optionally) one more swap to avoid 0 as a result
88  5. subtract result from bad
89  must get 0 in bad at the end
90 */
91 pthread_handler_t test_atomic_fas(void *arg)
92 {
93  int m= *(int *)arg;
94  int32 x;
95 
96  my_atomic_rwlock_wrlock(&rwl);
97  x= my_atomic_add32(&b32, 1);
98  my_atomic_rwlock_wrunlock(&rwl);
99 
100  my_atomic_rwlock_wrlock(&rwl);
101  my_atomic_add32(&bad, x);
102  my_atomic_rwlock_wrunlock(&rwl);
103 
104  for (; m ; m--)
105  {
106  my_atomic_rwlock_wrlock(&rwl);
107  x= my_atomic_fas32(&c32, x);
108  my_atomic_rwlock_wrunlock(&rwl);
109  }
110 
111  if (!x)
112  {
113  my_atomic_rwlock_wrlock(&rwl);
114  x= my_atomic_fas32(&c32, x);
115  my_atomic_rwlock_wrunlock(&rwl);
116  }
117 
118  my_atomic_rwlock_wrlock(&rwl);
119  my_atomic_add32(&bad, -x);
120  my_atomic_rwlock_wrunlock(&rwl);
121 
122  mysql_mutex_lock(&mutex);
123  if (!--running_threads) mysql_cond_signal(&cond);
124  mysql_mutex_unlock(&mutex);
125  return 0;
126 }
127 
128 /*
129  same as test_atomic_add, but my_atomic_add32 is emulated with
130  my_atomic_cas32 - notice that the slowdown is proportional to the
131  number of CPUs
132 */
133 pthread_handler_t test_atomic_cas(void *arg)
134 {
135  int m= (*(int *)arg)/2, ok= 0;
136  int32 x, y;
137  for (x= ((int)(intptr)(&m)); m ; m--)
138  {
139  my_atomic_rwlock_wrlock(&rwl);
140  y= my_atomic_load32(&bad);
141  my_atomic_rwlock_wrunlock(&rwl);
142  x= (x*m+0x87654321) & INT_MAX32;
143  do {
144  my_atomic_rwlock_wrlock(&rwl);
145  ok= my_atomic_cas32(&bad, &y, (uint32)y+x);
146  my_atomic_rwlock_wrunlock(&rwl);
147  } while (!ok) ;
148  do {
149  my_atomic_rwlock_wrlock(&rwl);
150  ok= my_atomic_cas32(&bad, &y, y-x);
151  my_atomic_rwlock_wrunlock(&rwl);
152  } while (!ok) ;
153  }
154  mysql_mutex_lock(&mutex);
155  if (!--running_threads) mysql_cond_signal(&cond);
156  mysql_mutex_unlock(&mutex);
157  return 0;
158 }
159 
160 
161 void do_tests()
162 {
163  bad= my_atomic_initialize();
164  EXPECT_FALSE(bad) << "my_atomic_initialize() returned";
165 
166  my_atomic_rwlock_init(&rwl);
167 
168  b32= c32= 0;
169  test_concurrently("my_atomic_add32", test_atomic_add, THREADS, CYCLES);
170  b32= c32= 0;
171  test_concurrently("my_atomic_fas32", test_atomic_fas, THREADS, CYCLES);
172  b32= c32= 0;
173  test_concurrently("my_atomic_cas32", test_atomic_cas, THREADS, CYCLES);
174 
175  {
176  /*
177  If b is not volatile, the wrong assembly code is generated on OSX Lion
178  as the variable is optimized away as a constant.
179  See Bug#62533 / Bug#13030056.
180  Another workaround is to specify architecture explicitly using e.g.
181  CFLAGS/CXXFLAGS= "-m64".
182  */
183  volatile int64 b=0x1000200030004000LL;
184  a64=0;
185  my_atomic_add64(&a64, b);
186  EXPECT_EQ(a64, b) << "add64";
187  }
188  a64=0;
189  test_concurrently("my_atomic_add64", test_atomic_add64, THREADS, CYCLES);
190 
191  my_atomic_rwlock_destroy(&rwl);
192 }
193 
194 
195 TEST(Mysys, Atomic)
196 {
197  mysql_mutex_init(0, &mutex, 0);
198  mysql_cond_init(0, &cond, NULL);
199  pthread_attr_init(&thr_attr);
200  pthread_attr_setdetachstate(&thr_attr, PTHREAD_CREATE_DETACHED);
201 
202  do_tests();
203 
204  mysql_mutex_destroy(&mutex);
205  mysql_cond_destroy(&cond);
206  pthread_attr_destroy(&thr_attr);
207 }
208 
209 }