Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
atomic.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_ATOMIC_H_)
21 #define __MITSUBA_CORE_ATOMIC_H_
22 
23 #include <mitsuba/mitsuba.h>
24 
25 #if defined(__OSX__)
26 #include <libkern/OSAtomic.h>
27 #elif defined(_MSC_VER)
28 #include <intrin.h>
29 #endif
30 
32 
33 /**
34  * The following implementations are based on PBRT
35  *
36  * \addtogroup libcore
37  */
38 
39 /*! @{ */
40 
41 /**
42  * \brief Atomically attempt to exchange a pointer with another value
43  *
44  * \param v Pointer to the pointer in question
45  * \param oldValue Last known value of the destination \a v
46  * \param newValue Replacement value for the destination \a v
47  * \tparam T Base type of the pointer
48  * \return \c true if \c *v was equal to \c oldValue and the exchange
49  * was successful.
50  */
51 template <typename T> inline bool atomicCompareAndExchangePtr(T **v, T *newValue, T *oldValue) {
52 #if defined(_MSC_VER)
53  #if defined(WIN64)
54  return _InterlockedCompareExchangePointer(
55  reinterpret_cast<void * volatile *>(v), newValue, oldValue) == oldValue;
56  #else
57  return _InterlockedCompareExchange(
58  reinterpret_cast<long volatile *>(v),
59  reinterpret_cast<long>(newValue), reinterpret_cast<long>(oldValue)) == reinterpret_cast<long>(oldValue);
60  #endif
61 #else
62  #if !defined(__clang__) && !defined(__INTEL_COMPILER)
63  return __sync_bool_compare_and_swap(v, oldValue, newValue);
64  #else
65  /* Use the following workaround for clang and icl (Linux/Mac OS) */
66  #if __SIZEOF_POINTER__ == 8 || defined(__LP64__)
67  return __sync_bool_compare_and_swap(
68  reinterpret_cast<long long volatile *>(v), reinterpret_cast<long long>(oldValue),
69  reinterpret_cast<long long>(newValue));
70  #else
71  return __sync_bool_compare_and_swap(
72  reinterpret_cast<long volatile *>(v), reinterpret_cast<long>(oldValue),
73  reinterpret_cast<long>(newValue));
74  #endif
75  #endif
76 #endif
77 }
78 
79 /**
80  * \brief Atomically attempt to exchange a 32-bit integer with another value
81  *
82  * \param v Pointer to the memory region in question
83  * \param oldValue Last known value of the destination \a v
84  * \param newValue Replacement value for the destination \a v
85  * \return \c true if \c *v was equal to \c oldValue and the exchange
86  * was successful.
87  */
88 
89 inline bool atomicCompareAndExchange(volatile int32_t *v, int32_t newValue, int32_t oldValue) {
90 #if defined(_MSC_VER)
91  return _InterlockedCompareExchange(
92  reinterpret_cast<volatile long *>(v), newValue, oldValue) == oldValue;
93 #else
94  return __sync_bool_compare_and_swap(v, oldValue, newValue);
95 #endif
96 }
97 
98 /**
99  * \brief Atomically attempt to exchange a 64-bit integer with another value
100  *
101  * \param v Pointer to the memory region in question
102  * \param oldValue Last known value of the destination \a v
103  * \param newValue Replacement value for the destination \a v
104  * \return \c true if \c *v was equal to \c oldValue and the exchange
105  * was successful.
106  */
107 
108 inline bool atomicCompareAndExchange(volatile int64_t *v, int64_t newValue, int64_t oldValue) {
109 #if defined(_MSC_VER)
110  return _InterlockedCompareExchange64(
111  reinterpret_cast<volatile __int64 *>(v), newValue, oldValue) == oldValue;
112 #else
113  return __sync_bool_compare_and_swap(v, oldValue, newValue);
114 #endif
115 }
116 
117 /**
118  * \brief Atomically add \a delta to the floating point destination \a dst
119  *
120  * \return The final value written to \a dst
121  */
122 inline float atomicAdd(volatile float *dst, float delta) {
123  /* Atomic FP addition from PBRT */
124  union bits { float f; int32_t i; };
125  bits oldVal, newVal;
126  do {
127  // On IA32/x64, adding a PAUSE instruction in compare/exchange loops
128  // is recommended to improve performance. (And it does!)
129 #if (defined(__i386__) || defined(__amd64__))
130  __asm__ __volatile__ ("pause\n");
131 #endif
132  oldVal.f = *dst;
133  newVal.f = oldVal.f + delta;
134  } while (!atomicCompareAndExchange((volatile int32_t *) dst, newVal.i, oldVal.i));
135  return newVal.f;
136 }
137 
138 /**
139  * \brief Atomically add \a delta to the floating point destination \a dst
140  *
141  * \return The final value written to \a dst
142  */
143 inline double atomicAdd(volatile double *dst, double delta) {
144  /* Atomic FP addition from PBRT */
145  union bits { double f; int64_t i; };
146  bits oldVal, newVal;
147  do {
148  // On IA64/x64, adding a PAUSE instruction in compare/exchange loops
149  // is recommended to improve performance. (And it does!)
150 #if (defined(__i386__) || defined(__amd64__))
151  __asm__ __volatile__ ("pause\n");
152 #endif
153  oldVal.f = *dst;
154  newVal.f = oldVal.f + delta;
155  } while (!atomicCompareAndExchange((volatile int64_t *) dst, newVal.i, oldVal.i));
156  return newVal.f;
157 }
158 
159 /**
160  * \brief Atomically add \a delta to the 32-bit integer destination \a dst
161  *
162  * \return The final value written to \a dst
163  */
164 
165 inline int32_t atomicAdd(volatile int32_t *dst, int32_t delta) {
166 #if defined(_MSC_VER)
167  return _InterlockedExchangeAdd(reinterpret_cast<volatile long *>(dst), delta) + delta;
168 #else
169  return __sync_add_and_fetch(dst, delta);
170 #endif
171 }
172 
173 /**
174  * \brief Atomically add \a delta to the 64-bit integer destination \a dst
175  *
176  * \return The final value written to \a dst
177  */
178 
179 inline int64_t atomicAdd(volatile int64_t *dst, int64_t delta) {
180 #if defined(_MSC_VER)
181  #if defined(_WIN64)
182  return _InterlockedExchangeAdd64(reinterpret_cast<volatile __int64 *>(dst), delta) + delta;
183  #else
184  SLog(EError, "atomicAdd() cannot handle 64-bit integers on WIN32");
185  return 0;
186  #endif
187 #else
188  return __sync_add_and_fetch(dst, delta);
189 #endif
190 }
191 
192 /**
193  * \brief Atomically set \c dst to the maximum of itself and \c value
194  * \return The maximum value now stored in \c dst
195  */
196 
197 inline int64_t atomicMaximum(volatile int64_t *dst, int64_t value) {
198  int64_t current;
199  do {
200  current = *dst;
201  if (value <= current)
202  return current;
203  #if (defined(__i386__) || defined(__amd64__))
204  __asm__ __volatile__ ("pause\n");
205  #endif
206  } while (!atomicCompareAndExchange(dst, value, current));
207 
208  return value;
209 }
210 
211 /*
212  * \brief Atomically set \c dst to the maximum of itself and \c value
213  * \return The maximum value now stored in \c dst
214  */
215 
216 inline int32_t atomicMaximum(volatile int32_t *dst, int32_t value) {
217  int32_t current;
218  do {
219  current = *dst;
220  if (value <= current)
221  return current;
222  #if (defined(__i386__) || defined(__amd32__))
223  __asm__ __volatile__ ("pause\n");
224  #endif
225  } while (!atomicCompareAndExchange(dst, value, current));
226 
227  return value;
228 }
229 
230 
231 /*! }@ */
232 
234 
235 #endif /* __MITSUBA_CORE_ATOMIC_H_ */
int64_t atomicAdd(volatile int64_t *dst, int64_t delta)
Atomically add delta to the 64-bit integer destination dst.
Definition: atomic.h:179
bool atomicCompareAndExchange(volatile int64_t *v, int64_t newValue, int64_t oldValue)
Atomically attempt to exchange a 64-bit integer with another value.
Definition: atomic.h:108
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
Error message, causes an exception to be thrown.
Definition: formatter.h:33
int32_t atomicMaximum(volatile int32_t *dst, int32_t value)
Definition: atomic.h:216
#define MTS_NAMESPACE_END
Definition: platform.h:138
bool atomicCompareAndExchangePtr(T **v, T *newValue, T *oldValue)
Atomically attempt to exchange a pointer with another value.
Definition: atomic.h:51