parallel/compatibility.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // Copyright (C) 2007, 2008 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the terms
00007 // of the GNU General Public License as published by the Free Software
00008 // Foundation; either version 2, or (at your option) any later
00009 // version.
00010 
00011 // This library is distributed in the hope that it will be useful, but
00012 // WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // General Public License for more details.
00015 
00016 // You should have received a copy of the GNU General Public License
00017 // along with this library; see the file COPYING.  If not, write to
00018 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
00019 // MA 02111-1307, USA.
00020 
00021 // As a special exception, you may use this file as part of a free
00022 // software library without restriction.  Specifically, if other files
00023 // instantiate templates or use macros or inline functions from this
00024 // file, or you compile this file and link it with other files to
00025 // produce an executable, this file does not by itself cause the
00026 // resulting executable to be covered by the GNU General Public
00027 // License.  This exception does not however invalidate any other
00028 // reasons why the executable file might be covered by the GNU General
00029 // Public License.
00030 
00031 /** @file parallel/compatibility.h
00032  *  @brief Compatibility layer, mostly concerned with atomic operations.
00033  *  This file is a GNU parallel extension to the Standard C++ Library.
00034  */
00035 
00036 // Written by Felix Putze.
00037 
00038 #ifndef _GLIBCXX_PARALLEL_COMPATIBILITY_H
00039 #define _GLIBCXX_PARALLEL_COMPATIBILITY_H 1
00040 
00041 #include <parallel/types.h>
00042 #include <parallel/base.h>
00043 
00044 #if defined(__SUNPRO_CC) && defined(__sparc)
00045 #include <sys/atomic.h>
00046 #endif
00047 
00048 #if !defined(_WIN32) || defined (__CYGWIN__)
00049 #include <sched.h>
00050 #endif
00051 
00052 #if defined(_MSC_VER)
00053 #include <Windows.h>
00054 #include <intrin.h>
00055 #undef max
00056 #undef min
00057 #endif
00058 
00059 #ifdef __MINGW32__
00060 // Including <windows.h> will drag in all the windows32 names.  Since
00061 // that can cause user code portability problems, we just declare the
00062 // one needed function here.
00063 extern "C"
00064 __attribute((dllimport)) void __attribute__((stdcall)) Sleep (unsigned long);
00065 #endif
00066 
00067 namespace __gnu_parallel
00068 {
00069 #if defined(__ICC)
00070   template<typename must_be_int = int>
00071   int32 faa32(int32* x, int32 inc)
00072   {
00073     asm volatile("lock xadd %0,%1"
00074          : "=r" (inc), "=m" (*x)
00075          : "0" (inc)
00076          : "memory");
00077     return inc;
00078   }
00079 #if defined(__x86_64)
00080   template<typename must_be_int = int>
00081   int64 faa64(int64* x, int64 inc)
00082   {
00083     asm volatile("lock xadd %0,%1"
00084          : "=r" (inc), "=m" (*x)
00085          : "0" (inc)
00086          : "memory");
00087     return inc;
00088   }
00089 #endif
00090 #endif
00091 
00092   // atomic functions only work on integers
00093 
00094   /** @brief Add a value to a variable, atomically.
00095    *
00096    *  Implementation is heavily platform-dependent.
00097    *  @param ptr Pointer to a 32-bit signed integer.
00098    *  @param addend Value to add.
00099    */
00100   inline int32
00101   fetch_and_add_32(volatile int32* ptr, int32 addend)
00102   {
00103 #if defined(__ICC)  //x86 version
00104     return _InterlockedExchangeAdd((void*)ptr, addend);
00105 #elif defined(__ECC)    //IA-64 version
00106     return _InterlockedExchangeAdd((void*)ptr, addend);
00107 #elif defined(__ICL) || defined(_MSC_VER)
00108     return _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(ptr),
00109                    addend);
00110 #elif defined(__GNUC__)
00111     return __sync_fetch_and_add(ptr, addend);
00112 #elif defined(__SUNPRO_CC) && defined(__sparc)
00113     volatile int32 before, after;
00114     do
00115       {
00116     before = *ptr;
00117     after = before + addend;
00118       } while (atomic_cas_32((volatile unsigned int*)ptr, before,
00119                  after) != before);
00120     return before;
00121 #else   //fallback, slow
00122 #pragma message("slow fetch_and_add_32")
00123     int32 res;
00124 #pragma omp critical
00125     {
00126       res = *ptr;
00127       *(ptr) += addend;
00128     }
00129     return res;
00130 #endif
00131   }
00132 
00133   /** @brief Add a value to a variable, atomically.
00134    *
00135    *  Implementation is heavily platform-dependent.
00136    *  @param ptr Pointer to a 64-bit signed integer.
00137    *  @param addend Value to add.
00138    */
00139   inline int64
00140   fetch_and_add_64(volatile int64* ptr, int64 addend)
00141   {
00142 #if defined(__ICC) && defined(__x86_64) //x86 version
00143     return faa64<int>((int64*)ptr, addend);
00144 #elif defined(__ECC)    //IA-64 version
00145     return _InterlockedExchangeAdd64((void*)ptr, addend);
00146 #elif defined(__ICL) || defined(_MSC_VER)
00147 #ifndef _WIN64
00148     _GLIBCXX_PARALLEL_ASSERT(false);    //not available in this case
00149     return 0;
00150 #else
00151     return _InterlockedExchangeAdd64(ptr, addend);
00152 #endif
00153 #elif defined(__GNUC__) && defined(__x86_64)
00154     return __sync_fetch_and_add(ptr, addend);
00155 #elif defined(__GNUC__) && defined(__i386) &&           \
00156   (defined(__i686) || defined(__pentium4) || defined(__athlon))
00157     return __sync_fetch_and_add(ptr, addend);
00158 #elif defined(__SUNPRO_CC) && defined(__sparc)
00159     volatile int64 before, after;
00160     do
00161       {
00162     before = *ptr;
00163     after = before + addend;
00164       } while (atomic_cas_64((volatile unsigned long long*)ptr, before,
00165                  after) != before);
00166     return before;
00167 #else   //fallback, slow
00168 #if defined(__GNUC__) && defined(__i386)
00169     // XXX doesn't work with -march=native
00170     //#warning "please compile with -march=i686 or better"
00171 #endif
00172 #pragma message("slow fetch_and_add_64")
00173     int64 res;
00174 #pragma omp critical
00175     {
00176       res = *ptr;
00177       *(ptr) += addend;
00178     }
00179     return res;
00180 #endif
00181   }
00182 
00183   /** @brief Add a value to a variable, atomically.
00184    *
00185    *  Implementation is heavily platform-dependent.
00186    *  @param ptr Pointer to a signed integer.
00187    *  @param addend Value to add.
00188    */
00189   template<typename T>
00190   inline T
00191   fetch_and_add(volatile T* ptr, T addend)
00192   {
00193     if (sizeof(T) == sizeof(int32))
00194       return (T)fetch_and_add_32((volatile int32*) ptr, (int32)addend);
00195     else if (sizeof(T) == sizeof(int64))
00196       return (T)fetch_and_add_64((volatile int64*) ptr, (int64)addend);
00197     else
00198       _GLIBCXX_PARALLEL_ASSERT(false);
00199   }
00200 
00201 
00202 #if defined(__ICC)
00203 
00204   template<typename must_be_int = int>
00205   inline int32
00206   cas32(volatile int32* ptr, int32 old, int32 nw)
00207   {
00208     int32 before;
00209     __asm__ __volatile__("lock; cmpxchgl %1,%2"
00210              : "=a"(before)
00211              : "q"(nw), "m"(*(volatile long long*)(ptr)), "0"(old)
00212              : "memory");
00213     return before;
00214   }
00215 
00216 #if defined(__x86_64)
00217   template<typename must_be_int = int>
00218   inline int64
00219   cas64(volatile int64 *ptr, int64 old, int64 nw)
00220   {
00221     int64 before;
00222     __asm__ __volatile__("lock; cmpxchgq %1,%2"
00223              : "=a"(before)
00224              : "q"(nw), "m"(*(volatile long long*)(ptr)), "0"(old)
00225              : "memory");
00226     return before;
00227   }
00228 #endif
00229 
00230 #endif
00231 
00232   /** @brief Compare @c *ptr and @c comparand. If equal, let @c
00233    * *ptr=replacement and return @c true, return @c false otherwise.
00234    *
00235    *  Implementation is heavily platform-dependent.
00236    *  @param ptr Pointer to 32-bit signed integer.
00237    *  @param comparand Compare value.
00238    *  @param replacement Replacement value.
00239    */
00240   inline bool
00241   compare_and_swap_32(volatile int32* ptr, int32 comparand, int32 replacement)
00242   {
00243 #if defined(__ICC)  //x86 version
00244     return _InterlockedCompareExchange((void*)ptr, replacement,
00245                        comparand) == comparand;
00246 #elif defined(__ECC)    //IA-64 version
00247     return _InterlockedCompareExchange((void*)ptr, replacement,
00248                        comparand) == comparand;
00249 #elif defined(__ICL) || defined(_MSC_VER)
00250     return _InterlockedCompareExchange(reinterpret_cast<volatile long*>(ptr),
00251                        replacement, comparand) == comparand;
00252 #elif defined(__GNUC__)
00253     return __sync_bool_compare_and_swap(ptr, comparand, replacement);
00254 #elif defined(__SUNPRO_CC) && defined(__sparc)
00255     return atomic_cas_32((volatile unsigned int*)ptr, comparand,
00256              replacement) == comparand;
00257 #else
00258 #pragma message("slow compare_and_swap_32")
00259     bool res = false;
00260 #pragma omp critical
00261     {
00262       if (*ptr == comparand)
00263     {
00264       *ptr = replacement;
00265       res = true;
00266     }
00267     }
00268     return res;
00269 #endif
00270   }
00271 
00272   /** @brief Compare @c *ptr and @c comparand. If equal, let @c
00273    * *ptr=replacement and return @c true, return @c false otherwise.
00274    *
00275    *  Implementation is heavily platform-dependent.
00276    *  @param ptr Pointer to 64-bit signed integer.
00277    *  @param comparand Compare value.
00278    *  @param replacement Replacement value.
00279    */
00280   inline bool
00281   compare_and_swap_64(volatile int64* ptr, int64 comparand, int64 replacement)
00282   {
00283 #if defined(__ICC) && defined(__x86_64) //x86 version
00284     return cas64<int>(ptr, comparand, replacement) == comparand;
00285 #elif defined(__ECC)    //IA-64 version
00286     return _InterlockedCompareExchange64((void*)ptr, replacement,
00287                      comparand) == comparand;
00288 #elif defined(__ICL) || defined(_MSC_VER)
00289 #ifndef _WIN64
00290     _GLIBCXX_PARALLEL_ASSERT(false);    //not available in this case
00291     return 0;
00292 #else
00293     return _InterlockedCompareExchange64(ptr, replacement,
00294                      comparand) == comparand;
00295 #endif
00296 
00297 #elif defined(__GNUC__) && defined(__x86_64)
00298     return __sync_bool_compare_and_swap(ptr, comparand, replacement);
00299 #elif defined(__GNUC__) && defined(__i386) &&           \
00300   (defined(__i686) || defined(__pentium4) || defined(__athlon))
00301     return __sync_bool_compare_and_swap(ptr, comparand, replacement);
00302 #elif defined(__SUNPRO_CC) && defined(__sparc)
00303     return atomic_cas_64((volatile unsigned long long*)ptr,
00304              comparand, replacement) == comparand;
00305 #else
00306 #if defined(__GNUC__) && defined(__i386)
00307     // XXX -march=native
00308     //#warning "please compile with -march=i686 or better"
00309 #endif
00310 #pragma message("slow compare_and_swap_64")
00311     bool res = false;
00312 #pragma omp critical
00313     {
00314       if (*ptr == comparand)
00315     {
00316       *ptr = replacement;
00317       res = true;
00318     }
00319     }
00320     return res;
00321 #endif
00322   }
00323 
00324   /** @brief Compare @c *ptr and @c comparand. If equal, let @c
00325    * *ptr=replacement and return @c true, return @c false otherwise.
00326    *
00327    *  Implementation is heavily platform-dependent.
00328    *  @param ptr Pointer to signed integer.
00329    *  @param comparand Compare value.
00330    *  @param replacement Replacement value. */
00331   template<typename T>
00332   inline bool
00333   compare_and_swap(volatile T* ptr, T comparand, T replacement)
00334   {
00335     if (sizeof(T) == sizeof(int32))
00336       return compare_and_swap_32((volatile int32*) ptr, (int32)comparand, (int32)replacement);
00337     else if (sizeof(T) == sizeof(int64))
00338       return compare_and_swap_64((volatile int64*) ptr, (int64)comparand, (int64)replacement);
00339     else
00340       _GLIBCXX_PARALLEL_ASSERT(false);
00341   }
00342 
00343   /** @brief Yield the control to another thread, without waiting for
00344       the end to the time slice. */
00345   inline void
00346   yield()
00347   {
00348 #if defined (_WIN32) && !defined (__CYGWIN__)
00349     Sleep(0);
00350 #else
00351     sched_yield();
00352 #endif
00353   }
00354 } // end namespace
00355 
00356 #endif

Generated on Sat Dec 12 09:40:09 2009 for libstdc++ by  doxygen 1.5.6