compatibility.h revision 1.1
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. 57extern "C" 58__attribute((dllimport)) void __attribute__((stdcall)) Sleep (unsigned long); 59#endif 60 61namespace __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 */ 365