1 /***************************************************************************
2 * Copyright (c) 2010, Ronald Landheer-Cieslak & Vlinder Software *
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. *
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. *
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. *
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>
32 #define AO_ASSUME_WINDOWS98
34 #include "Private/atomic_ops.h"
44 struct PlatformAtomics
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
>
59 : public boost::noncopyable
61 BOOST_STATIC_ASSERT(sizeof(T
) <= sizeof(AO_t
));
62 BOOST_STATIC_ASSERT(boost::is_pod
< T
>::value
);
64 BOOST_STATIC_ASSERT(sizeof(T
) <= sizeof(LONG
));
65 BOOST_STATIC_ASSERT(sizeof(AO_t
) >= sizeof(LONG
));
74 template < typename D
>
75 T
load(const D
& debug_info
, MemoryOrder memory_order
= memory_order_seq_cst__
) const
80 case memory_order_relaxed__
:
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__
:
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__
)
99 case memory_order_relaxed__
:
100 value_
= (AO_t
)value
;
102 case memory_order_acquire__
:
103 AO_store_acquire(&value_
, (AO_t
)value
);
105 case memory_order_release__
:
106 AO_store_release(&value_
, (AO_t
)value
);
108 case memory_order_acq_rel__
:
109 case memory_order_consume__
:
110 case memory_order_seq_cst__
:
112 AO_store_full(&value_
, (AO_t
)value
);
117 template < typename D
>
118 T
exchange(const D
& debug_info
, T value
, MemoryOrder memory_order
= memory_order_seq_cst__
)
122 switch (memory_order
)
124 case memory_order_relaxed__
:
125 case memory_order_acquire__
:
126 InterlockedExchangeAcquire(&value
, value
);
128 case memory_order_release__
:
129 case memory_order_acq_rel__
:
130 case memory_order_consume__
:
131 case memory_order_seq_cst__
:
133 InterlockedExchange(&value
, value
);
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. */
141 while (!cas(debug_info
, &exp
, value
, memory_order
))
146 template < typename D
>
147 bool cas(const D
& debug_info
, T
* expected
, T desired
, MemoryOrder order
= memory_order_seq_cst__
)
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
))
160 { /* all is well */ }
163 case memory_order_release__
:
164 if (!AO_compare_and_swap_release(&value_
, (AO_t
)*expected
, desired
))
170 { /* all is well */ }
173 case memory_order_acq_rel__
:
174 case memory_order_consume__
:
175 case memory_order_seq_cst__
:
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
);
184 { /* all is well */ }
190 template < typename D
>
191 T
fetchAndAdd(const D
& debug_info
, T value
, MemoryOrder order
= memory_order_seq_cst__
)
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__
:
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 */
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__
:
232 return AO_fetch_and_sub_full(&value_
, (AO_t
)value
);
239 static void membarRelease()
241 /* Sub-optimal implementation, but Boehm's library doesn't provide a nop_release */
245 static void membarAcquire()
247 /* Sub-optimal implementation, but Boehm's library doesn't provide a nop_acquire */