MongoDB C++ Driver legacy-1.1.1
Loading...
Searching...
No Matches
atomic_intrinsics_win32.h
1/* Copyright 2012 10gen Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
20#pragma once
21
22#include <boost/utility.hpp>
23
24#include "mongo/platform/windows_basic.h"
25
26#include <intrin.h>
27#pragma intrinsic(_InterlockedCompareExchange64)
28
29namespace mongo {
30
34template <typename T, typename _IsTSupported = void>
35class AtomicIntrinsics {
36private:
37 AtomicIntrinsics();
38 ~AtomicIntrinsics();
39};
40
44template <typename T>
45class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == sizeof(LONG)>::type> {
46public:
47 static T compareAndSwap(volatile T* dest, T expected, T newValue) {
48 return InterlockedCompareExchange(
49 reinterpret_cast<volatile LONG*>(dest), LONG(newValue), LONG(expected));
50 }
51
52 static T swap(volatile T* dest, T newValue) {
53 return InterlockedExchange(reinterpret_cast<volatile LONG*>(dest), LONG(newValue));
54 }
55
56 static T load(volatile const T* value) {
57 MemoryBarrier();
58 T result = *value;
59 MemoryBarrier();
60 return result;
61 }
62
63 static T loadRelaxed(volatile const T* value) {
64 return *value;
65 }
66
67 static void store(volatile T* dest, T newValue) {
68 MemoryBarrier();
69 *dest = newValue;
70 MemoryBarrier();
71 }
72
73 static T fetchAndAdd(volatile T* dest, T increment) {
74 return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(dest), LONG(increment));
75 }
76
77private:
80};
81
82
83namespace details {
84
85template <typename T, bool HaveInterlocked64Ops>
87
88// Implementation of 64-bit Interlocked operations via Windows API calls.
89template <typename T>
90struct InterlockedImpl64<T, true> {
91 static T compareAndSwap(volatile T* dest, T expected, T newValue) {
92 return InterlockedCompareExchange64(
93 reinterpret_cast<volatile LONGLONG*>(dest), LONGLONG(newValue), LONGLONG(expected));
94 }
95
96 static T swap(volatile T* dest, T newValue) {
97 return InterlockedExchange64(reinterpret_cast<volatile LONGLONG*>(dest),
98 LONGLONG(newValue));
99 }
100
101 static T fetchAndAdd(volatile T* dest, T increment) {
102 return InterlockedExchangeAdd64(reinterpret_cast<volatile LONGLONG*>(dest),
103 LONGLONG(increment));
104 }
105};
106
107// Implementation of 64-bit Interlocked operations for systems where the API does not
108// yet provide the Interlocked...64 operations.
109template <typename T>
110struct InterlockedImpl64<T, false> {
111 static T compareAndSwap(volatile T* dest, T expected, T newValue) {
112 // NOTE: We must use the compiler intrinsic here: WinXP does not offer
113 // InterlockedCompareExchange64 as an API call.
114 return _InterlockedCompareExchange64(
115 reinterpret_cast<volatile LONGLONG*>(dest), LONGLONG(newValue), LONGLONG(expected));
116 }
117
118 static T swap(volatile T* dest, T newValue) {
119 // NOTE: You may be tempted to replace this with
120 // 'InterlockedExchange64'. Resist! It will compile just fine despite not being
121 // listed in the docs as available on XP, but the compiler may replace it with
122 // calls to the non-intrinsic 'InterlockedCompareExchange64', which does not
123 // exist on XP. We work around this by rolling our own synthetic in terms of
124 // compareAndSwap which we have explicitly formulated in terms of the compiler
125 // provided _InterlockedCompareExchange64 intrinsic.
126 T currentValue = *dest;
127 while (true) {
128 const T result = compareAndSwap(dest, currentValue, newValue);
129 if (result == currentValue)
130 return result;
131 currentValue = result;
132 }
133 }
134
135 static T fetchAndAdd(volatile T* dest, T increment) {
136 // NOTE: See note for 'swap' on why we roll this ourselves.
137 T currentValue = *dest;
138 while (true) {
139 const T incremented = currentValue + increment;
140 const T result = compareAndSwap(dest, currentValue, incremented);
141 if (result == currentValue)
142 return result;
143 currentValue = result;
144 }
145 }
146};
147
148// On 32-bit IA-32 systems, 64-bit load and store must be implemented in terms of
149// Interlocked operations, but on 64-bit systems they support a simpler, native
150// implementation. The LoadStoreImpl type represents the abstract implementation of
151// loading and storing 64-bit values.
152template <typename U, typename _IsTTooBig = void>
154
155// Implementation on 64-bit systems.
156template <typename U>
157struct LoadStoreImpl<U, typename boost::enable_if_c<sizeof(U) <= sizeof(void*)>::type> {
158 static U load(volatile const U* value) {
159 MemoryBarrier();
160 U result = *value;
161 MemoryBarrier();
162 return result;
163 }
164
165
166 static void store(volatile U* dest, U newValue) {
167 MemoryBarrier();
168 *dest = newValue;
169 MemoryBarrier();
170 }
171};
172
173// Implementation on 32-bit systems.
174template <typename U>
175struct LoadStoreImpl<U, typename boost::disable_if_c<sizeof(U) <= sizeof(void*)>::type> {
176 // NOTE: Implemented out-of-line below since the implementation relies on
177 // AtomicIntrinsics.
178 static U load(volatile const U* value);
179 static void store(volatile U* dest, U newValue);
180};
181
182} // namespace details
183
187template <typename T>
188class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG)>::type> {
189public:
190#if defined(NTDDI_VERSION) && defined(NTDDI_WS03SP2) && (NTDDI_VERSION >= NTDDI_WS03SP2)
191 static const bool kHaveInterlocked64 = true;
192#else
193 static const bool kHaveInterlocked64 = false;
194#endif
195
198
199 static T compareAndSwap(volatile T* dest, T expected, T newValue) {
200 return InterlockedImpl::compareAndSwap(dest, expected, newValue);
201 }
202
203 static T swap(volatile T* dest, T newValue) {
204 return InterlockedImpl::swap(dest, newValue);
205 }
206
207 static T load(volatile const T* value) {
208 return LoadStoreImpl::load(value);
209 }
210
211 static void store(volatile T* dest, T newValue) {
212 LoadStoreImpl::store(dest, newValue);
213 }
214
215 static T fetchAndAdd(volatile T* dest, T increment) {
216 return InterlockedImpl::fetchAndAdd(dest, increment);
217 }
218
219private:
222};
223
224namespace details {
225
226template <typename U>
227U LoadStoreImpl<U, typename boost::disable_if_c<sizeof(U) <= sizeof(void*)>::type>::load(
228 volatile const U* value) {
229 return AtomicIntrinsics<U>::compareAndSwap(const_cast<volatile U*>(value), U(0), U(0));
230}
231
232template <typename U>
233void LoadStoreImpl<U, typename boost::disable_if_c<sizeof(U) <= sizeof(void*)>::type>::store(
234 volatile U* dest, U newValue) {
235 AtomicIntrinsics<U>::swap(dest, newValue);
236}
237
238} // namespace details
239
240} // namespace mongo
Instantiation of AtomicIntrinsics<> for all word types T.
Definition atomic_intrinsics_gcc_atomic.h:29
Utility functions for parsing numbers from strings.
Definition compare_numbers.h:32
Definition atomic_intrinsics_win32.h:86
Definition atomic_intrinsics_win32.h:153