]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libstdc++-v3/contrib/libstdc++-v3-4.6/include/parallel/compatibility.h
update
[l4.git] / l4 / pkg / libstdc++-v3 / contrib / libstdc++-v3-4.6 / include / parallel / compatibility.h
1 // -*- C++ -*-
2
3 // Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the terms
7 // of the GNU General Public License as published by the Free Software
8 // Foundation; either version 3, or (at your option) any later
9 // version.
10
11 // This library is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24
25 /** @file parallel/compatibility.h
26  *  @brief Compatibility layer, mostly concerned with atomic operations.
27  *  This file is a GNU parallel extension to the Standard C++ Library.
28  */
29
30 // Written by Felix Putze.
31
32 #ifndef _GLIBCXX_PARALLEL_COMPATIBILITY_H
33 #define _GLIBCXX_PARALLEL_COMPATIBILITY_H 1
34
35 #include <parallel/types.h>
36 #include <parallel/base.h>
37
38 #if defined(__SUNPRO_CC) && defined(__sparc)
39 #include <sys/atomic.h>
40 #endif
41
42 #if !defined(_WIN32) || defined (__CYGWIN__)
43 #include <sched.h>
44 #endif
45
46 #if defined(_MSC_VER)
47 #include <Windows.h>
48 #include <intrin.h>
49 #undef max
50 #undef min
51 #endif
52
53 #ifdef __MINGW32__
54 // Including <windows.h> will drag in all the windows32 names.  Since
55 // that can cause user code portability problems, we just declare the
56 // one needed function here.
57 extern "C"
58 __attribute((dllimport)) void __attribute__((stdcall)) Sleep (unsigned long);
59 #endif
60
61 namespace __gnu_parallel
62 {
63 #if defined(__ICC)
64   template<typename _MustBeInt = int>
65   int32_t __faa32(int32_t* __x, int32_t __inc)
66   {
67     asm volatile("lock xadd %0,%1"
68                  : "=__r" (__inc), "=__m" (*__x)
69                  : "0" (__inc)
70                  : "memory");
71     return __inc;
72   }
73 #if defined(__x86_64)
74   template<typename _MustBeInt = int>
75   int64_t __faa64(int64_t* __x, int64_t __inc)
76   {
77     asm volatile("lock xadd %0,%1"
78                  : "=__r" (__inc), "=__m" (*__x)
79                  : "0" (__inc)
80                  : "memory");
81     return __inc;
82   }
83 #endif
84 #endif
85
86   // atomic functions only work on integers
87
88   /** @brief Add a value to a variable, atomically.
89    *
90    *  Implementation is heavily platform-dependent.
91    *  @param __ptr Pointer to a 32-bit signed integer.
92    *  @param __addend Value to add.
93    */
94   inline int32_t
95   __fetch_and_add_32(volatile int32_t* __ptr, int32_t __addend)
96   {
97 #if defined(__ICC)      //x86 version
98     return _InterlockedExchangeAdd((void*)__ptr, __addend);
99 #elif defined(__ECC)    //IA-64 version
100     return _InterlockedExchangeAdd((void*)__ptr, __addend);
101 #elif defined(__ICL) || defined(_MSC_VER)
102     return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(__ptr),
103                                    __addend);
104 #elif defined(__GNUC__)
105     return __sync_fetch_and_add(__ptr, __addend);
106 #elif defined(__SUNPRO_CC) && defined(__sparc)
107     volatile int32_t __before, __after;
108     do
109       {
110         __before = *__ptr;
111         __after = __before + __addend;
112       } while (atomic_cas_32((volatile unsigned int*)__ptr, __before,
113                              __after) != __before);
114     return __before;
115 #else   //fallback, slow
116 #pragma message("slow __fetch_and_add_32")
117     int32_t __res;
118 #pragma omp critical
119     {
120       __res = *__ptr;
121       *(__ptr) += __addend;
122     }
123     return __res;
124 #endif
125   }
126
127   /** @brief Add a value to a variable, atomically.
128    *
129    *  Implementation is heavily platform-dependent.
130    *  @param __ptr Pointer to a 64-bit signed integer.
131    *  @param __addend Value to add.
132    */
133   inline int64_t
134   __fetch_and_add_64(volatile int64_t* __ptr, int64_t __addend)
135   {
136 #if defined(__ICC) && defined(__x86_64) //x86 version
137     return __faa64<int>((int64_t*)__ptr, __addend);
138 #elif defined(__ECC)    //IA-64 version
139     return _InterlockedExchangeAdd64((void*)__ptr, __addend);
140 #elif defined(__ICL) || defined(_MSC_VER)
141 #ifndef _WIN64
142     _GLIBCXX_PARALLEL_ASSERT(false);    //not available in this case
143     return 0;
144 #else
145     return _InterlockedExchangeAdd64(__ptr, __addend);
146 #endif
147 #elif defined(__GNUC__) && defined(__x86_64)
148     return __sync_fetch_and_add(__ptr, __addend);
149 #elif defined(__GNUC__) && defined(__i386) &&                   \
150   (defined(__i686) || defined(__pentium4) || defined(__athlon)  \
151    || defined(__k8) || defined(__core2))
152     return __sync_fetch_and_add(__ptr, __addend);
153 #elif defined(__SUNPRO_CC) && defined(__sparc)
154     volatile int64_t __before, __after;
155     do
156       {
157         __before = *__ptr;
158         __after = __before + __addend;
159       } while (atomic_cas_64((volatile unsigned long long*)__ptr, __before,
160                              __after) != __before);
161     return __before;
162 #else   //fallback, slow
163 #if defined(__GNUC__) && defined(__i386)
164     // XXX doesn'__t work with -march=native
165     //#warning "please compile with -march=i686 or better"
166 #endif
167 #pragma message("slow __fetch_and_add_64")
168     int64_t __res;
169 #pragma omp critical
170     {
171       __res = *__ptr;
172       *(__ptr) += __addend;
173     }
174     return __res;
175 #endif
176   }
177
178   /** @brief Add a value to a variable, atomically.
179    *
180    *  Implementation is heavily platform-dependent.
181    *  @param __ptr Pointer to a signed integer.
182    *  @param __addend Value to add.
183    */
184   template<typename _Tp>
185   inline _Tp
186   __fetch_and_add(volatile _Tp* __ptr, _Tp __addend)
187   {
188     if (sizeof(_Tp) == sizeof(int32_t))
189       return
190         (_Tp)__fetch_and_add_32((volatile int32_t*) __ptr, (int32_t)__addend);
191     else if (sizeof(_Tp) == sizeof(int64_t))
192       return
193         (_Tp)__fetch_and_add_64((volatile int64_t*) __ptr, (int64_t)__addend);
194     else
195       _GLIBCXX_PARALLEL_ASSERT(false);
196   }
197
198
199 #if defined(__ICC)
200
201   template<typename _MustBeInt = int>
202   inline int32_t
203   __cas32(volatile int32_t* __ptr, int32_t __old, int32_t __nw)
204   {
205     int32_t __before;
206     __asm__ __volatile__("lock; cmpxchgl %1,%2"
207                          : "=a"(__before)
208                          : "q"(__nw), "__m"(*(volatile long long*)(__ptr)),
209                                "0"(__old)
210                          : "memory");
211     return __before;
212   }
213
214 #if defined(__x86_64)
215   template<typename _MustBeInt = int>
216   inline int64_t
217   __cas64(volatile int64_t *__ptr, int64_t __old, int64_t __nw)
218   {
219     int64_t __before;
220     __asm__ __volatile__("lock; cmpxchgq %1,%2"
221                          : "=a"(__before)
222                          : "q"(__nw), "__m"(*(volatile long long*)(__ptr)),
223                                "0"(__old)
224                          : "memory");
225     return __before;
226   }
227 #endif
228
229 #endif
230
231   /** @brief Compare @c *__ptr and @c __comparand. If equal, let @c
232    * *__ptr=__replacement and return @c true, return @c false otherwise.
233    *
234    *  Implementation is heavily platform-dependent.
235    *  @param __ptr Pointer to 32-bit signed integer.
236    *  @param __comparand Compare value.
237    *  @param __replacement Replacement value.
238    */
239   inline bool
240   __compare_and_swap_32(volatile int32_t* __ptr, int32_t __comparand,
241                         int32_t __replacement)
242   {
243 #if defined(__ICC)      //x86 version
244     return _InterlockedCompareExchange((void*)__ptr, __replacement,
245                                        __comparand) == __comparand;
246 #elif defined(__ECC)    //IA-64 version
247     return _InterlockedCompareExchange((void*)__ptr, __replacement,
248                                        __comparand) == __comparand;
249 #elif defined(__ICL) || defined(_MSC_VER)
250     return _InterlockedCompareExchange(
251                reinterpret_cast<volatile long*>(__ptr),
252                __replacement, __comparand)
253              == __comparand;
254 #elif defined(__GNUC__)
255     return __sync_bool_compare_and_swap(__ptr, __comparand, __replacement);
256 #elif defined(__SUNPRO_CC) && defined(__sparc)
257     return atomic_cas_32((volatile unsigned int*)__ptr, __comparand,
258                          __replacement) == __comparand;
259 #else
260 #pragma message("slow __compare_and_swap_32")
261     bool __res = false;
262 #pragma omp critical
263     {
264       if (*__ptr == __comparand)
265         {
266           *__ptr = __replacement;
267           __res = true;
268         }
269     }
270     return __res;
271 #endif
272   }
273
274   /** @brief Compare @c *__ptr and @c __comparand. If equal, let @c
275    * *__ptr=__replacement and return @c true, return @c false otherwise.
276    *
277    *  Implementation is heavily platform-dependent.
278    *  @param __ptr Pointer to 64-bit signed integer.
279    *  @param __comparand Compare value.
280    *  @param __replacement Replacement value.
281    */
282   inline bool
283   __compare_and_swap_64(volatile int64_t* __ptr, int64_t __comparand,
284                         int64_t __replacement)
285   {
286 #if defined(__ICC) && defined(__x86_64) //x86 version
287     return __cas64<int>(__ptr, __comparand, __replacement) == __comparand;
288 #elif defined(__ECC)    //IA-64 version
289     return _InterlockedCompareExchange64((void*)__ptr, __replacement,
290                                          __comparand) == __comparand;
291 #elif defined(__ICL) || defined(_MSC_VER)
292 #ifndef _WIN64
293     _GLIBCXX_PARALLEL_ASSERT(false);    //not available in this case
294     return 0;
295 #else
296     return _InterlockedCompareExchange64(__ptr, __replacement,
297                                          __comparand) == __comparand;
298 #endif
299
300 #elif defined(__GNUC__) && defined(__x86_64)
301     return __sync_bool_compare_and_swap(__ptr, __comparand, __replacement);
302 #elif defined(__GNUC__) && defined(__i386) &&                   \
303   (defined(__i686) || defined(__pentium4) || defined(__athlon)  \
304    || defined(__k8) || defined(__core2))
305     return __sync_bool_compare_and_swap(__ptr, __comparand, __replacement);
306 #elif defined(__SUNPRO_CC) && defined(__sparc)
307     return atomic_cas_64((volatile unsigned long long*)__ptr,
308                          __comparand, __replacement) == __comparand;
309 #else
310 #if defined(__GNUC__) && defined(__i386)
311     // XXX -march=native
312     //#warning "please compile with -march=i686 or better"
313 #endif
314 #pragma message("slow __compare_and_swap_64")
315     bool __res = false;
316 #pragma omp critical
317     {
318       if (*__ptr == __comparand)
319         {
320           *__ptr = __replacement;
321           __res = true;
322         }
323     }
324     return __res;
325 #endif
326   }
327
328   /** @brief Compare @c *__ptr and @c __comparand. If equal, let @c
329    * *__ptr=__replacement and return @c true, return @c false otherwise.
330    *
331    *  Implementation is heavily platform-dependent.
332    *  @param __ptr Pointer to signed integer.
333    *  @param __comparand Compare value.
334    *  @param __replacement Replacement value. */
335   template<typename _Tp>
336   inline bool
337   __compare_and_swap(volatile _Tp* __ptr, _Tp __comparand, _Tp __replacement)
338   {
339     if (sizeof(_Tp) == sizeof(int32_t))
340       return __compare_and_swap_32((volatile int32_t*) __ptr,
341                                    (int32_t)__comparand,
342                                    (int32_t)__replacement);
343     else if (sizeof(_Tp) == sizeof(int64_t))
344       return __compare_and_swap_64((volatile int64_t*) __ptr,
345                                    (int64_t)__comparand,
346                                    (int64_t)__replacement);
347     else
348       _GLIBCXX_PARALLEL_ASSERT(false);
349   }
350
351   /** @brief Yield the control to another thread, without waiting for
352       the end to the time slice. */
353   inline void
354   __yield()
355   {
356 #if defined (_WIN32) && !defined (__CYGWIN__)
357     Sleep(0);
358 #else
359     sched_yield();
360 #endif
361   }
362 } // end namespace
363
364 #endif /* _GLIBCXX_PARALLEL_COMPATIBILITY_H */