blob: 366fb32b7def7c21b74b3ae30a54752e75dc1341 [file] [log] [blame]
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -04001/*
2 * Copyright © 2007 Chris Wilson
3 * Copyright © 2009,2010 Red Hat, Inc.
Behdad Esfahbod34961e32012-05-17 20:50:38 -04004 * Copyright © 2011,2012 Google, Inc.
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -04005 *
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
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#ifndef HB_ATOMIC_HH
33#define HB_ATOMIC_HH
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -040034
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070035#include "hb.hh"
Behdad Esfahbodf64ea8f2018-12-30 18:49:34 -050036#include "hb-meta.hh"
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -040037
38
Behdad Esfahbod1227a9e2018-08-08 22:45:49 -070039/*
40 * Atomic integers and pointers.
41 */
42
43
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -040044/* We need external help for these */
45
Konstantin Ritt3f174cd2015-03-28 00:49:33 +040046#if defined(hb_atomic_int_impl_add) \
Behdad Esfahbod06b91d92018-07-31 19:29:49 -070047 && defined(hb_atomic_ptr_impl_get) \
Konstantin Ritt3f174cd2015-03-28 00:49:33 +040048 && defined(hb_atomic_ptr_impl_cmpexch)
Behdad Esfahbod45a8b462015-04-08 12:49:38 -070049
Behdad Esfahbod1227a9e2018-08-08 22:45:49 -070050/* Defined externally, i.e. in config.h. */
Behdad Esfahbod34961e32012-05-17 20:50:38 -040051
Behdad Esfahbod022a05a2012-05-17 21:53:24 -040052
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040053#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
Behdad Esfahbod04b7b812018-07-17 10:57:01 +020054
Behdad Esfahbod52f91262021-02-22 17:22:09 -070055/* C++11-style GCC primitives. We prefer these as they don't require linking to libstdc++ / libc++. */
Behdad Esfahbod04b7b812018-07-17 10:57:01 +020056
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040057#define _hb_memory_barrier() __sync_synchronize ()
58
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -070059#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
60#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040061#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE)
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -070062#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED)
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040063#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE)
Behdad Esfahbod04b7b812018-07-17 10:57:01 +020064
Behdad Esfahbod1f738092018-08-09 00:22:37 -070065#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED)
66#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED)
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040067#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE)
Behdad Esfahbod04b7b812018-07-17 10:57:01 +020068static inline bool
69_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
70{
71 const void *O = O_; // Need lvalue
72 return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
73}
Behdad Esfahbod13f4c132018-08-01 14:13:59 -070074#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
Behdad Esfahbod04b7b812018-07-17 10:57:01 +020075
Behdad Esfahbodb368a072021-02-22 17:23:53 -070076
Behdad Esfahbod52f91262021-02-22 17:22:09 -070077#elif !defined(HB_NO_MT)
Behdad Esfahbodbda24242018-07-16 15:41:09 +020078
Behdad Esfahbod04b7b812018-07-17 10:57:01 +020079/* C++11 atomics. */
Behdad Esfahbodbda24242018-07-16 15:41:09 +020080
81#include <atomic>
82
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040083#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
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
Behdad Esfahboda924bbc2023-01-30 14:13:33 -070087#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
88#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
89#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
90#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
91#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
Behdad Esfahbodbda24242018-07-16 15:41:09 +020092
Behdad Esfahbod1f738092018-08-09 00:22:37 -070093#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
Stephan Bergmannd936ad42019-03-05 17:18:57 +010094#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
Behdad Esfahbodec743fc2018-09-26 16:37:18 -040095#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
Behdad Esfahbodbda24242018-07-16 15:41:09 +020096static inline bool
97_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
98{
99 const void *O = O_; // Need lvalue
Behdad Esfahbod04b7b812018-07-17 10:57:01 +0200100 return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
Behdad Esfahbodbda24242018-07-16 15:41:09 +0200101}
Behdad Esfahbod13f4c132018-08-01 14:13:59 -0700102#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
Behdad Esfahbodbda24242018-07-16 15:41:09 +0200103
104
Behdad Esfahbod67b39622021-09-22 16:21:27 -0600105#else /* defined(HB_NO_MT) */
Behdad Esfahbodcdafe3a2012-06-05 16:34:49 -0400106
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -0700107#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
Behdad Esfahbod179570d2019-05-27 13:08:07 -0400108#define _hb_memory_barrier() do {} while (0)
Konstantin Ritt3f174cd2015-03-28 00:49:33 +0400109#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
110
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -0400111#endif
112
Konstantin Ritt3f174cd2015-03-28 00:49:33 +0400113
Behdad Esfahbodb41efb62023-02-13 21:16:16 -0700114/* This should never be disabled, even under HB_NO_MT.
115 * except that MSVC gives me an internal compiler error, so disabled there.
116 *
117 * https://github.com/harfbuzz/harfbuzz/pull/4119
118 */
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600119#ifndef _hb_compiler_memory_r_barrier
Behdad Esfahbodb41efb62023-02-13 21:16:16 -0700120#if defined(__ATOMIC_ACQUIRE) // gcc-like
Behdad Esfahbodb16f1802023-11-03 17:51:50 -0600121static inline void _hb_compiler_memory_r_barrier () { asm volatile("": : :"memory"); }
Behdad Esfahbodb41efb62023-02-13 21:16:16 -0700122#elif !defined(_MSC_VER)
Behdad Esfahbod9518d602022-07-17 17:03:40 -0600123#include <atomic>
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600124#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
Behdad Esfahbod9518d602022-07-17 17:03:40 -0600125#else
Behdad Esfahbodb16f1802023-11-03 17:51:50 -0600126static inline void _hb_compiler_memory_r_barrier () {}
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600127#endif
Behdad Esfahbod9518d602022-07-17 17:03:40 -0600128#endif
129
Behdad Esfahbodf0707e22022-07-17 16:47:16 -0600130
131
Behdad Esfahbod006d4f02018-08-01 13:59:31 -0700132#ifndef _hb_memory_r_barrier
133#define _hb_memory_r_barrier() _hb_memory_barrier ()
134#endif
135#ifndef _hb_memory_w_barrier
136#define _hb_memory_w_barrier() _hb_memory_barrier ()
137#endif
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -0700138#ifndef hb_atomic_int_impl_set_relaxed
Behdad Esfahbod63c74e82018-07-31 22:21:21 -0700139#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V))
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -0700140#endif
141#ifndef hb_atomic_int_impl_get_relaxed
Behdad Esfahbod63c74e82018-07-31 22:21:21 -0700142#define hb_atomic_int_impl_get_relaxed(AI) (*(AI))
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -0700143#endif
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700144
145#ifndef hb_atomic_ptr_impl_set_relaxed
146#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V))
147#endif
148#ifndef hb_atomic_ptr_impl_get_relaxed
149#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
150#endif
Behdad Esfahbod3ee96982018-09-27 17:20:26 -0400151#ifndef hb_atomic_int_impl_set
Behdad Esfahbodb435df32018-09-28 09:13:14 -0400152inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
Behdad Esfahboda924bbc2023-01-30 14:13:33 -0700153inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; }
Behdad Esfahbod3ee96982018-09-27 17:20:26 -0400154#endif
Behdad Esfahbodec743fc2018-09-26 16:37:18 -0400155#ifndef hb_atomic_int_impl_get
Behdad Esfahbod475be9d2018-11-13 13:01:13 -0500156inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
Behdad Esfahboda924bbc2023-01-30 14:13:33 -0700157inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; }
Behdad Esfahbodec743fc2018-09-26 16:37:18 -0400158#endif
Behdad Esfahbod896ff152018-07-31 22:51:38 -0700159#ifndef hb_atomic_ptr_impl_get
Behdad Esfahbod475be9d2018-11-13 13:01:13 -0500160inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
Behdad Esfahbod896ff152018-07-31 22:51:38 -0700161#endif
Behdad Esfahbod4bc16ac2018-07-31 21:05:51 -0700162
Konstantin Ritt3f174cd2015-03-28 00:49:33 +0400163
Behdad Esfahboda924bbc2023-01-30 14:13:33 -0700164struct hb_atomic_short_t
165{
166 hb_atomic_short_t () = default;
167 constexpr hb_atomic_short_t (short v) : v (v) {}
168
169 hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
170 operator short () const { return get_relaxed (); }
171
172 void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
173 void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
174 short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
175 short get_acquire () const { return hb_atomic_int_impl_get (&v); }
176 short inc () { return hb_atomic_int_impl_add (&v, 1); }
177 short dec () { return hb_atomic_int_impl_add (&v, -1); }
178
179 short v = 0;
180};
181
Konstantin Ritt3f174cd2015-03-28 00:49:33 +0400182struct hb_atomic_int_t
183{
Behdad Esfahbod140797d2020-06-29 03:51:09 -0700184 hb_atomic_int_t () = default;
185 constexpr hb_atomic_int_t (int v) : v (v) {}
186
Behdad Esfahbodf73c15c2022-08-03 12:54:03 -0600187 hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; }
188 operator int () const { return get_relaxed (); }
189
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330190 void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
Behdad Esfahbodd3f22872022-08-03 12:37:41 -0600191 void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330192 int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
Behdad Esfahbodd3f22872022-08-03 12:37:41 -0600193 int get_acquire () const { return hb_atomic_int_impl_get (&v); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330194 int inc () { return hb_atomic_int_impl_add (&v, 1); }
195 int dec () { return hb_atomic_int_impl_add (&v, -1); }
Behdad Esfahbod6e42f4c2018-08-08 22:51:35 -0700196
Behdad Esfahbod140797d2020-06-29 03:51:09 -0700197 int v = 0;
Konstantin Ritt3f174cd2015-03-28 00:49:33 +0400198};
199
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700200template <typename P>
201struct hb_atomic_ptr_t
202{
Behdad Esfahbod54ece292019-04-16 16:45:53 -0400203 typedef hb_remove_pointer<P> T;
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700204
Behdad Esfahbod140797d2020-06-29 03:51:09 -0700205 hb_atomic_ptr_t () = default;
206 constexpr hb_atomic_ptr_t (T* v) : v (v) {}
Behdad Esfahbod43ec78f2023-06-23 10:22:30 -0600207 hb_atomic_ptr_t (const hb_atomic_ptr_t &other) = delete;
Behdad Esfahbod140797d2020-06-29 03:51:09 -0700208
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330209 void init (T* v_ = nullptr) { set_relaxed (v_); }
210 void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330211 T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
Behdad Esfahbod86d1e222022-08-03 12:43:28 -0600212 T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330213 bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700214
Behdad Esfahbod86d1e222022-08-03 12:43:28 -0600215 T * operator -> () const { return get_acquire (); }
216 template <typename C> operator C * () const { return get_acquire (); }
Behdad Esfahbodf6fc5572018-11-05 13:23:54 -0500217
Behdad Esfahbod140797d2020-06-29 03:51:09 -0700218 T *v = nullptr;
Behdad Esfahbod1f738092018-08-09 00:22:37 -0700219};
Konstantin Ritt3f174cd2015-03-28 00:49:33 +0400220
Behdad Esfahbod30672c72023-11-03 18:52:03 -0600221static inline bool hb_barrier ()
222{
223 _hb_compiler_memory_r_barrier ();
224 return true;
225}
226
Behdad Esfahbodec3ba4b2012-05-17 20:30:46 -0400227
Behdad Esfahbodc77ae402018-08-25 22:36:36 -0700228#endif /* HB_ATOMIC_HH */