MongoDB C++ Driver  legacy-1.1.2
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 
29 namespace mongo {
30 
34 template <typename T, typename _IsTSupported = void>
35 class AtomicIntrinsics {
36 private:
37  AtomicIntrinsics();
38  ~AtomicIntrinsics();
39 };
40 
44 template <typename T>
45 class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == sizeof(LONG)>::type> {
46 public:
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 
77 private:
80 };
81 
82 
83 namespace details {
84 
85 template <typename T, bool HaveInterlocked64Ops>
87 
88 // Implementation of 64-bit Interlocked operations via Windows API calls.
89 template <typename T>
90 struct 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.
109 template <typename T>
110 struct 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.
152 template <typename U, typename _IsTTooBig = void>
154 
155 // Implementation on 64-bit systems.
156 template <typename U>
157 struct 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.
174 template <typename U>
175 struct 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 
187 template <typename T>
188 class AtomicIntrinsics<T, typename boost::enable_if_c<sizeof(T) == sizeof(LONGLONG)>::type> {
189 public:
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 
219 private:
221  ~AtomicIntrinsics();
222 };
223 
224 namespace details {
225 
226 template <typename U>
227 U 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 
232 template <typename U>
233 void 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
Definition: atomic_intrinsics_win32.h:153
Utility functions for parsing numbers from strings.
Definition: compare_numbers.h:20
Definition: atomic_intrinsics_win32.h:86
Instantiation of AtomicIntrinsics<> for all word types T.
Definition: atomic_intrinsics_gcc_atomic.h:29