tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

hb-atomic.hh (8967B)


      1 /*
      2 * Copyright © 2007  Chris Wilson
      3 * Copyright © 2009,2010  Red Hat, Inc.
      4 * Copyright © 2011,2012  Google, Inc.
      5 *
      6 *  This is part of HarfBuzz, a text shaping library.
      7 *
      8 * Permission is hereby granted, without written agreement and without
      9 * license or royalty fees, to use, copy, modify, and distribute this
     10 * software and its documentation for any purpose, provided that the
     11 * above copyright notice and the following two paragraphs appear in
     12 * all copies of this software.
     13 *
     14 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     15 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     16 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     17 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     18 * DAMAGE.
     19 *
     20 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     21 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     22 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     23 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     24 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     25 *
     26 * Contributor(s):
     27 *	Chris Wilson <chris@chris-wilson.co.uk>
     28 * Red Hat Author(s): Behdad Esfahbod
     29 * Google Author(s): Behdad Esfahbod
     30 */
     31 
     32 #ifndef HB_ATOMIC_HH
     33 #define HB_ATOMIC_HH
     34 
     35 #include "hb.hh"
     36 #include "hb-meta.hh"
     37 
     38 
     39 /*
     40 * Atomic integers and pointers.
     41 */
     42 
     43 /* We need external help for these */
     44 
     45 #if defined(hb_atomic_int_impl_add) \
     46 && defined(hb_atomic_ptr_impl_get) \
     47 && defined(hb_atomic_ptr_impl_cmpexch)
     48 
     49 /* Defined externally, i.e. in config.h. */
     50 
     51 
     52 #elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
     53 
     54 /* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
     55 
     56 #define _hb_memory_barrier()			__sync_synchronize ()
     57 
     58 #define hb_atomic_int_impl_add(AI, V)		__atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
     59 #define hb_atomic_int_impl_set_relaxed(AI, V)	__atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
     60 #define hb_atomic_int_impl_set(AI, V)		__atomic_store_n ((AI), (V), __ATOMIC_RELEASE)
     61 #define hb_atomic_int_impl_get_relaxed(AI)	__atomic_load_n ((AI), __ATOMIC_RELAXED)
     62 #define hb_atomic_int_impl_get(AI)		__atomic_load_n ((AI), __ATOMIC_ACQUIRE)
     63 
     64 #define hb_atomic_ptr_impl_set_relaxed(P, V)	__atomic_store_n ((P), (V), __ATOMIC_RELAXED)
     65 #define hb_atomic_ptr_impl_get_relaxed(P)	__atomic_load_n ((P), __ATOMIC_RELAXED)
     66 #define hb_atomic_ptr_impl_get(P)		__atomic_load_n ((P), __ATOMIC_ACQUIRE)
     67 static inline bool
     68 _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
     69 {
     70  const void *O = O_; // Need lvalue
     71  return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
     72 }
     73 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	_hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
     74 
     75 
     76 #elif !defined(HB_NO_MT)
     77 
     78 /* C++11 atomics. */
     79 
     80 #include <atomic>
     81 
     82 #define HB_STL_ATOMIC_IMPL
     83 
     84 #define _hb_memory_r_barrier()			std::atomic_thread_fence(std::memory_order_acquire)
     85 #define _hb_memory_w_barrier()			std::atomic_thread_fence(std::memory_order_release)
     86 
     87 #else /* defined(HB_NO_MT) */
     88 
     89 #define hb_atomic_int_impl_add(AI, V)		((*(AI) += (V)) - (V))
     90 #define _hb_memory_barrier()			do {} while (0)
     91 #define hb_atomic_ptr_impl_cmpexch(P,O,N)	(* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
     92 
     93 #endif
     94 
     95 
     96 /* This should never be disabled, even under HB_NO_MT.
     97 * except that MSVC gives me an internal compiler error, so disabled there.
     98 *
     99 * https://github.com/harfbuzz/harfbuzz/pull/4119
    100 */
    101 #ifndef _hb_compiler_memory_r_barrier
    102 #if defined(__ATOMIC_ACQUIRE) // gcc-like
    103 static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
    104 #elif !defined(_MSC_VER)
    105 #include <atomic>
    106 #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
    107 #else
    108 static inline void _hb_compiler_memory_r_barrier () {}
    109 #endif
    110 #endif
    111 
    112 
    113 
    114 #ifndef _hb_memory_r_barrier
    115 #define _hb_memory_r_barrier()			_hb_memory_barrier ()
    116 #endif
    117 #ifndef _hb_memory_w_barrier
    118 #define _hb_memory_w_barrier()			_hb_memory_barrier ()
    119 #endif
    120 #ifndef hb_atomic_int_impl_set_relaxed
    121 #define hb_atomic_int_impl_set_relaxed(AI, V)	(*(AI) = (V))
    122 #endif
    123 #ifndef hb_atomic_int_impl_get_relaxed
    124 #define hb_atomic_int_impl_get_relaxed(AI)	(*(AI))
    125 #endif
    126 
    127 #ifndef hb_atomic_ptr_impl_set_relaxed
    128 #define hb_atomic_ptr_impl_set_relaxed(P, V)	(*(P) = (V))
    129 #endif
    130 #ifndef hb_atomic_ptr_impl_get_relaxed
    131 #define hb_atomic_ptr_impl_get_relaxed(P)	(*(P))
    132 #endif
    133 #ifndef hb_atomic_int_impl_set
    134 template <typename T>
    135 inline void hb_atomic_int_impl_set (T *AI, T v)	{ _hb_memory_w_barrier (); *AI = v; }
    136 #endif
    137 #ifndef hb_atomic_int_impl_get
    138 template <typename T>
    139 inline T hb_atomic_int_impl_get (const T *AI)	{ T v = *AI; _hb_memory_r_barrier (); return v; }
    140 #endif
    141 #ifndef hb_atomic_ptr_impl_get
    142 inline void *hb_atomic_ptr_impl_get (void ** const P)	{ void *v = *P; _hb_memory_r_barrier (); return v; }
    143 #endif
    144 
    145 #ifdef HB_STL_ATOMIC_IMPL
    146 template <typename T>
    147 struct hb_atomic_t
    148 {
    149  hb_atomic_t () = default;
    150  constexpr hb_atomic_t (T v) : v (v) {}
    151  constexpr hb_atomic_t (const hb_atomic_t& o) : v (o.get_relaxed ()) {}
    152  constexpr hb_atomic_t (hb_atomic_t&& o) : v (o.get_relaxed ()) { o.set_relaxed ({}); }
    153 
    154  hb_atomic_t &operator= (const hb_atomic_t& o) { set_relaxed (o.get_relaxed ()); return *this; }
    155  hb_atomic_t &operator= (hb_atomic_t&& o){ set_relaxed (o.get_relaxed ()); o.set_relaxed ({}); return *this; }
    156  hb_atomic_t &operator= (T v_)
    157  {
    158    set_relaxed (v_);
    159    return *this;
    160  }
    161  operator T () const { return get_relaxed (); }
    162 
    163  void set_relaxed (T v_) { v.store (v_, std::memory_order_relaxed); }
    164  void set_release (T v_) { v.store (v_, std::memory_order_release); }
    165  T get_relaxed () const { return v.load (std::memory_order_relaxed); }
    166  T get_acquire () const { return v.load (std::memory_order_acquire); }
    167  T inc () { return v.fetch_add (1, std::memory_order_acq_rel); }
    168  T dec () { return v.fetch_add (-1, std::memory_order_acq_rel); }
    169 
    170  int operator++ (int) { return inc (); }
    171  int operator-- (int) { return dec (); }
    172 
    173  friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
    174  {
    175    T v = a.get_acquire ();
    176    a.set_relaxed (b.get_acquire ());
    177    b.set_relaxed (v);
    178  }
    179 
    180  std::atomic<T> v = 0;
    181 };
    182 
    183 template <typename T>
    184 struct hb_atomic_t<T *>
    185 {
    186  hb_atomic_t () = default;
    187  constexpr hb_atomic_t (T *v) : v (v) {}
    188  hb_atomic_t (const hb_atomic_t &other) = delete;
    189 
    190  void init (T *v_ = nullptr) { set_relaxed (v_); }
    191  void set_relaxed (T *v_) { v.store (v_, std::memory_order_relaxed); }
    192  T *get_relaxed () const { return v.load (std::memory_order_relaxed); }
    193  T *get_acquire () const { return v.load (std::memory_order_acquire); }
    194  bool cmpexch (T *old, T *new_) { return v.compare_exchange_weak (old, new_, std::memory_order_acq_rel, std::memory_order_relaxed); }
    195 
    196  operator bool () const { return get_acquire () != nullptr; }
    197  T *operator->() const { return get_acquire (); }
    198  template <typename C>
    199  operator C * () const
    200  {
    201    return get_acquire ();
    202  }
    203 
    204  friend void swap (hb_atomic_t &a, hb_atomic_t &b) noexcept
    205  {
    206    T *p = a.get_acquire ();
    207    a.set_relaxed (b.get_acquire ());
    208    b.set_relaxed (p);
    209  }
    210 
    211  std::atomic<T *> v = nullptr;
    212 };
    213 
    214 #else
    215 
    216 template <typename T>
    217 struct hb_atomic_t
    218 {
    219  hb_atomic_t () = default;
    220  constexpr hb_atomic_t (T v) : v (v) {}
    221 
    222  hb_atomic_t& operator = (T v_) { set_relaxed (v_); return *this; }
    223  operator T () const { return get_relaxed (); }
    224 
    225  void set_relaxed (T v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
    226  void set_release (T v_) { hb_atomic_int_impl_set (&v, v_); }
    227  T get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
    228  T get_acquire () const { return hb_atomic_int_impl_get (&v); }
    229  T inc () { return hb_atomic_int_impl_add (&v,  1); }
    230  T dec () { return hb_atomic_int_impl_add (&v, -1); }
    231 
    232  int operator ++ (int) { return inc (); }
    233  int operator -- (int) { return dec (); }
    234 
    235  T v = 0;
    236 };
    237 
    238 template <typename T>
    239 struct hb_atomic_t<T*>
    240 {
    241  hb_atomic_t () = default;
    242  constexpr hb_atomic_t (T* v) : v (v) {}
    243  hb_atomic_t (const hb_atomic_t &other) = delete;
    244 
    245  void init (T* v_ = nullptr) { set_relaxed (v_); }
    246  void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
    247  T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
    248  T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
    249  bool cmpexch (T *old, T *new_) { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
    250 
    251  operator bool () const { return get_acquire () != nullptr; }
    252  T * operator -> () const                    { return get_acquire (); }
    253  template <typename C> operator C * () const { return get_acquire (); }
    254 
    255  T *v = nullptr;
    256 };
    257 
    258 #endif
    259 
    260 static inline bool hb_barrier ()
    261 {
    262  _hb_compiler_memory_r_barrier ();
    263  return true;
    264 }
    265 
    266 
    267 #endif /* HB_ATOMIC_HH */