]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_atomics.h
Initial vogl checkin
[vogl] / src / voglcore / vogl_atomics.h
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_atomics.h
28 #ifndef VOGL_ATOMICS_H
29 #define VOGL_ATOMICS_H
30
31 #include "vogl_core.h"
32
33 #ifdef WIN32
34 #pragma once
35 #endif
36
37 #ifdef WIN32
38 #include "vogl_winhdr.h"
39 #endif
40
41 #if defined(__GNUC__) && VOGL_PLATFORM_PC
42 extern __inline__ __attribute__((__always_inline__, __gnu_inline__)) void vogl_yield_processor()
43 {
44     __asm__ __volatile__("pause");
45 }
46 #else
47 VOGL_FORCE_INLINE void vogl_yield_processor()
48 {
49 #if VOGL_USE_MSVC_INTRINSICS
50 #if VOGL_PLATFORM_PC_X64
51     _mm_pause();
52 #else
53     YieldProcessor();
54 #endif
55 #else
56 // No implementation
57 #endif
58 }
59 #endif
60
61 #if VOGL_USE_WIN32_ATOMIC_FUNCTIONS
62 extern "C" __int64 _InterlockedCompareExchange64(__int64 volatile *Destination, __int64 Exchange, __int64 Comperand);
63 #if defined(_MSC_VER)
64 #pragma intrinsic(_InterlockedCompareExchange64)
65 #endif
66 #endif // VOGL_USE_WIN32_ATOMIC_FUNCTIONS
67
68 namespace vogl
69 {
70 #if VOGL_USE_WIN32_ATOMIC_FUNCTIONS
71     typedef volatile LONG atomic32_t;
72     typedef volatile LONGLONG atomic64_t;
73
74     // Returns the original value.
75     inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
76     {
77         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
78         return InterlockedCompareExchange(pDest, exchange, comparand);
79     }
80
81     // Returns the original value.
82     inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
83     {
84         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
85         return _InterlockedCompareExchange64(pDest, exchange, comparand);
86     }
87
88     // Returns the resulting incremented value.
89     inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
90     {
91         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
92         return InterlockedIncrement(pDest);
93     }
94
95     // Returns the resulting decremented value.
96     inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
97     {
98         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
99         return InterlockedDecrement(pDest);
100     }
101
102     // Returns the original value.
103     inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
104     {
105         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
106         return InterlockedExchange(pDest, val);
107     }
108
109     // Returns the resulting value.
110     inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
111     {
112         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
113         return InterlockedExchangeAdd(pDest, val) + val;
114     }
115
116     // Returns the original value.
117     inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
118     {
119         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
120         return InterlockedExchangeAdd(pDest, val);
121     }
122 #elif VOGL_USE_GCC_ATOMIC_BUILTINS
123     typedef volatile long atomic32_t;
124     typedef long nonvolatile_atomic32_t;
125     typedef VOGL_ALIGNED_BEGIN(8) volatile long long VOGL_ALIGNED_END(8) atomic64_t;
126     typedef long long nonvolatile_atomic64_t;
127
128     // Returns the original value.
129     inline nonvolatile_atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
130     {
131         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
132         return __sync_val_compare_and_swap(pDest, comparand, exchange);
133     }
134
135     // Returns the original value.
136     inline nonvolatile_atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
137     {
138         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
139         return __sync_val_compare_and_swap(pDest, comparand, exchange);
140     }
141
142     // Returns the resulting incremented value.
143     inline nonvolatile_atomic32_t atomic_increment32(atomic32_t volatile *pDest)
144     {
145         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
146         return __sync_add_and_fetch(pDest, 1);
147     }
148
149     // Returns the resulting decremented value.
150     inline nonvolatile_atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
151     {
152         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
153         return __sync_sub_and_fetch(pDest, 1);
154     }
155
156     // Returns the original value.
157     inline nonvolatile_atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
158     {
159         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
160         return __sync_lock_test_and_set(pDest, val);
161     }
162
163     // Returns the resulting value.
164     inline nonvolatile_atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
165     {
166         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
167         return __sync_add_and_fetch(pDest, val);
168     }
169
170     // Returns the original value.
171     inline nonvolatile_atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
172     {
173         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
174         return __sync_fetch_and_add(pDest, val);
175     }
176 #else
177 #define VOGL_NO_ATOMICS 1
178
179     // Atomic ops not supported - but try to do something reasonable. Assumes no threading at all.
180     typedef long atomic32_t;
181     typedef long long atomic64_t;
182
183     inline atomic32_t atomic_compare_exchange32(atomic32_t volatile *pDest, atomic32_t exchange, atomic32_t comparand)
184     {
185         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
186         atomic32_t cur = *pDest;
187         if (cur == comparand)
188             *pDest = exchange;
189         return cur;
190     }
191
192     inline atomic64_t atomic_compare_exchange64(atomic64_t volatile *pDest, atomic64_t exchange, atomic64_t comparand)
193     {
194         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 7) == 0);
195         atomic64_t cur = *pDest;
196         if (cur == comparand)
197             *pDest = exchange;
198         return cur;
199     }
200
201     inline atomic32_t atomic_increment32(atomic32_t volatile *pDest)
202     {
203         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
204         return (*pDest += 1);
205     }
206
207     inline atomic32_t atomic_decrement32(atomic32_t volatile *pDest)
208     {
209         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
210         return (*pDest -= 1);
211     }
212
213     inline atomic32_t atomic_exchange32(atomic32_t volatile *pDest, atomic32_t val)
214     {
215         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
216         atomic32_t cur = *pDest;
217         *pDest = val;
218         return cur;
219     }
220
221     inline atomic32_t atomic_add32(atomic32_t volatile *pDest, atomic32_t val)
222     {
223         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
224         return (*pDest += val);
225     }
226
227     inline atomic32_t atomic_exchange_add32(atomic32_t volatile *pDest, atomic32_t val)
228     {
229         VOGL_ASSERT((reinterpret_cast<ptr_bits_t>(pDest) & 3) == 0);
230         atomic32_t cur = *pDest;
231         *pDest += val;
232         return cur;
233     }
234 #endif
235
236 } // namespace vogl
237
238 #endif // VOGL_ATOMICS_H