2006-04-18 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / libatomic_ops / tests / test_atomic.c
1 /*  
2  * Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
3  * Original Author: Hans Boehm
4  *
5  * This file may be redistributed and/or modified under the
6  * terms of the GNU General Public License as published by the Free Software
7  * Foundation; either version 2, or (at your option) any later version.
8  * 
9  * It is distributed in the hope that it will be useful, but WITHOUT ANY
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License in the
12  * file doc/COPYING for more details.
13  */
14
15 #if defined(HAVE_CONFIG_H)
16 # include "config.h"
17 #endif
18
19
20 #include "run_parallel.inc"
21
22 #include "test_atomic_include.h"
23
24 #ifdef AO_USE_PTHREAD_DEFS
25 # define NITERS 100000
26 #else
27 # define NITERS 10000000
28 #endif
29
30 #if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
31
32 AO_t counter = 0;
33
34 void * add1sub1_thr(void * id)
35 {
36   int me = (int)(long)id;
37
38   int i;
39
40   for (i = 0; i < NITERS; ++i)
41     if (me & 1)
42       AO_fetch_and_sub1(&counter);
43     else
44       AO_fetch_and_add1(&counter);
45
46   return 0;
47 }
48
49 int add1sub1_test(void)
50 {
51   return counter == 0;
52 }
53
54 #endif /* defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) */
55
56 #if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
57
58 /* Invariant: counter1 >= counter2 */
59 AO_t counter1 = 0;
60 AO_t counter2 = 0;
61
62 void * acqrel_thr(void *id)
63 {
64   int me = (int)(long)id;
65
66   int i;
67
68   for (i = 0; i < NITERS; ++i)
69     if (me & 1)
70       {
71         AO_t my_counter1;
72         if (me != 1)
73           fprintf(stderr, "acqrel test: too many threads\n");
74         my_counter1 = AO_load(&counter1);
75         AO_store(&counter1, my_counter1 + 1);
76         AO_store_release_write(&counter2, my_counter1 + 1);
77       }
78     else
79       {
80         AO_t my_counter1a, my_counter2a;
81         AO_t my_counter1b, my_counter2b;
82
83         my_counter2a = AO_load_acquire_read(&counter2);
84         my_counter1a = AO_load(&counter1);
85         /* Redo this, to make sure that the second load of counter1     */
86         /* is not viewed as a common subexpression.                     */
87         my_counter2b = AO_load_acquire_read(&counter2);
88         my_counter1b = AO_load(&counter1);
89         if (my_counter1a < my_counter2a)
90           {
91             fprintf(stderr, "Saw release store out of order: %lu < %lu\n",
92                     (unsigned long)my_counter1a, (unsigned long)my_counter2a);
93             abort();
94           }
95         if (my_counter1b < my_counter2b)
96           {
97             fprintf(stderr,
98                     "Saw release store out of order (bad CSE?): %lu < %lu\n",
99                     (unsigned long)my_counter1b, (unsigned long)my_counter2b);
100             abort();
101           }
102       }
103
104   return 0;
105 }
106
107 int acqrel_test(void)
108 {
109   return counter1 == NITERS && counter2 == NITERS;
110 }
111
112 #endif /* AO_HAVE_store_release_write && AO_HAVE_load_acquire_read */
113
114 #if defined(AO_HAVE_test_and_set_acquire)
115
116 AO_TS_T lock = AO_TS_INITIALIZER;
117
118 unsigned long locked_counter;
119 volatile unsigned long junk = 13;
120
121 void * test_and_set_thr(void * id)
122 {
123   unsigned long i;
124
125   for (i = 0; i < NITERS/10; ++i)
126     {
127       while (AO_test_and_set_acquire(&lock) != AO_TS_CLEAR);
128       ++locked_counter;
129       if (locked_counter != 1)
130         {
131           fprintf(stderr, "Test and set failure 1, counter = %ld\n",
132                       locked_counter);
133           abort();
134         }
135       locked_counter *= 2;
136       locked_counter -= 1;
137       locked_counter *= 5;
138       locked_counter -= 4;
139       if (locked_counter != 1)
140         {
141           fprintf(stderr, "Test and set failure 2, counter = %ld\n",
142                       locked_counter);
143           abort();
144         }
145       --locked_counter;
146       AO_CLEAR(&lock);
147       /* Spend a bit of time outside the lock. */
148         junk *= 17;
149         junk *= 17;
150     }
151   return 0;
152 }
153
154 int test_and_set_test(void)
155 {
156   return locked_counter == 0;
157 }
158
159 #endif /* defined(AO_HAVE_test_and_set_acquire) */
160
161 int main()
162 {
163   test_atomic();
164   test_atomic_acquire();
165   test_atomic_release();
166   test_atomic_read();
167   test_atomic_write();
168   test_atomic_full();
169   test_atomic_release_write();
170   test_atomic_acquire_read();
171 # if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
172     run_parallel(4, add1sub1_thr, add1sub1_test, "add1/sub1");
173 # endif
174 # if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
175     run_parallel(3, acqrel_thr, acqrel_test,
176                  "store_release_write/load_acquire_read");
177 # endif
178 # if defined(AO_HAVE_test_and_set_acquire)
179     run_parallel(5, test_and_set_thr, test_and_set_test,
180                  "test_and_set");
181 # endif
182   return 0;
183 }