Stefan Scholz / ETL
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers atomic_gcc.h Source File

atomic_gcc.h

00001 /******************************************************************************
00002 The MIT License(MIT)
00003 
00004 Embedded Template Library.
00005 https://github.com/ETLCPP/etl
00006 https://www.etlcpp.com
00007 
00008 Copyright(c) 2017 jwellbelove
00009 
00010 Permission is hereby granted, free of charge, to any person obtaining a copy
00011 of this software and associated documentation files(the "Software"), to deal
00012 in the Software without restriction, including without limitation the rights
00013 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
00014 copies of the Software, and to permit persons to whom the Software is
00015 furnished to do so, subject to the following conditions :
00016 
00017 The above copyright notice and this permission notice shall be included in all
00018 copies or substantial portions of the Software.
00019 
00020 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00021 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00022 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
00023 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00024 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00025 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00026 SOFTWARE.
00027 ******************************************************************************/
00028 
00029 #ifndef __ETL_ATOMIC_GCC__
00030 #define __ETL_ATOMIC_GCC__
00031 
00032 #include "../platform.h"
00033 #include "../type_traits.h"
00034 #include "../char_traits.h"
00035 #include "../static_assert.h"
00036 #include "../nullptr.h"
00037 
00038 #include <stdint.h>
00039 
00040 namespace etl
00041 {
00042   //***************************************************************************
00043   // Atomic type for pre C++11 GCC compilers that support the builtin 'fetch' functions.
00044   // Only integral and pointer types are supported.
00045   //***************************************************************************
00046   template <typename T>
00047   class atomic
00048   {
00049   public:
00050 
00051     STATIC_ASSERT(etl::is_integral<T>::value, "Only integral types are supported");
00052 
00053     atomic()
00054       : value(0)
00055     {
00056     }
00057 
00058     atomic(T v)
00059       : value(v)
00060     {
00061     }
00062 
00063     // Assignment
00064     T operator =(T v)
00065     {
00066       __sync_lock_test_and_set(&value, v);
00067 
00068       return v;
00069     }
00070 
00071     T operator =(T v) volatile
00072     {
00073       __sync_lock_test_and_set(&value, v);
00074 
00075       return v;
00076     }
00077 
00078     // Pre-increment
00079     T operator ++()
00080     {
00081       return fetch_add(1) + 1;
00082     }
00083 
00084     T operator ++() volatile
00085     {
00086       return fetch_add(1) + 1;
00087     }
00088 
00089     // Post-increment
00090     T operator ++(int)
00091     {
00092       return fetch_add(1);
00093     }
00094 
00095     T operator ++(int) volatile
00096     {
00097       return fetch_add(1);
00098     }
00099 
00100     // Pre-decrement
00101     T operator --()
00102     {
00103       return fetch_sub(1) + 1;
00104     }
00105 
00106     T operator --() volatile
00107     {
00108       return fetch_sub(1) + 1;
00109     }
00110 
00111     // Post-decrement
00112     T operator --(int)
00113     {
00114       return fetch_sub(1);
00115     }
00116 
00117     T operator --(int) volatile
00118     {
00119       return fetch_sub(1);
00120     }
00121 
00122     // Add
00123     T operator +=(T v)
00124     {
00125       return fetch_add(v) + v;
00126     }
00127 
00128     T operator +=(T v) volatile
00129     {
00130       return fetch_add(v) + v;
00131     }
00132 
00133     // Subtract
00134     T operator -=(T v)
00135     {
00136       return fetch_sub(v) - v;
00137     }
00138 
00139     T operator -=(T v) volatile
00140     {
00141       return fetch_sub(v) - v;
00142     }
00143 
00144     // And
00145     T operator &=(T v)
00146     {
00147       return fetch_and(v) & v;
00148     }
00149 
00150     T operator &=(T v) volatile
00151     {
00152       return fetch_and(v) & v;
00153     }
00154 
00155     // Or
00156     T operator |=(T v)
00157     {
00158       return fetch_or(v) | v;
00159     }
00160 
00161     T operator |=(T v) volatile
00162     {
00163       return fetch_or(v) | v;
00164     }
00165 
00166     // Exclusive or
00167     T operator ^=(T v)
00168     {
00169       return fetch_xor(v) ^ v;
00170     }
00171 
00172     T operator ^=(T v) volatile
00173     {
00174       return fetch_xor(v) ^ v;
00175     }
00176 
00177     // Conversion operator
00178     operator T () const
00179     {
00180       return __sync_fetch_and_add(const_cast<T*>(&value), 0);
00181     }
00182 
00183     operator T() volatile const
00184     {
00185       return __sync_fetch_and_add(const_cast<T*>(&value), 0);
00186     }
00187 
00188     // Is lock free?
00189     bool is_lock_free() const
00190     {
00191       return true;
00192     }
00193 
00194     bool is_lock_free() const volatile
00195     {
00196       return true;
00197     }
00198 
00199     // Store
00200     void store(T v)
00201     {
00202       __sync_lock_test_and_set(&value, v);
00203     }
00204 
00205     void store(T v) volatile
00206     {
00207       __sync_lock_test_and_set(&value, v);
00208     }
00209 
00210     // Load
00211     T load()
00212     {
00213       return __sync_fetch_and_add(&value, 0);
00214     }
00215 
00216     T load() volatile
00217     {
00218       return __sync_fetch_and_add(&value, 0);
00219     }
00220 
00221     // Fetch add
00222     T fetch_add(T v)
00223     {
00224       return __sync_fetch_and_add(&value, v);
00225     }
00226 
00227     T fetch_add(T v) volatile
00228     {
00229       return __sync_fetch_and_add(&value, v);
00230     }
00231 
00232     // Fetch subtract
00233     T fetch_sub(T v)
00234     {
00235       return __sync_fetch_and_sub(&value, v);
00236     }
00237 
00238     T fetch_sub(T v) volatile
00239     {
00240       return __sync_fetch_and_sub(&value, v);
00241     }
00242 
00243     // Fetch or
00244     T fetch_or(T v)
00245     {
00246       return __sync_fetch_and_or(&value, v);
00247     }
00248 
00249     T fetch_or(T v) volatile
00250     {
00251       return __sync_fetch_and_or(&value, v);
00252     }
00253 
00254     // Fetch and
00255     T fetch_and(T v)
00256     {
00257       return __sync_fetch_and_and(&value, v);
00258     }
00259 
00260     T fetch_and(T v) volatile
00261     {
00262       return __sync_fetch_and_and(&value, v);
00263     }
00264 
00265     // Fetch exclusive or
00266     T fetch_xor(T v)
00267     {
00268       return __sync_fetch_and_xor(&value, v);
00269     }
00270 
00271     T fetch_xor(T v) volatile
00272     {
00273       return __sync_fetch_and_xor(&value, v);
00274     }
00275 
00276     // Exchange
00277     T exchange(T v)
00278     {
00279       return __sync_lock_test_and_set(&value, v);
00280     }
00281 
00282     T exchange(T v) volatile
00283     {
00284       return __sync_lock_test_and_set(&value, v);
00285     }
00286 
00287     // Compare exchange weak
00288     bool compare_exchange_weak(T& expected, T desired)
00289     {
00290       T old = __sync_val_compare_and_swap(&value, expected, desired);
00291 
00292       if (old == expected)
00293       {
00294         return true;
00295       }
00296       else
00297       {
00298         expected = old;
00299         return false;
00300       }
00301     }
00302 
00303     bool compare_exchange_weak(T& expected, T desired) volatile
00304     {
00305       T old = __sync_val_compare_and_swap(&value, expected, desired);
00306 
00307       if (old == expected)
00308       {
00309         return true;
00310       }
00311       else
00312       {
00313         expected = old;
00314         return false;
00315       }
00316     }
00317 
00318     // Compare exchange strong
00319     bool compare_exchange_strong(T& expected, T desired)
00320     {
00321       T old = expected;
00322 
00323       while (!compare_exchange_weak(old, desired))
00324       {
00325         if (memcmp(&old, &expected, sizeof(T)))
00326         {
00327           expected = old;
00328           return false;
00329         }
00330       }
00331 
00332       return true;
00333     }
00334 
00335     bool compare_exchange_strong(T& expected, T desired) volatile
00336     {
00337       T old = expected;
00338 
00339       while (!compare_exchange_weak(old, desired))
00340       {
00341         if (memcmp(&old, &expected, sizeof(T)))
00342         {
00343           expected = old;
00344           return false;
00345         }
00346       }
00347 
00348       return true;
00349     }
00350 
00351   private:
00352 
00353     atomic& operator =(const atomic&);
00354     atomic& operator =(const atomic&) volatile;
00355 
00356     T value;
00357   };
00358 
00359   //***************************************************************************
00360   // Specialisation for pointers.
00361   //***************************************************************************
00362   template <typename T>
00363   class atomic<T*>
00364   {
00365   public:
00366 
00367     atomic()
00368       : value(std::nullptr)
00369     {
00370     }
00371 
00372     atomic(T v)
00373       : value(v)
00374     {
00375     }
00376 
00377     // Assignment
00378     T operator =(T* v)
00379     {
00380       __sync_lock_test_and_set(&value, v);
00381 
00382       return v;
00383     }
00384 
00385     T operator =(T* v) volatile
00386     {
00387       __sync_lock_test_and_set(&value, v);
00388 
00389       return v;
00390     }
00391 
00392     // Pre-increment
00393     T operator ++()
00394     {
00395       return fetch_add(1) + 1;
00396     }
00397 
00398     T operator ++() volatile
00399     {
00400       return fetch_add(1) + 1;
00401     }
00402 
00403     // Post-increment
00404     T operator ++(int)
00405     {
00406       return fetch_add(1);
00407     }
00408 
00409     T operator ++(int) volatile
00410     {
00411       return fetch_add(1);
00412     }
00413 
00414     // Pre-decrement
00415     T operator --()
00416     {
00417       return fetch_sub(1) + 1;
00418     }
00419 
00420     T operator --() volatile
00421     {
00422       return fetch_sub(1) + 1;
00423     }
00424 
00425     // Post-decrement
00426     T operator --(int)
00427     {
00428       return fetch_sub(1);
00429     }
00430 
00431     T operator --(int) volatile
00432     {
00433       return fetch_sub(1);
00434     }
00435 
00436     // Add
00437     T* operator +=(std::ptrdiff_t v)
00438     {
00439       return fetch_add(v) + v;
00440     }
00441 
00442     T* operator +=(std::ptrdiff_t v) volatile
00443     {
00444       return fetch_add(v) + v;
00445     }
00446 
00447     // Subtract
00448     T* operator -=(std::ptrdiff_t v)
00449     {
00450       return fetch_sub(v) - v;
00451     }
00452 
00453     T* operator -=(std::ptrdiff_t v) volatile
00454     {
00455       return fetch_sub(v) - v;
00456     }
00457 
00458     // Conversion operator
00459     operator T () const
00460     {
00461       return __sync_fetch_and_add(const_cast<T**>(&value), 0);
00462     }
00463 
00464     operator T() volatile const
00465     {
00466       return __sync_fetch_and_add(const_cast<T**>(&value), 0);
00467     }
00468 
00469     // Is lock free?
00470     bool is_lock_free() const
00471     {
00472       return true;
00473     }
00474 
00475     bool is_lock_free() const volatile
00476     {
00477       return true;
00478     }
00479 
00480     // Store
00481     void store(T v)
00482     {
00483       __sync_lock_test_and_set(&value, v);
00484     }
00485 
00486     void store(T v) volatile
00487     {
00488       __sync_lock_test_and_set(&value, v);
00489     }
00490 
00491     // Load
00492     T load()
00493     {
00494       return __sync_fetch_and_add(&value, 0);
00495     }
00496 
00497     T load() volatile
00498     {
00499       return __sync_fetch_and_add(&value, 0);
00500     }
00501 
00502     // Fetch add
00503     T* fetch_add(std::ptrdiff_t v)
00504     {
00505       return __sync_fetch_and_add(&value, v);
00506     }
00507 
00508     T* fetch_add(std::ptrdiff_t v) volatile
00509     {
00510       return __sync_fetch_and_add(&value, v);
00511     }
00512 
00513     // Fetch subtract
00514     T* fetch_sub(std::ptrdiff_t v)
00515     {
00516       return __sync_fetch_and_sub(&value, v);
00517     }
00518 
00519     T* fetch_sub(std::ptrdiff_t v) volatile
00520     {
00521       return __sync_fetch_and_sub(&value, v);
00522     }
00523 
00524     // Exchange
00525     T exchange(T v)
00526     {
00527       return __sync_lock_test_and_set(&value, v);
00528     }
00529 
00530     T exchange(T v) volatile
00531     {
00532       return __sync_lock_test_and_set(&value, v);
00533     }
00534 
00535     // Compare exchange weak
00536     bool compare_exchange_weak(T& expected, T desired)
00537     {
00538       return __sync_bool_compare_and_swap(&value, expected, desired);
00539     }
00540 
00541     bool compare_exchange_weak(T& expected, T desired) volatile
00542     {
00543       return __sync_bool_compare_and_swap(&value, expected, desired);
00544     }
00545 
00546     // Compare exchange strong
00547     bool compare_exchange_strong(T& expected, T desired)
00548     {
00549       T old = expected;
00550 
00551       while (!compare_exchange_weak(old, desired))
00552       {
00553         if (memcmp(&old, &expected, sizeof(T)))
00554         {
00555           expected = old;
00556           return false;
00557         }
00558       }
00559 
00560       return true;
00561     }
00562 
00563     bool compare_exchange_strong(T& expected, T desired) volatile
00564     {
00565       T old = expected;
00566 
00567       while (!compare_exchange_weak(old, desired))
00568       {
00569         if (memcmp(&old, &expected, sizeof(T)))
00570         {
00571           expected = old;
00572           return false;
00573         }
00574       }
00575 
00576       return true;
00577     }
00578 
00579   private:
00580 
00581     atomic& operator =(const atomic&);
00582     atomic& operator =(const atomic&) volatile;
00583 
00584     T* value;
00585   };
00586 
00587   typedef etl::atomic<char>                atomic_char;
00588   typedef etl::atomic<signed char>         atomic_schar;
00589   typedef etl::atomic<unsigned char>       atomic_uchar;
00590   typedef etl::atomic<short>               atomic_short;
00591   typedef etl::atomic<unsigned short>      atomic_ushort;
00592   typedef etl::atomic<int>                 atomic_int;
00593   typedef etl::atomic<unsigned int>        atomic_uint;
00594   typedef etl::atomic<long>                atomic_long;
00595   typedef etl::atomic<unsigned long>       atomic_ulong;
00596   typedef etl::atomic<long long>           atomic_llong;
00597   typedef etl::atomic<unsigned long long>  atomic_ullong;
00598   typedef etl::atomic<wchar_t>             atomic_wchar_t;
00599   typedef etl::atomic<char16_t>            atomic_char16_t;
00600   typedef etl::atomic<char32_t>            atomic_char32_t;
00601   typedef etl::atomic<uint8_t>             atomic_uint8_t;
00602   typedef etl::atomic<int8_t>              atomic_int8_t;
00603   typedef etl::atomic<uint16_t>            atomic_uint16_t;
00604   typedef etl::atomic<int16_t>             atomic_int16_t;
00605   typedef etl::atomic<uint32_t>            atomic_uint32_t;
00606   typedef etl::atomic<int32_t>             atomic_int32_t;
00607   typedef etl::atomic<uint64_t>            atomic_uint64_t;
00608   typedef etl::atomic<int64_t>             atomic_int64_t;
00609   typedef etl::atomic<int_least8_t>        atomic_int_least8_t;
00610   typedef etl::atomic<uint_least8_t>       atomic_uint_least8_t;
00611   typedef etl::atomic<int_least16_t>       atomic_int_least16_t;
00612   typedef etl::atomic<uint_least16_t>      atomic_uint_least16_t;
00613   typedef etl::atomic<int_least32_t>       atomic_int_least32_t;
00614   typedef etl::atomic<uint_least32_t>      atomic_uint_least32_t;
00615   typedef etl::atomic<int_least64_t>       atomic_int_least64_t;
00616   typedef etl::atomic<uint_least64_t>      atomic_uint_least64_t;
00617   typedef etl::atomic<int_fast8_t>         atomic_int_fast8_t;
00618   typedef etl::atomic<uint_fast8_t>        atomic_uint_fast8_t;
00619   typedef etl::atomic<int_fast16_t>        atomic_int_fast16_t;
00620   typedef etl::atomic<uint_fast16_t>       atomic_uint_fast16_t;
00621   typedef etl::atomic<int_fast32_t>        atomic_int_fast32_t;
00622   typedef etl::atomic<uint_fast32_t>       atomic_uint_fast32_t;
00623   typedef etl::atomic<int_fast64_t>        atomic_int_fast64_t;
00624   typedef etl::atomic<uint_fast64_t>       atomic_uint_fast64_t;
00625   typedef etl::atomic<intptr_t>            atomic_intptr_t;
00626   typedef etl::atomic<uintptr_t>           atomic_uintptr_t;
00627   typedef etl::atomic<size_t>              atomic_size_t;
00628   typedef etl::atomic<ptrdiff_t>           atomic_ptrdiff_t;
00629   typedef etl::atomic<intmax_t>            atomic_intmax_t;
00630   typedef etl::atomic<uintmax_t>           atomic_uintmax_t;
00631 }
00632 
00633 #endif
00634