# atomic_2.h

Go to the documentation of this file.

    00001 // -*- C++ -*- header.
    00002
    00003 // Copyright (C) 2008, 2009
    00004 // Free Software Foundation, Inc.
    00005 //
    00006 // This file is part of the GNU ISO C++ Library.  This library is free
    00007 // software; you can redistribute it and/or modify it under the
    00008 // terms of the GNU General Public License as published by the
    00009 // Free Software Foundation; either version 3, or (at your option)
    00010 // any later version.
    00011
    00012 // This library is distributed in the hope that it will be useful,
    00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00015 // GNU General Public License for more details.
    00016
    00017 // Under Section 7 of GPL version 3, you are granted additional
    00018 // permissions described in the GCC Runtime Library Exception, version
    00019 // 3.1, as published by the Free Software Foundation.
    00020
    00021 // You should have received a copy of the GNU General Public License and
    00022 // a copy of the GCC Runtime Library Exception along with this program;
    00023 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    00024 // <http://www.gnu.org/licenses/>.
    00025
    00026 /** @file bits/atomic_2.h
    00027  *  This is an internal header file, included by other library headers.
    00028  *  You should not attempt to use it directly.
    00029  */
    00030
    00031 #ifndef _GLIBCXX_ATOMIC_2_H
    00032 #define _GLIBCXX_ATOMIC_2_H 1
    00033
    00034 #pragma GCC system_header
    00035
    00036 // _GLIBCXX_BEGIN_NAMESPACE(std)
    00037
    00038 // 2 == __atomic2 == Always lock-free
    00039 // Assumed:
    00040 // _GLIBCXX_ATOMIC_BUILTINS_1
    00041 // _GLIBCXX_ATOMIC_BUILTINS_2
    00042 // _GLIBCXX_ATOMIC_BUILTINS_4
    00043 // _GLIBCXX_ATOMIC_BUILTINS_8
    00044 namespace __atomic2
    00045 {
    00046   /// atomic_flag
    00047   struct atomic_flag : private __atomic_flag_base
    00048   {
    00049     atomic_flag() = default;
    00050     ~atomic_flag() = default;
    00051     atomic_flag(const atomic_flag&) = delete;
    00052     atomic_flag& operator=(const atomic_flag&) = delete;
    00053
    00054     atomic_flag(bool __i) { _M_i = __i; } // XXX deleted copy ctor != agg
    00055
    00056     bool
    00057     test_and_set(memory_order __m = memory_order_seq_cst) volatile
    00058     {
    00059       // Redundant synchronize if built-in for lock is a full barrier.
    00060       if (__m != memory_order_acquire && __m != memory_order_acq_rel)
    00061     __sync_synchronize();
    00062       return __sync_lock_test_and_set(&_M_i, 1);
    00063     }
    00064
    00065     void
    00066     clear(memory_order __m = memory_order_seq_cst) volatile
    00067     {
    00068       __sync_lock_release(&_M_i);
    00069       if (__m != memory_order_acquire && __m != memory_order_acq_rel)
    00070     __sync_synchronize();
    00071     }
    00072   };
    00073
    00074
    00075   /// 29.4.2, address types
    00076   struct atomic_address
    00077   {
    00078   private:
    00079     void* _M_i;
    00080
    00081   public:
    00082     atomic_address() = default;
    00083     ~atomic_address() = default;
    00084     atomic_address(const atomic_address&) = delete;
    00085     atomic_address& operator=(const atomic_address&) = delete;
    00086
    00087     atomic_address(void* __v) { _M_i = __v; }
    00088
    00089     bool
    00090     is_lock_free() const volatile
    00091     { return true; }
    00092
    00093     void
    00094     store(void* __v, memory_order __m = memory_order_seq_cst) volatile
    00095     {
    00096       __glibcxx_assert(__m == memory_order_acquire);
    00097       __glibcxx_assert(__m == memory_order_acq_rel);
    00098       __glibcxx_assert(__m == memory_order_consume);
    00099
    00100       if (__m == memory_order_relaxed)
    00101     _M_i = __v;
    00102       else
    00103     {
    00104       // write_mem_barrier();
    00105       _M_i = __v;
    00106       if (__m = memory_order_seq_cst)
    00107         __sync_synchronize();
    00108     }
    00109     }
    00110
    00111     void*
    00112     load(memory_order __m = memory_order_seq_cst) const volatile
    00113     {
    00114       __glibcxx_assert(__m == memory_order_release);
    00115       __glibcxx_assert(__m == memory_order_acq_rel);
    00116
    00117       __sync_synchronize();
    00118       void* __ret = _M_i;
    00119       __sync_synchronize();
    00120       return __ret;
    00121     }
    00122
    00123     void*
    00124     exchange(void* __v, memory_order __m = memory_order_seq_cst) volatile
    00125     {
    00126       // XXX built-in assumes memory_order_acquire.
    00127       return __sync_lock_test_and_set(&_M_i, __v);
    00128     }
    00129
    00130     bool
    00131     compare_exchange_weak(void*& __v1, void* __v2, memory_order __m1,
    00132               memory_order __m2) volatile
    00133     { return compare_exchange_strong(__v1, __v2, __m1, __m2); }
    00134
    00135     bool
    00136     compare_exchange_weak(void*& __v1, void* __v2,
    00137               memory_order __m = memory_order_seq_cst) volatile
    00138     {
    00139       return compare_exchange_weak(__v1, __v2, __m,
    00140                    __calculate_memory_order(__m));
    00141     }
    00142
    00143     bool
    00144     compare_exchange_strong(void*& __v1, void* __v2, memory_order __m1,
    00145                 memory_order __m2) volatile
    00146     {
    00147       __glibcxx_assert(__m2 == memory_order_release);
    00148       __glibcxx_assert(__m2 == memory_order_acq_rel);
    00149       __glibcxx_assert(__m2 <= __m1);
    00150
    00151       void* __v1o = __v1;
    00152       void* __v1n = __sync_val_compare_and_swap(&_M_i, __v1o, __v2);
    00153
    00154       // Assume extra stores (of same value) allowed in true case.
    00155       __v1 = __v1n;
    00156       return __v1o == __v1n;
    00157     }
    00158
    00159     bool
    00160     compare_exchange_strong(void*& __v1, void* __v2,
    00161               memory_order __m = memory_order_seq_cst) volatile
    00162     {
    00163       return compare_exchange_strong(__v1, __v2, __m,
    00164                      __calculate_memory_order(__m));
    00165     }
    00166
    00167     void*
    00168     fetch_add(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile
    00169     { return __sync_fetch_and_add(&_M_i, __d); }
    00170
    00171     void*
    00172     fetch_sub(ptrdiff_t __d, memory_order __m = memory_order_seq_cst) volatile
    00173     { return __sync_fetch_and_sub(&_M_i, __d); }
    00174
    00175     operator void*() const volatile
    00176     { return load(); }
    00177
    00178     void*
    00179     operator=(void* __v) // XXX volatile
    00180     {
    00181       store(__v);
    00182       return __v;
    00183     }
    00184
    00185     void*
    00186     operator+=(ptrdiff_t __d) volatile
    00187     { return __sync_add_and_fetch(&_M_i, __d); }
    00188
    00189     void*
    00190     operator-=(ptrdiff_t __d) volatile
    00191     { return __sync_sub_and_fetch(&_M_i, __d); }
    00192   };
    00193
    00194   // 29.3.1 atomic integral types
    00195   // For each of the integral types, define atomic_[integral type] struct
    00196   //
    00197   // atomic_bool     bool
    00198   // atomic_char     char
    00199   // atomic_schar    signed char
    00200   // atomic_uchar    unsigned char
    00201   // atomic_short    short
    00202   // atomic_ushort   unsigned short
    00203   // atomic_int      int
    00204   // atomic_uint     unsigned int
    00205   // atomic_long     long
    00206   // atomic_ulong    unsigned long
    00207   // atomic_llong    long long
    00208   // atomic_ullong   unsigned long long
    00209   // atomic_char16_t char16_t
    00210   // atomic_char32_t char32_t
    00211   // atomic_wchar_t  wchar_t
    00212
    00213   // Base type.
    00214   // NB: Assuming _ITp is an integral scalar type that is 1, 2, 4, or 8 bytes,
    00215   // since that is what GCC built-in functions for atomic memory access work on.
    00216   template<typename _ITp>
    00217     struct __atomic_base
    00218     {
    00219     private:
    00220       typedef _ITp  __integral_type;
    00221
    00222       __integral_type   _M_i;
    00223
    00224     public:
    00225       __atomic_base() = default;
    00226       ~__atomic_base() = default;
    00227       __atomic_base(const __atomic_base&) = delete;
    00228       __atomic_base& operator=(const __atomic_base&) = delete;
    00229
    00230       // Requires __integral_type convertible to _M_base._M_i.
    00231       __atomic_base(__integral_type __i) { _M_i = __i; }
    00232
    00233       operator __integral_type() const volatile
    00234       { return load(); }
    00235
    00236       __integral_type
    00237       operator=(__integral_type __i) // XXX volatile
    00238       {
    00239     store(__i);
    00240     return __i;
    00241       }
    00242
    00243       __integral_type
    00244       operator++(int) volatile
    00245       { return fetch_add(1); }
    00246
    00247       __integral_type
    00248       operator--(int) volatile
    00249       { return fetch_sub(1); }
    00250
    00251       __integral_type
    00252       operator++() volatile
    00253       { return __sync_add_and_fetch(&_M_i, 1); }
    00254
    00255       __integral_type
    00256       operator--() volatile
    00257       { return __sync_sub_and_fetch(&_M_i, 1); }
    00258
    00259       __integral_type
    00260       operator+=(__integral_type __i) volatile
    00261       { return __sync_add_and_fetch(&_M_i, __i); }
    00262
    00263       __integral_type
    00264       operator-=(__integral_type __i) volatile
    00265       { return __sync_sub_and_fetch(&_M_i, __i); }
    00266
    00267       __integral_type
    00268       operator&=(__integral_type __i) volatile
    00269       { return __sync_and_and_fetch(&_M_i, __i); }
    00270
    00271       __integral_type
    00272       operator|=(__integral_type __i) volatile
    00273       { return __sync_or_and_fetch(&_M_i, __i); }
    00274
    00275       __integral_type
    00276       operator^=(__integral_type __i) volatile
    00277       { return __sync_xor_and_fetch(&_M_i, __i); }
    00278
    00279       bool
    00280       is_lock_free() const volatile
    00281       { return true; }
    00282
    00283       void
    00284       store(__integral_type __i,
    00285         memory_order __m = memory_order_seq_cst) volatile
    00286       {
    00287     __glibcxx_assert(__m == memory_order_acquire);
    00288     __glibcxx_assert(__m == memory_order_acq_rel);
    00289     __glibcxx_assert(__m == memory_order_consume);
    00290
    00291     if (__m == memory_order_relaxed)
    00292       _M_i = __i;
    00293     else
    00294       {
    00295         // write_mem_barrier();
    00296         _M_i = __i;
    00297         if (__m = memory_order_seq_cst)
    00298           __sync_synchronize();
    00299       }
    00300       }
    00301
    00302       __integral_type
    00303       load(memory_order __m = memory_order_seq_cst) const volatile
    00304       {
    00305     __glibcxx_assert(__m == memory_order_release);
    00306     __glibcxx_assert(__m == memory_order_acq_rel);
    00307
    00308     __sync_synchronize();
    00309     __integral_type __ret = _M_i;
    00310     __sync_synchronize();
    00311     return __ret;
    00312       }
    00313
    00314       __integral_type
    00315       exchange(__integral_type __i,
    00316            memory_order __m = memory_order_seq_cst) volatile
    00317       {
    00318     // XXX built-in assumes memory_order_acquire.
    00319     return __sync_lock_test_and_set(&_M_i, __i);
    00320       }
    00321
    00322       bool
    00323       compare_exchange_weak(__integral_type& __i1, __integral_type __i2,
    00324                 memory_order __m1, memory_order __m2) volatile
    00325       { return compare_exchange_strong(__i1, __i2, __m1, __m2); }
    00326
    00327       bool
    00328       compare_exchange_weak(__integral_type& __i1, __integral_type __i2,
    00329                 memory_order __m = memory_order_seq_cst) volatile
    00330       {
    00331     return compare_exchange_weak(__i1, __i2, __m,
    00332                      __calculate_memory_order(__m));
    00333       }
    00334
    00335       bool
    00336       compare_exchange_strong(__integral_type& __i1, __integral_type __i2,
    00337                   memory_order __m1, memory_order __m2) volatile
    00338       {
    00339     __glibcxx_assert(__m2 == memory_order_release);
    00340     __glibcxx_assert(__m2 == memory_order_acq_rel);
    00341     __glibcxx_assert(__m2 <= __m1);
    00342
    00343     __integral_type __i1o = __i1;
    00344     __integral_type __i1n = __sync_val_compare_and_swap(&_M_i, __i1o, __i2);
    00345
    00346     // Assume extra stores (of same value) allowed in true case.
    00347     __i1 = __i1n;
    00348     return __i1o == __i1n;
    00349       }
    00350
    00351       bool
    00352       compare_exchange_strong(__integral_type& __i1, __integral_type __i2,
    00353                   memory_order __m = memory_order_seq_cst) volatile
    00354       {
    00355     return compare_exchange_strong(__i1, __i2, __m,
    00356                        __calculate_memory_order(__m));
    00357       }
    00358
    00359       __integral_type
    00360       fetch_add(__integral_type __i,
    00361         memory_order __m = memory_order_seq_cst) volatile
    00362       { return __sync_fetch_and_add(&_M_i, __i); }
    00363
    00364       __integral_type
    00365       fetch_sub(__integral_type __i,
    00366         memory_order __m = memory_order_seq_cst) volatile
    00367       { return __sync_fetch_and_sub(&_M_i, __i); }
    00368
    00369       __integral_type
    00370       fetch_and(__integral_type __i,
    00371         memory_order __m = memory_order_seq_cst) volatile
    00372       { return __sync_fetch_and_and(&_M_i, __i); }
    00373
    00374       __integral_type
    00375       fetch_or(__integral_type __i,
    00376            memory_order __m = memory_order_seq_cst) volatile
    00377       { return __sync_fetch_and_or(&_M_i, __i); }
    00378
    00379       __integral_type
    00380       fetch_xor(__integral_type __i,
    00381         memory_order __m = memory_order_seq_cst) volatile
    00382       { return __sync_fetch_and_xor(&_M_i, __i); }
    00383     };
    00384
    00385
    00386   /// atomic_bool
    00387   // NB: No operators or fetch-operations for this type.
    00388   struct atomic_bool
    00389   {
    00390   private:
    00391     __atomic_base<bool> _M_base;
    00392
    00393   public:
    00394     atomic_bool() = default;
    00395     ~atomic_bool() = default;
    00396     atomic_bool(const atomic_bool&) = delete;
    00397     atomic_bool& operator=(const atomic_bool&) = delete;
    00398
    00399     atomic_bool(bool __i) : _M_base(__i) { }
    00400
    00401     bool
    00402     operator=(bool __i) // XXX volatile
    00403     { return _M_base.operator=(__i); }
    00404
    00405     operator bool() const volatile
    00406     { return _M_base.load(); }
    00407
    00408     bool
    00409     is_lock_free() const volatile
    00410     { return _M_base.is_lock_free(); }
    00411
    00412     void
    00413     store(bool __i, memory_order __m = memory_order_seq_cst) volatile
    00414     { _M_base.store(__i, __m); }
    00415
    00416     bool
    00417     load(memory_order __m = memory_order_seq_cst) const volatile
    00418     { return _M_base.load(__m); }
    00419
    00420     bool
    00421     exchange(bool __i, memory_order __m = memory_order_seq_cst) volatile
    00422     { return _M_base.exchange(__i, __m); }
    00423
    00424     bool
    00425     compare_exchange_weak(bool& __i1, bool __i2, memory_order __m1,
    00426               memory_order __m2) volatile
    00427     { return _M_base.compare_exchange_weak(__i1, __i2, __m1, __m2); }
    00428
    00429     bool
    00430     compare_exchange_weak(bool& __i1, bool __i2,
    00431               memory_order __m = memory_order_seq_cst) volatile
    00432     { return _M_base.compare_exchange_weak(__i1, __i2, __m); }
    00433
    00434     bool
    00435     compare_exchange_strong(bool& __i1, bool __i2, memory_order __m1,
    00436                 memory_order __m2) volatile
    00437     { return _M_base.compare_exchange_strong(__i1, __i2, __m1, __m2); }
    00438
    00439
    00440     bool
    00441     compare_exchange_strong(bool& __i1, bool __i2,
    00442                 memory_order __m = memory_order_seq_cst) volatile
    00443     { return _M_base.compare_exchange_strong(__i1, __i2, __m); }
    00444   };
    00445 } // namespace __atomic2
    00446
    00447 // _GLIBCXX_END_NAMESPACE
    00448
    00449 #endif