• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/InterlockCounter.cpp

00001 /* Ported to SPL, orignal attribution below. */
00002 /* ---------------------------------------------------------------------------
00003    commonc++ - A C++ Common Class Library
00004    Copyright (C) 2005-2009  Mark A Lindner
00005 
00006    Ported from commonc++.
00007 
00008    This library is free software; you can redistribute it and/or
00009    modify it under the terms of the GNU Library General Public
00010    License as published by the Free Software Foundation; either
00011    version 2 of the License, or (at your option) any later version.
00012 
00013    This library is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016    Library General Public License for more details.
00017 
00018    You should have received a copy of the GNU Library General Public
00019    License along with this library; if not, write to the Free
00020    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021    ---------------------------------------------------------------------------
00022 */
00023 #include <spl/Environment.h>
00024 #include <spl/threading/InterlockCounter.h>
00025 #include <spl/threading/Thread.h>
00026 
00027 #ifdef _WINDOWS
00028 
00029 #include <spl/cleanwindows.h>
00030 
00031 int32 atomic_increment(volatile int32 *ptr)
00032 {
00033         int32 r = InterlockedIncrement((LONG *)ptr);
00034 
00035         return r;
00036 }
00037 
00038 int32 atomic_decrement(volatile int32 *ptr)
00039 {
00040         int32 r = InterlockedDecrement((LONG *)ptr);
00041 
00042         return r;
00043 }
00044 
00045 int32 atomic_set(volatile int32 *ptr, int32 val)
00046 {
00047         *ptr = val;
00048 
00049         return val;
00050 }
00051 
00052 int32 atomic_add(volatile const int32 *ptr, int32 val)
00053 {
00054         int32 r = InterlockedExchangeAdd((LONG *)ptr, val);
00055 
00056         return r;
00057 }
00058 
00059 int32 atomic_cas(volatile int32 *ptr, int32 val, int32 cmp)
00060 {
00061 #if _MSC_VER > 1200
00062         return InterlockedCompareExchange((volatile LONG *)ptr, val, cmp);
00063 #else
00064         return *(int32 *)InterlockedCompareExchange((void **)&ptr, &val, &cmp);
00065 #endif
00066 }
00067 
00068 int32 atomic_swap(volatile int32 *ptr, int32 val)
00069 {
00070         return InterlockedExchange((LONG *)ptr, val);
00071 }
00072 #else
00073 
00074 static pthread_mutex_t __atomic_mutex = PTHREAD_MUTEX_INITIALIZER;
00075 
00076 int32 atomic_increment(volatile int32 *ptr)
00077 {
00078         int32 r;
00079 
00080         if (0 != pthread_mutex_lock(&__atomic_mutex))
00081         {
00082                 throw new IOException(Environment::LastErrorMessage());
00083         }
00084 
00085         r = ++(*ptr);
00086 
00087         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00088         {
00089                 throw new IOException(Environment::LastErrorMessage());
00090         }
00091 
00092         return r;
00093 }
00094 
00095 int32 atomic_decrement(volatile int32 *ptr)
00096 {
00097         int32 r;
00098 
00099         if (0 != pthread_mutex_lock(&__atomic_mutex))
00100         {
00101                 throw new IOException(Environment::LastErrorMessage());
00102         }
00103 
00104         r = --(*ptr);
00105 
00106         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00107         {
00108                 throw new IOException(Environment::LastErrorMessage());
00109         }
00110 
00111         return r;
00112 }
00113 
00114 int32 atomic_set(volatile int32 *ptr, int32 val)
00115 {
00116         if ( 0 != pthread_mutex_lock(&__atomic_mutex))
00117         {
00118                 throw new IOException(Environment::LastErrorMessage());
00119         }
00120 
00121         (*ptr) = val;
00122 
00123         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00124         {
00125                 throw new IOException(Environment::LastErrorMessage());
00126         }
00127 
00128         return val;
00129 }
00130 
00131 int32 atomic_add(volatile int32 *ptr, int32 val)
00132 {
00133         int32 r;
00134 
00135         if (0 != pthread_mutex_lock(&__atomic_mutex))
00136         {
00137                 throw new IOException(Environment::LastErrorMessage());
00138         }
00139 
00140         r = ((*ptr) += val);
00141 
00142         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00143         {
00144                 throw new IOException(Environment::LastErrorMessage());
00145         }
00146 
00147         return r;
00148 }
00149 
00150 int32 atomic_get(volatile const int32 *ptr)
00151 {
00152         int32 r;
00153 
00154         if (0 != pthread_mutex_lock(&__atomic_mutex))
00155         {
00156                 throw new IOException(Environment::LastErrorMessage());
00157         }
00158 
00159         r = *ptr;
00160 
00161         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00162         {
00163                 throw new IOException(Environment::LastErrorMessage());
00164         }
00165 
00166         return r;
00167 }
00168 
00169 int32 atomic_cas(volatile int32 *ptr, int32 val, int32 cmp)
00170 {
00171         int32 r;
00172 
00173         if (0 != pthread_mutex_lock(&__atomic_mutex))
00174         {
00175                 throw new IOException(Environment::LastErrorMessage());
00176         }
00177 
00178         r = *ptr;
00179 
00180         if((*ptr) == cmp)
00181         *ptr = val;
00182 
00183         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00184         {
00185                 throw new IOException(Environment::LastErrorMessage());
00186         }
00187 
00188         return r;
00189 }
00190 
00191 int32 atomic_swap(volatile int32 *ptr, int32 val)
00192 {
00193         int32 r;
00194 
00195         if (0 != pthread_mutex_lock(&__atomic_mutex))
00196         {
00197                 throw new IOException(Environment::LastErrorMessage());
00198         }
00199 
00200         r = *ptr;  
00201         *ptr = val;
00202 
00203         if (0 != pthread_mutex_unlock(&__atomic_mutex))
00204         {
00205                 throw new IOException(Environment::LastErrorMessage());
00206         }
00207 
00208         return r;
00209 }
00210 
00211 #endif
00212 
00213 InterlockCounter::InterlockCounter(int32 value /* = 0 */) throw()
00214 {
00215         operator=(value);
00216 }
00217 
00218 /*
00219  */
00220 
00221 InterlockCounter::~InterlockCounter() throw()
00222 {
00223 }
00224 
00225 /*
00226  */
00227 
00228 int32 InterlockCounter::operator++() throw()
00229 {
00230         // prefix
00231         return atomic_increment(&_atomic);
00232 }
00233 
00234 /*
00235  */
00236 
00237 int32 InterlockCounter::operator++(int) throw()
00238 {
00239         // postfix
00240         int32 r = atomic_increment(&_atomic);
00241         return --r;
00242 }
00243 
00244 /*
00245  */
00246 
00247 int32 InterlockCounter::operator--() throw()
00248 {
00249         // prefix
00250         return atomic_decrement(&_atomic);
00251 }
00252 
00253 /*
00254  */
00255 
00256 int32 InterlockCounter::operator--(int) throw()
00257 {
00258         // postfix
00259         int32 r = atomic_decrement(&_atomic);
00260         return ++r;
00261 }
00262 
00263 /*
00264  */
00265 
00266 int32 InterlockCounter::operator+=(int32 delta) throw()
00267 {
00268         return atomic_add(&_atomic, delta);
00269 }
00270 
00271 /*
00272  */
00273 
00274 int32 InterlockCounter::operator-=(int32 delta) throw()
00275 {
00276         return atomic_add(&_atomic, -delta);
00277 }
00278 
00279 /*
00280  */
00281 
00282 int32 InterlockCounter::operator+(int32 delta) const throw()
00283 {
00284         return Get() + delta;
00285 }
00286 
00287 /*
00288  */
00289 
00290 int32 InterlockCounter::operator-(int32 delta) const throw()
00291 {
00292         return Get() - delta;
00293 }
00294 
00295 /*
00296  */
00297 
00298 int32 InterlockCounter::operator=(int32 value) throw()
00299 {
00300         atomic_set(&_atomic, value);
00301 
00302         return value;
00303 }
00304 
00305 /*
00306  */
00307 
00308 int32 InterlockCounter::Set(int32 value) throw()
00309 {
00310         return atomic_set(&_atomic, value);
00311 }
00312 
00313 /*
00314  */
00315 
00316 int32 InterlockCounter::Get() const throw()
00317 {
00318 #ifdef WIN32
00319         return(atomic_add(&_atomic, 0));
00320 #else
00321         return atomic_get(&_atomic);
00322 #endif
00323 }
00324 
00325 /*
00326  */
00327 
00328 int32 InterlockCounter::Swap(int32 value) throw()
00329 {
00330         return atomic_swap(&_atomic, value);
00331 }
00332 
00333 /*
00334  */
00335 
00336 int32 InterlockCounter::TestAndSet(int32 value, int32 comparand) throw()
00337 {
00338         return atomic_cas(&_atomic, value, comparand);
00339 }
00340 
00341 /*
00342  */
00343 
00344 InterlockCounter::InterlockCounter(const InterlockCounter& other) throw()
00345 {
00346         Set(other.Get());
00347 }
00348 
00349 /*
00350  */
00351 
00352 InterlockCounter& InterlockCounter::operator=(const InterlockCounter& other) throw()
00353 {
00354         Set(other.Get());
00355 
00356         return *this;
00357 }