remove "either" from the license
[Atomics.git] / PlatformAtomics.h
blob482f105385dd2547f8a575cd00419e63c3333de9
1 /***************************************************************************
2 * Copyright (c) 2010, Ronald Landheer-Cieslak & Vlinder Software *
3 * *
4 * Ownership of Copyright *
5 * ====================== *
6 * The copyright in this material (including without limitation the text, *
7 * computer code, artwork, photographs, images, music, audio material, *
8 * video material and audio-visual material) is owned by Ronald *
9 * Landheer-Cieslak and/or Vlinder Software. *
10 * *
11 * Copyright license *
12 * ================= *
13 * This program is free software: you can redistribute it and/or modify *
14 * it under the terms of the GNU General Public License as published by *
15 * the Free Software Foundation, version 3 of the License. *
16 * *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
21 * *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
24 ***************************************************************************/
25 #ifndef VLINDER_ATOMICS_PLATFORMATOMICS_H
26 #define VLINDER_ATOMICS_PLATFORMATOMICS_H
28 #include <boost/noncopyable.hpp>
29 #include <boost/static_assert.hpp>
30 #include <boost/type_traits/is_pod.hpp>
31 #if _MSC_VER
32 #define AO_ASSUME_WINDOWS98
33 #endif
34 #include "Private/atomic_ops.h"
36 #ifndef $
37 #define $ 0
38 #endif
40 namespace Vlinder
42 namespace Atomics
44 struct PlatformAtomics
46 enum MemoryOrder {
47 memory_order_relaxed__, // no operation orders memory
48 memory_order_consume__, // a load operation performs a consume operation on the affected memory location
49 memory_order_acquire__, // a load operation performs an acquire operation on the affected memory location
50 memory_order_release__, // a store operation performs a release operation on the affected memory location
51 memory_order_acq_rel__, // a store operation performs a release operation on the affected memory location;
52 // a load operation performs an acquire operation on the affected memory location
53 memory_order_seq_cst__, // a store operation performs a release operation on the affected memory location;
54 // a load operation performs an acquire operation on the affected memory location
57 template < typename T >
58 struct Atomic
59 : public boost::noncopyable
61 BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(AO_t));
62 BOOST_STATIC_ASSERT(boost::is_pod< T >::value);
63 #ifdef _MSC_VER
64 BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(LONG));
65 BOOST_STATIC_ASSERT(sizeof(AO_t) >= sizeof(LONG));
66 #endif
67 Atomic()
68 { /* no-op */ }
70 explicit Atomic(T t)
71 : value_(t)
72 { /* no-op */ }
74 template < typename D >
75 T load(const D & debug_info, MemoryOrder memory_order = memory_order_seq_cst__) const
77 (void)debug_info;
78 switch (memory_order)
80 case memory_order_relaxed__ :
81 return (T)value_;
82 case memory_order_acquire__ :
83 return AO_load_acquire(&value_);
84 case memory_order_release__ :
85 case memory_order_acq_rel__ :
86 case memory_order_consume__ :
87 case memory_order_seq_cst__ :
88 default :
89 return (T)AO_load_full(&value_);
93 template < typename D >
94 void store(const D & debug_info, T value, MemoryOrder memory_order = memory_order_seq_cst__)
96 (void)debug_info;
97 switch (memory_order)
99 case memory_order_relaxed__ :
100 value_ = (AO_t)value;
101 break;
102 case memory_order_acquire__ :
103 AO_store_acquire(&value_, (AO_t)value);
104 break;
105 case memory_order_release__ :
106 AO_store_release(&value_, (AO_t)value);
107 break;
108 case memory_order_acq_rel__ :
109 case memory_order_consume__ :
110 case memory_order_seq_cst__ :
111 default :
112 AO_store_full(&value_, (AO_t)value);
113 break;
117 template < typename D >
118 T exchange(const D & debug_info, T value, MemoryOrder memory_order = memory_order_seq_cst__)
120 (void)debug_info;
121 #ifdef _MSC_VER
122 switch (memory_order)
124 case memory_order_relaxed__ :
125 case memory_order_acquire__ :
126 InterlockedExchangeAcquire(&value, value);
127 break;
128 case memory_order_release__ :
129 case memory_order_acq_rel__ :
130 case memory_order_consume__ :
131 case memory_order_seq_cst__ :
132 default :
133 InterlockedExchange(&value, value);
134 break;
136 #else
137 /* This is a very sub-optimal implementation of an atomic exchange,
138 * but Boehm's library's test-and-set doesn't guarantee that it
139 * works on T's that are not booleans. */
140 T exp((T)value_);
141 while (!cas(debug_info, &exp, value, memory_order))
143 #endif
146 template < typename D >
147 bool cas(const D & debug_info, T * expected, T desired, MemoryOrder order = memory_order_seq_cst__)
149 (void)debug_info;
150 switch (memory_order)
152 case memory_order_relaxed__ :
153 case memory_order_acquire__ :
154 if (!AO_compare_and_swap_acquire(&value_, (AO_t)*expected, desired))
156 *expected = value_;
157 return false;
159 else
160 { /* all is well */ }
161 return true;
162 break;
163 case memory_order_release__ :
164 if (!AO_compare_and_swap_release(&value_, (AO_t)*expected, desired))
166 *expected = value_;
167 return false;
169 else
170 { /* all is well */ }
171 return true;
172 break;
173 case memory_order_acq_rel__ :
174 case memory_order_consume__ :
175 case memory_order_seq_cst__ :
176 default :
177 /* This implementation could re-emit a memory barrier - i.e. if it doesn't work */
178 if (!AO_compare_and_swap_full(&value_, (AO_t)*expected, desired))
180 *expected = load(debug_info, order);
181 return false;
183 else
184 { /* all is well */ }
185 return true;
186 break;
190 template < typename D >
191 T fetchAndAdd(const D & debug_info, T value, MemoryOrder order = memory_order_seq_cst__)
193 (void)debug_info;
194 switch (order)
196 case memory_order_relaxed__ :
197 case memory_order_acquire__ :
198 return AO_fetch_and_add_acquire(&value_, (AO_t)value);
199 case memory_order_release__ :
200 return AO_fetch_and_add_release(&value_, (AO_t)value);
201 case memory_order_acq_rel__ :
202 case memory_order_consume__ :
203 case memory_order_seq_cst__ :
204 default :
205 return AO_fetch_and_add_full(&value_, (AO_t)value);
209 template < typename D >
210 void add(const D & debug_info, T value, MemoryOrder order = memory_order_seq_cst__)
212 /* Sub-optimal implementation, but Boehm's library doesn't provide an atomic_add */
213 fetchAndAdd(debug_info, value, order);
216 template < typename D >
217 void sub(const D & debug_info, T value, MemoryOrder order = memory_order_seq_cst__)
219 /* Sub-optimal implementation, but Boehm's library doesn't provide an atomic_add */
220 (void)debug_info;
221 switch (memory_order)
223 case memory_order_relaxed__ :
224 case memory_order_acquire__ :
225 return AO_fetch_and_sub_acquire(&value_, (AO_t)value);
226 case memory_order_release__ :
227 return AO_fetch_and_sub_release(&value_, (AO_t)value);
228 case memory_order_acq_rel__ :
229 case memory_order_consume__ :
230 case memory_order_seq_cst__ :
231 default :
232 return AO_fetch_and_sub_full(&value_, (AO_t)value);
236 mutable AO_t value_;
239 static void membarRelease()
241 /* Sub-optimal implementation, but Boehm's library doesn't provide a nop_release */
242 AO_nop_full();
245 static void membarAcquire()
247 /* Sub-optimal implementation, but Boehm's library doesn't provide a nop_acquire */
248 AO_nop_full();
254 #endif