From 1f7380944df9aa81cd48a4764c763d692533c4a6 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Thu, 9 Aug 2018 00:22:37 -0700 Subject: [PATCH] [atomic] Add hb_atomic_ptr_t<> and port all uses Found and fixed a couple bugs. Found a couple multithreading issues. Marked them with "XXX-MT-bug". --- src/hb-atomic-private.hh | 34 +++++++++++++++++++++++++++++++--- src/hb-common.cc | 34 ++++++++++++++++++---------------- src/hb-face-private.hh | 3 ++- src/hb-face.cc | 6 +++--- src/hb-font.cc | 2 +- src/hb-ft.cc | 22 ++++++++++++---------- src/hb-glib.cc | 11 ++++++----- src/hb-graphite2.cc | 16 +++++++++------- src/hb-icu.cc | 22 ++++++++++++---------- src/hb-machinery-private.hh | 17 +++++++++-------- src/hb-object-private.hh | 29 +++++++++++++++-------------- src/hb-ot-font.cc | 11 ++++++----- src/hb-ot-layout-private.hh | 2 +- src/hb-ot-post-table.hh | 9 +++++---- src/hb-ot-shape-complex-arabic.cc | 9 +++++---- src/hb-shape-plan.cc | 19 +++++++++++-------- src/hb-shape.cc | 11 ++++++----- src/hb-shaper-impl-private.hh | 2 +- src/hb-shaper-private.hh | 16 +++++++++------- src/hb-shaper.cc | 18 ++++++++++-------- src/hb-ucdn.cc | 11 ++++++----- src/hb-uniscribe.cc | 14 +++++++------- 22 files changed, 185 insertions(+), 133 deletions(-) diff --git a/src/hb-atomic-private.hh b/src/hb-atomic-private.hh index cdd0a40..276e696 100644 --- a/src/hb-atomic-private.hh +++ b/src/hb-atomic-private.hh @@ -57,6 +57,8 @@ #define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED) #define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED) +#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED) +#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED) #define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_CONSUME) static inline bool _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) @@ -76,6 +78,8 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_relaxed)) #define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast *> (P)->load (std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get(P) (reinterpret_cast *> (P)->load (std::memory_order_consume)) static inline bool _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) @@ -231,6 +235,13 @@ static_assert ((sizeof (long) == sizeof (void *)), ""); #ifndef hb_atomic_int_impl_get_relaxed #define hb_atomic_int_impl_get_relaxed(AI) (*(AI)) #endif + +#ifndef hb_atomic_ptr_impl_set_relaxed +#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V)) +#endif +#ifndef hb_atomic_ptr_impl_get_relaxed +#define hb_atomic_ptr_impl_get_relaxed(P) (*(P)) +#endif #ifndef hb_atomic_ptr_impl_get inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; } #endif @@ -239,7 +250,7 @@ inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barr #define HB_ATOMIC_INT_INIT(V) {V} struct hb_atomic_int_t { - inline void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } + inline void set_relaxed (int v_) const { hb_atomic_int_impl_set_relaxed (&v, v_); } inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); } inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); } inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); } @@ -248,8 +259,25 @@ struct hb_atomic_int_t }; -#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get((void **) P) -#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N)) +template struct hb_remove_ptr_t { typedef T value; }; +template struct hb_remove_ptr_t { typedef T value; }; + +#define HB_ATOMIC_PTR_INIT(V) {V} +template +struct hb_atomic_ptr_t +{ + typedef typename hb_remove_ptr_t

::value T; + + inline void init (T* v_ = nullptr) { set_relaxed (v_); } + inline void set_relaxed (T* v_) const { hb_atomic_ptr_impl_set_relaxed (&v, v_); } + inline T *get_relaxed (void) const { return hb_atomic_ptr_impl_get_relaxed (&v); } + inline T *get (void) const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } + inline bool cmpexch (const T *old, T *new_) const{ return hb_atomic_ptr_impl_cmpexch (&v, old, new_); } + + inline T* operator -> (void) const { return get (); } + + mutable T *v; +}; #endif /* HB_ATOMIC_PRIVATE_HH */ diff --git a/src/hb-common.cc b/src/hb-common.cc index bab1a66..a02d325 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc @@ -244,15 +244,15 @@ struct hb_language_item_t { /* Thread-safe lock-free language list */ -static hb_language_item_t *langs; +static hb_atomic_ptr_t langs; #ifdef HB_USE_ATEXIT static void free_langs (void) { retry: - hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); - if (!hb_atomic_ptr_cmpexch (&langs, first_lang, nullptr)) + hb_language_item_t *first_lang = langs.get (); + if (unlikely (!langs.cmpexch (first_lang, nullptr))) goto retry; while (first_lang) { @@ -268,7 +268,7 @@ static hb_language_item_t * lang_find_or_insert (const char *key) { retry: - hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs); + hb_language_item_t *first_lang = langs.get (); for (hb_language_item_t *lang = first_lang; lang; lang = lang->next) if (*lang == key) @@ -286,7 +286,8 @@ retry: return nullptr; } - if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) { + if (unlikely (!langs.cmpexch (first_lang, lang))) + { lang->fini (); free (lang); goto retry; @@ -368,15 +369,16 @@ hb_language_to_string (hb_language_t language) hb_language_t hb_language_get_default (void) { - static hb_language_t default_language = HB_LANGUAGE_INVALID; + static hb_atomic_ptr_t default_language; - hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language); - if (unlikely (language == HB_LANGUAGE_INVALID)) { + hb_language_t language = default_language.get (); + if (unlikely (language == HB_LANGUAGE_INVALID)) + { language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1); - (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language); + (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language); } - return default_language; + return language; } @@ -728,16 +730,16 @@ parse_uint32 (const char **pp, const char *end, uint32_t *pv) #ifdef USE_XLOCALE -static HB_LOCALE_T C_locale; +static hb_atomic_ptr_t C_locale; #ifdef HB_USE_ATEXIT static void free_C_locale (void) { retry: - HB_LOCALE_T locale = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale); + HB_LOCALE_T locale = C_locale.get (); - if (!hb_atomic_ptr_cmpexch (&C_locale, locale, nullptr)) + if (unlikely (!C_locale.cmpexch (locale, nullptr))) goto retry; if (locale) @@ -749,15 +751,15 @@ static HB_LOCALE_T get_C_locale (void) { retry: - HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale); + HB_LOCALE_T C = C_locale.get (); if (unlikely (!C)) { C = HB_CREATE_LOCALE ("C"); - if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C)) + if (unlikely (!C_locale.cmpexch (nullptr, C))) { - HB_FREE_LOCALE (C_locale); + HB_FREE_LOCALE (C); goto retry; } diff --git a/src/hb-face-private.hh b/src/hb-face-private.hh index a4b2cd3..086ce6e 100644 --- a/src/hb-face-private.hh +++ b/src/hb-face-private.hh @@ -61,7 +61,8 @@ struct hb_face_t { hb_shape_plan_t *shape_plan; plan_node_t *next; - } *shape_plans; + }; + hb_atomic_ptr_t shape_plans; inline hb_blob_t *reference_table (hb_tag_t tag) const { diff --git a/src/hb-face.cc b/src/hb-face.cc index e149275..49f29d3 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -78,12 +78,12 @@ DEFINE_NULL_INSTANCE (hb_face_t) = 0, /* num_glyphs */ { -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, +#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID), #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT }, - nullptr, /* shape_plans */ + HB_ATOMIC_PTR_INIT (nullptr), /* shape_plans */ }; @@ -249,7 +249,7 @@ hb_face_destroy (hb_face_t *face) { if (!hb_object_destroy (face)) return; - for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) + for (hb_face_t::plan_node_t *node = face->shape_plans.get (); node; ) { hb_face_t::plan_node_t *next = node->next; hb_shape_plan_destroy (node->shape_plan); diff --git a/src/hb-font.cc b/src/hb-font.cc index 80768d6..857b8f5 100644 --- a/src/hb-font.cc +++ b/src/hb-font.cc @@ -1247,7 +1247,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = nullptr, /* destroy */ { -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, +#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID), #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT } diff --git a/src/hb-ft.cc b/src/hb-ft.cc index f8a6b0c..5ab2a88 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -416,15 +416,15 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, return true; } -static hb_font_funcs_t *static_ft_funcs = nullptr; +static hb_atomic_ptr_t static_ft_funcs; #ifdef HB_USE_ATEXIT static void free_static_ft_funcs (void) { retry: - hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs); - if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr)) + hb_font_funcs_t *ft_funcs = static_ft_funcs.get (); + if (unlikely (!static_ft_funcs.cmpexch (ft_funcs, nullptr))) goto retry; hb_font_funcs_destroy (ft_funcs); @@ -435,7 +435,7 @@ static void _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref) { retry: - hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs); + hb_font_funcs_t *funcs = static_ft_funcs.get (); if (unlikely (!funcs)) { @@ -458,7 +458,8 @@ retry: hb_font_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) { + if (unlikely (!static_ft_funcs. cmpexch (nullptr, funcs))) + { hb_font_funcs_destroy (funcs); goto retry; } @@ -686,15 +687,15 @@ hb_ft_font_create_referenced (FT_Face ft_face) /* Thread-safe, lock-free, FT_Library */ -static FT_Library ft_library; +static hb_atomic_ptr_t ft_library; #ifdef HB_USE_ATEXIT static void free_ft_library (void) { retry: - FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); - if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr)) + FT_Library library = ft_library.get (); + if (unlikely (!ft_library.cmpexch (library, nullptr))) goto retry; FT_Done_FreeType (library); @@ -705,7 +706,7 @@ static FT_Library get_ft_library (void) { retry: - FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); + FT_Library library = ft_library.get (); if (unlikely (!library)) { @@ -713,7 +714,8 @@ retry: if (FT_Init_FreeType (&library)) return nullptr; - if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) { + if (unlikely (!ft_library.cmpexch (nullptr, library))) + { FT_Done_FreeType (library); goto retry; } diff --git a/src/hb-glib.cc b/src/hb-glib.cc index 246380a..4bb6f08 100644 --- a/src/hb-glib.cc +++ b/src/hb-glib.cc @@ -364,15 +364,15 @@ hb_glib_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, return utf8_decomposed_len; } -static hb_unicode_funcs_t *static_glib_funcs = nullptr; +static hb_atomic_ptr_t static_glib_funcs; #ifdef HB_USE_ATEXIT static void free_static_glib_funcs (void) { retry: - hb_unicode_funcs_t *glib_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs); - if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, glib_funcs, nullptr)) + hb_unicode_funcs_t *glib_funcs = static_glib_funcs.get (); + if (unlikely (!static_glib_funcs.cmpexch (glib_funcs, nullptr))) goto retry; hb_unicode_funcs_destroy (glib_funcs); @@ -383,7 +383,7 @@ hb_unicode_funcs_t * hb_glib_get_unicode_funcs (void) { retry: - hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_glib_funcs); + hb_unicode_funcs_t *funcs = static_glib_funcs.get (); if (unlikely (!funcs)) { @@ -396,7 +396,8 @@ retry: hb_unicode_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_glib_funcs, nullptr, funcs)) { + if (unlikely (!static_glib_funcs.cmpexch (nullptr, funcs))) + { hb_unicode_funcs_destroy (funcs); goto retry; } diff --git a/src/hb-graphite2.cc b/src/hb-graphite2.cc index 2ba905d..1f42a36 100644 --- a/src/hb-graphite2.cc +++ b/src/hb-graphite2.cc @@ -42,22 +42,24 @@ HB_SHAPER_DATA_ENSURE_DEFINE(graphite2, font) * shaper face data */ -typedef struct hb_graphite2_tablelist_t { +typedef struct hb_graphite2_tablelist_t +{ struct hb_graphite2_tablelist_t *next; hb_blob_t *blob; unsigned int tag; } hb_graphite2_tablelist_t; -struct hb_graphite2_face_data_t { +struct hb_graphite2_face_data_t +{ hb_face_t *face; gr_face *grface; - hb_graphite2_tablelist_t *tlist; + hb_atomic_ptr_t tlist; }; static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len) { hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data; - hb_graphite2_tablelist_t *tlist = face_data->tlist; + hb_graphite2_tablelist_t *tlist = face_data->tlist.get (); hb_blob_t *blob = nullptr; @@ -80,10 +82,10 @@ static const void *hb_graphite2_get_table (const void *data, unsigned int tag, s p->tag = tag; retry: - hb_graphite2_tablelist_t *tlist = (hb_graphite2_tablelist_t *) hb_atomic_ptr_get (&face_data->tlist); + hb_graphite2_tablelist_t *tlist = face_data->tlist.get (); p->next = tlist; - if (!hb_atomic_ptr_cmpexch (&face_data->tlist, tlist, p)) + if (unlikely (!face_data->tlist.cmpexch (tlist, p))) goto retry; } @@ -124,7 +126,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face) void _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data) { - hb_graphite2_tablelist_t *tlist = data->tlist; + hb_graphite2_tablelist_t *tlist = data->tlist.get (); while (tlist) { diff --git a/src/hb-icu.cc b/src/hb-icu.cc index c52e165..ce58de0 100644 --- a/src/hb-icu.cc +++ b/src/hb-icu.cc @@ -165,7 +165,7 @@ hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED, } #if U_ICU_VERSION_MAJOR_NUM >= 49 -static const UNormalizer2 *normalizer; +static hb_atomic_ptr_t normalizer; #endif static hb_bool_t @@ -177,7 +177,7 @@ hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if U_ICU_VERSION_MAJOR_NUM >= 49 { - UChar32 ret = unorm2_composePair (normalizer, a, b); + UChar32 ret = unorm2_composePair (normalizer.get (), a, b); if (ret < 0) return false; *ab = ret; return true; @@ -225,7 +225,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, UChar decomposed[4]; int len; UErrorCode icu_err = U_ZERO_ERROR; - len = unorm2_getRawDecomposition (normalizer, ab, decomposed, + len = unorm2_getRawDecomposition (normalizer.get (), ab, decomposed, ARRAY_LENGTH (decomposed), &icu_err); if (U_FAILURE (icu_err) || len < 0) return false; @@ -345,15 +345,15 @@ hb_icu_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs HB_UNUSED, } -static hb_unicode_funcs_t *static_icu_funcs = nullptr; +static hb_atomic_ptr_t static_icu_funcs; #ifdef HB_USE_ATEXIT static void free_static_icu_funcs (void) { retry: - hb_unicode_funcs_t *icu_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs); - if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, icu_funcs, nullptr)) + hb_unicode_funcs_t *icu_funcs = static_icu_funcs.get (); + if (unlikely (!static_icu_funcs.cmpexch (icu_funcs, nullptr))) goto retry; hb_unicode_funcs_destroy (icu_funcs); @@ -364,15 +364,16 @@ hb_unicode_funcs_t * hb_icu_get_unicode_funcs (void) { retry: - hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_icu_funcs); + hb_unicode_funcs_t *funcs = static_icu_funcs.get (); if (unlikely (!funcs)) { #if U_ICU_VERSION_MAJOR_NUM >= 49 - if (!hb_atomic_ptr_get (&normalizer)) { + if (!normalizer.get ()) + { UErrorCode icu_err = U_ZERO_ERROR; /* We ignore failure in getNFCInstace(). */ - (void) hb_atomic_ptr_cmpexch (&normalizer, nullptr, unorm2_getNFCInstance (&icu_err)); + (void) normalizer.cmpexch (nullptr, unorm2_getNFCInstance (&icu_err)); } #endif @@ -385,7 +386,8 @@ retry: hb_unicode_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_icu_funcs, nullptr, funcs)) { + if (unlikely (!static_icu_funcs.cmpexch (nullptr, funcs))) + { hb_unicode_funcs_destroy (funcs); goto retry; } diff --git a/src/hb-machinery-private.hh b/src/hb-machinery-private.hh index ec41e2b..fd35e40 100644 --- a/src/hb-machinery-private.hh +++ b/src/hb-machinery-private.hh @@ -605,12 +605,13 @@ struct hb_lazy_loader_t inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */ inline void init (void) { - instance = nullptr; + instance.set_relaxed (nullptr); } inline void fini (void) { - if (instance) - thiz ()->destroy (instance); + Stored *p = instance.get (); + if (p) + thiz ()->destroy (p); } inline const Returned * operator -> (void) const { return thiz ()->get (); } @@ -619,7 +620,7 @@ struct hb_lazy_loader_t inline Stored * get_stored (void) const { retry: - Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance); + Stored *p = this->instance.get (); if (unlikely (!p)) { hb_face_t *face = *(((hb_face_t **) this) - WheresFace); @@ -628,7 +629,7 @@ struct hb_lazy_loader_t if (unlikely (!p)) p = thiz ()->create (nullptr); /* Produce nil object. */ assert (p); - if (unlikely (!hb_atomic_ptr_cmpexch (const_cast(&this->instance), nullptr, p))) + if (unlikely (!this->instance.cmpexch (nullptr, p))) { thiz ()->destroy (p); goto retry; @@ -642,10 +643,10 @@ struct hb_lazy_loader_t /* This *must* be called when there are no other threads accessing. * However, to make TSan, etc, happy, we using cmpexch. */ retry: - Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance); + Stored *p = this->instance.get (); if (p) { - if (unlikely (!hb_atomic_ptr_cmpexch (const_cast(&this->instance), p, instance_))) + if (unlikely (!this->instance.cmpexch (p, instance_))) goto retry; thiz ()->destroy (p); } @@ -663,7 +664,7 @@ struct hb_lazy_loader_t private: /* Must only have one pointer. */ - mutable Stored *instance; + hb_atomic_ptr_t instance; }; /* Specializations. */ diff --git a/src/hb-object-private.hh b/src/hb-object-private.hh index 4725548..f5d78e5 100644 --- a/src/hb-object-private.hh +++ b/src/hb-object-private.hh @@ -143,12 +143,12 @@ struct hb_lockable_set_t struct hb_reference_count_t { - hb_atomic_int_t ref_count; + mutable hb_atomic_int_t ref_count; - inline void init (int v) { ref_count.set_relaxed (v); } + inline void init (int v = 1) { ref_count.set_relaxed (v); } inline int get_relaxed (void) const { return ref_count.get_relaxed (); } - inline int inc (void) { return ref_count.inc (); } - inline int dec (void) { return ref_count.dec (); } + inline int inc (void) const { return ref_count.inc (); } + inline int dec (void) const { return ref_count.dec (); } inline void fini (void) { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); } inline bool is_inert (void) const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; } @@ -194,9 +194,9 @@ struct hb_user_data_array_t struct hb_object_header_t { hb_reference_count_t ref_count; - mutable hb_user_data_array_t *user_data; + hb_atomic_ptr_t user_data; -#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, nullptr} +#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, HB_ATOMIC_PTR_INIT (nullptr)} private: ASSERT_POD (); @@ -231,8 +231,8 @@ static inline Type *hb_object_create (void) template static inline void hb_object_init (Type *obj) { - obj->header.ref_count.init (1); - obj->header.user_data = nullptr; + obj->header.ref_count.init (); + obj->header.user_data.init (); } template static inline bool hb_object_is_inert (const Type *obj) @@ -271,10 +271,11 @@ template static inline void hb_object_fini (Type *obj) { obj->header.ref_count.fini (); /* Do this before user_data */ - if (obj->header.user_data) + hb_user_data_array_t *user_data = obj->header.user_data.get (); + if (user_data) { - obj->header.user_data->fini (); - free (obj->header.user_data); + user_data->fini (); + free (user_data); } } template @@ -289,14 +290,14 @@ static inline bool hb_object_set_user_data (Type *obj, assert (hb_object_is_valid (obj)); retry: - hb_user_data_array_t *user_data = (hb_user_data_array_t *) hb_atomic_ptr_get (&obj->header.user_data); + hb_user_data_array_t *user_data = obj->header.user_data.get (); if (unlikely (!user_data)) { user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1); if (unlikely (!user_data)) return false; user_data->init (); - if (unlikely (!hb_atomic_ptr_cmpexch (&obj->header.user_data, nullptr, user_data))) + if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data))) { user_data->fini (); free (user_data); @@ -311,7 +312,7 @@ template static inline void *hb_object_get_user_data (Type *obj, hb_user_data_key_t *key) { - if (unlikely (!obj || hb_object_is_inert (obj) || !obj->header.user_data)) + if (unlikely (!obj || hb_object_is_inert (obj) || !obj->header.user_data.get ())) return nullptr; assert (hb_object_is_valid (obj)); return obj->header.user_data->get (key); diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 025f943..0284a45 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -225,15 +225,15 @@ hb_ot_get_font_v_extents (hb_font_t *font, return ot_font->v_metrics.has_font_extents; } -static hb_font_funcs_t *static_ot_funcs = nullptr; +static hb_atomic_ptr_t static_ot_funcs; #ifdef HB_USE_ATEXIT static void free_static_ot_funcs (void) { retry: - hb_font_funcs_t *ot_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); - if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, ot_funcs, nullptr)) + hb_font_funcs_t *ot_funcs = static_ot_funcs.get (); + if (unlikely (!static_ot_funcs.cmpexch (ot_funcs, nullptr))) goto retry; hb_font_funcs_destroy (ot_funcs); @@ -244,7 +244,7 @@ static hb_font_funcs_t * _hb_ot_get_font_funcs (void) { retry: - hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs); + hb_font_funcs_t *funcs = static_ot_funcs.get (); if (unlikely (!funcs)) { @@ -267,7 +267,8 @@ retry: hb_font_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) { + if (unlikely (!static_ot_funcs.cmpexch (nullptr, funcs))) + { hb_font_funcs_destroy (funcs); goto retry; } diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh index 2a74135..de1adda 100644 --- a/src/hb-ot-layout-private.hh +++ b/src/hb-ot-layout-private.hh @@ -219,7 +219,7 @@ HB_INTERNAL void _hb_ot_layout_destroy (hb_ot_layout_t *layout); -#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot) +#define hb_ot_layout_from_face(face) ((hb_ot_layout_t *) face->shaper_data.ot.get_relaxed ()) /* diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh index 9766f31..4f08a51 100644 --- a/src/hb-ot-post-table.hh +++ b/src/hb-ot-post-table.hh @@ -130,7 +130,7 @@ struct post inline void fini (void) { index_to_offset.fini (); - free (gids_sorted_by_name); + free (gids_sorted_by_name.get ()); } inline bool get_glyph_name (hb_codepoint_t glyph, @@ -162,7 +162,7 @@ struct post return false; retry: - uint16_t *gids = (uint16_t *) hb_atomic_ptr_get (&gids_sorted_by_name); + uint16_t *gids = gids_sorted_by_name.get (); if (unlikely (!gids)) { @@ -174,7 +174,8 @@ struct post gids[i] = i; hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); - if (!hb_atomic_ptr_cmpexch (&gids_sorted_by_name, nullptr, gids)) { + if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) + { free (gids); goto retry; } @@ -255,7 +256,7 @@ struct post const ArrayOf *glyphNameIndex; hb_vector_t index_to_offset; const uint8_t *pool; - mutable uint16_t *gids_sorted_by_name; + hb_atomic_ptr_t gids_sorted_by_name; }; public: diff --git a/src/hb-ot-shape-complex-arabic.cc b/src/hb-ot-shape-complex-arabic.cc index 0c4948d..f4b397b 100644 --- a/src/hb-ot-shape-complex-arabic.cc +++ b/src/hb-ot-shape-complex-arabic.cc @@ -250,7 +250,7 @@ struct arabic_shape_plan_t * mask_array[NONE] == 0. */ hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1]; - mutable arabic_fallback_plan_t *fallback_plan; + hb_atomic_ptr_t fallback_plan; unsigned int do_fallback : 1; unsigned int has_stch : 1; @@ -280,7 +280,7 @@ data_destroy_arabic (void *data) { arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) data; - arabic_fallback_plan_destroy (arabic_plan->fallback_plan); + arabic_fallback_plan_destroy (arabic_plan->fallback_plan.get ()); free (data); } @@ -403,12 +403,13 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan, return; retry: - arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_atomic_ptr_get (&arabic_plan->fallback_plan); + arabic_fallback_plan_t *fallback_plan = arabic_plan->fallback_plan.get (); if (unlikely (!fallback_plan)) { /* This sucks. We need a font to build the fallback plan... */ fallback_plan = arabic_fallback_plan_create (plan, font); - if (unlikely (!hb_atomic_ptr_cmpexch (&(const_cast (arabic_plan))->fallback_plan, nullptr, fallback_plan))) { + if (unlikely (!arabic_plan->fallback_plan.cmpexch (nullptr, fallback_plan))) + { arabic_fallback_plan_destroy (fallback_plan); goto retry; } diff --git a/src/hb-shape-plan.cc b/src/hb-shape-plan.cc index cc1834c..0d61d9e 100644 --- a/src/hb-shape-plan.cc +++ b/src/hb-shape-plan.cc @@ -49,11 +49,13 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan, #define HB_SHAPER_PLAN(shaper) \ HB_STMT_START { \ - if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) { \ - HB_SHAPER_DATA (shaper, shape_plan) = \ + if (hb_##shaper##_shaper_face_data_ensure (shape_plan->face_unsafe)) \ + { \ + /* XXX-MT-bug What happened to *ensure*ing this?!!!! */ \ + HB_SHAPER_DATA (shaper, shape_plan).set_relaxed ( \ HB_SHAPER_DATA_CREATE_FUNC (shaper, shape_plan) (shape_plan, \ user_features, num_user_features, \ - coords, num_coords); \ + coords, num_coords)); \ shape_plan->shaper_func = _hb_##shaper##_shape; \ shape_plan->shaper_name = #shaper; \ return; \ @@ -106,10 +108,10 @@ DEFINE_NULL_INSTANCE (hb_shape_plan_t) = 0, /* num_coords */ { -#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID, +#define HB_SHAPER_IMPLEMENT(shaper) HB_ATOMIC_PTR_INIT (HB_SHAPER_DATA_INVALID), #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT - } + }, }; @@ -339,7 +341,7 @@ hb_shape_plan_execute (hb_shape_plan_t *shape_plan, #define HB_SHAPER_EXECUTE(shaper) \ HB_STMT_START { \ - return HB_SHAPER_DATA (shaper, shape_plan) && \ + return HB_SHAPER_DATA (shaper, shape_plan).get () && \ hb_##shaper##_shaper_font_data_ensure (font) && \ _hb_##shaper##_shape (shape_plan, font, buffer, features, num_features); \ } HB_STMT_END @@ -517,7 +519,7 @@ hb_shape_plan_create_cached2 (hb_face_t *face, retry: - hb_face_t::plan_node_t *cached_plan_nodes = (hb_face_t::plan_node_t *) hb_atomic_ptr_get (&face->shape_plans); + hb_face_t::plan_node_t *cached_plan_nodes = face->shape_plans.get (); /* Don't look for plan in the cache if there were variation coordinates XXX Fix me. */ if (!hb_coords_present (coords, num_coords)) @@ -552,7 +554,8 @@ retry: node->shape_plan = shape_plan; node->next = cached_plan_nodes; - if (!hb_atomic_ptr_cmpexch (&face->shape_plans, cached_plan_nodes, node)) { + if (unlikely (!face->shape_plans.cmpexch (cached_plan_nodes, node))) + { hb_shape_plan_destroy (shape_plan); free (node); goto retry; diff --git a/src/hb-shape.cc b/src/hb-shape.cc index c1e7365..01734f8 100644 --- a/src/hb-shape.cc +++ b/src/hb-shape.cc @@ -45,15 +45,15 @@ * contains the output glyphs and their positions. **/ -static const char **static_shaper_list; +static hb_atomic_ptr_t static_shaper_list; #ifdef HB_USE_ATEXIT static void free_static_shaper_list (void) { retry: - const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list); - if (!hb_atomic_ptr_cmpexch (&static_shaper_list, shaper_list, nullptr)) + const char **shaper_list = static_shaper_list.get (); + if (unlikely (!static_shaper_list.cmpexch (shaper_list, nullptr))) goto retry; free (shaper_list); @@ -74,7 +74,7 @@ const char ** hb_shape_list_shapers (void) { retry: - const char **shaper_list = (const char **) hb_atomic_ptr_get (&static_shaper_list); + const char **shaper_list = static_shaper_list.get (); if (unlikely (!shaper_list)) { @@ -91,7 +91,8 @@ retry: shaper_list[i] = shapers[i].name; shaper_list[i] = nullptr; - if (!hb_atomic_ptr_cmpexch (&static_shaper_list, nullptr, shaper_list)) { + if (unlikely (!static_shaper_list.cmpexch (nullptr, shaper_list))) + { free (shaper_list); goto retry; } diff --git a/src/hb-shaper-impl-private.hh b/src/hb-shaper-impl-private.hh index 7844081..4a10279 100644 --- a/src/hb-shaper-impl-private.hh +++ b/src/hb-shaper-impl-private.hh @@ -36,7 +36,7 @@ #ifdef HB_SHAPER -#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object) +#define HB_SHAPER_DATA_GET(object) HB_SHAPER_DATA (HB_SHAPER, object).get () #endif diff --git a/src/hb-shaper-private.hh b/src/hb-shaper-private.hh index 457cd95..fb04bbc 100644 --- a/src/hb-shaper-private.hh +++ b/src/hb-shaper-private.hh @@ -56,7 +56,7 @@ _hb_shapers_get (void); #define HB_SHAPER_DATA_TYPE_NAME(shaper, object) hb_##shaper##_##object##_data_t #define HB_SHAPER_DATA_TYPE(shaper, object) struct HB_SHAPER_DATA_TYPE_NAME(shaper, object) -#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance) (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper) +#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance) (* reinterpret_cast *> (&(instance)->shaper_data.shaper)) #define HB_SHAPER_DATA(shaper, object) HB_SHAPER_DATA_INSTANCE(shaper, object, object) #define HB_SHAPER_DATA_CREATE_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_create #define HB_SHAPER_DATA_DESTROY_FUNC(shaper, object) _hb_##shaper##_shaper_##object##_data_destroy @@ -72,7 +72,7 @@ _hb_shapers_get (void); HB_SHAPER_DATA_ENSURE_FUNC (shaper, object) (hb_##object##_t *object) #define HB_SHAPER_DATA_DESTROY(shaper, object) \ - if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object)) \ + if (HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object).get ()) \ if (data != HB_SHAPER_DATA_INVALID && data != HB_SHAPER_DATA_SUCCEEDED) \ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); @@ -84,9 +84,10 @@ bool \ HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \ {\ retry: \ - HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \ + HB_SHAPER_DATA_TYPE (shaper, object) *data = HB_SHAPER_DATA (shaper, object).get (); \ if (likely (data) && !(condition)) { \ - /* Note that evaluating condition above can be dangerous if another thread \ + /* XXX-MT-bug \ + * Note that evaluating condition above can be dangerous if another thread \ * got here first and destructed data. That's, as always, bad use pattern. \ * If you modify the font (change font size), other threads must not be \ * using it at the same time. However, since this check is delayed to \ @@ -99,7 +100,8 @@ HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \ /* Drop and recreate. */ \ /* If someone dropped it in the mean time, throw it away and don't touch it. \ * Otherwise, destruct it. */ \ - if (hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), data, nullptr)) { \ + if (likely (HB_SHAPER_DATA (shaper, object).cmpexch (data, nullptr))) \ + { \ HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (data); \ } \ goto retry; \ @@ -108,7 +110,7 @@ HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \ data = HB_SHAPER_DATA_CREATE_FUNC (shaper, object) (object); \ if (unlikely (!data)) \ data = (HB_SHAPER_DATA_TYPE (shaper, object) *) HB_SHAPER_DATA_INVALID; \ - if (!hb_atomic_ptr_cmpexch (&HB_SHAPER_DATA (shaper, object), nullptr, data)) { \ + if (unlikely (!HB_SHAPER_DATA (shaper, object).cmpexch (nullptr, data))) { \ if (data && \ data != HB_SHAPER_DATA_INVALID && \ data != HB_SHAPER_DATA_SUCCEEDED) \ @@ -122,7 +124,7 @@ HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \ /* For embedding in face / font / ... */ struct hb_shaper_data_t { -#define HB_SHAPER_IMPLEMENT(shaper) void *shaper; +#define HB_SHAPER_IMPLEMENT(shaper) hb_atomic_ptr_t shaper; #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT }; diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc index d44d8c9..e487582 100644 --- a/src/hb-shaper.cc +++ b/src/hb-shaper.cc @@ -38,15 +38,15 @@ static const hb_shaper_pair_t all_shapers[] = { /* Thread-safe, lock-free, shapers */ -static const hb_shaper_pair_t *static_shapers; +static hb_atomic_ptr_t static_shapers; #ifdef HB_USE_ATEXIT static void free_static_shapers (void) { retry: - hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); - if (!hb_atomic_ptr_cmpexch (&static_shapers, shapers, nullptr)) + const hb_shaper_pair_t *shapers = static_shapers.get (); + if (unlikely (!static_shapers.cmpexch (shapers, nullptr))) goto retry; if (unlikely (shapers != all_shapers)) @@ -58,20 +58,21 @@ const hb_shaper_pair_t * _hb_shapers_get (void) { retry: - hb_shaper_pair_t *shapers = (hb_shaper_pair_t *) hb_atomic_ptr_get (&static_shapers); + hb_shaper_pair_t *shapers = const_cast (static_shapers.get ()); if (unlikely (!shapers)) { char *env = getenv ("HB_SHAPER_LIST"); if (!env || !*env) { - (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]); + (void) static_shapers.cmpexch (nullptr, &all_shapers[0]); return (const hb_shaper_pair_t *) all_shapers; } /* Not found; allocate one. */ shapers = (hb_shaper_pair_t *) calloc (1, sizeof (all_shapers)); - if (unlikely (!shapers)) { - (void) hb_atomic_ptr_cmpexch (&static_shapers, nullptr, &all_shapers[0]); + if (unlikely (!shapers)) + { + (void) static_shapers.cmpexch (nullptr, &all_shapers[0]); return (const hb_shaper_pair_t *) all_shapers; } @@ -102,7 +103,8 @@ retry: p = end + 1; } - if (!hb_atomic_ptr_cmpexch (&static_shapers, nullptr, shapers)) { + if (unlikely (!static_shapers.cmpexch (nullptr, shapers))) + { free (shapers); goto retry; } diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc index 2c08718..b414b1d 100644 --- a/src/hb-ucdn.cc +++ b/src/hb-ucdn.cc @@ -238,15 +238,15 @@ hb_ucdn_decompose_compatibility(hb_unicode_funcs_t *ufuncs HB_UNUSED, return ucdn_compat_decompose(u, decomposed); } -static hb_unicode_funcs_t *static_ucdn_funcs = nullptr; +static hb_atomic_ptr_t static_ucdn_funcs; #ifdef HB_USE_ATEXIT static void free_static_ucdn_funcs (void) { retry: - hb_unicode_funcs_t *ucdn_funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs); - if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, ucdn_funcs, nullptr)) + hb_unicode_funcs_t *ucdn_funcs = static_ucdn_funcs.get (); + if (unlikely (!static_ucdn_funcs.cmpexch (ucdn_funcs, nullptr))) goto retry; hb_unicode_funcs_destroy (ucdn_funcs); @@ -258,7 +258,7 @@ hb_unicode_funcs_t * hb_ucdn_get_unicode_funcs (void) { retry: - hb_unicode_funcs_t *funcs = (hb_unicode_funcs_t *) hb_atomic_ptr_get (&static_ucdn_funcs); + hb_unicode_funcs_t *funcs = static_ucdn_funcs.get (); if (unlikely (!funcs)) { @@ -271,7 +271,8 @@ retry: hb_unicode_funcs_make_immutable (funcs); - if (!hb_atomic_ptr_cmpexch (&static_ucdn_funcs, nullptr, funcs)) { + if (unlikely (!static_ucdn_funcs.cmpexch (nullptr, funcs))) + { hb_unicode_funcs_destroy (funcs); goto retry; } diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 94e6bb5..22beb90 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -220,19 +220,18 @@ struct hb_uniscribe_shaper_funcs_t { } } }; -static hb_uniscribe_shaper_funcs_t *uniscribe_funcs; +static hb_atomic_ptr_t uniscribe_funcs; #ifdef HB_USE_ATEXIT static inline void free_uniscribe_funcs (void) { retry: - hb_uniscribe_shaper_funcs_t *local_uniscribe_funcs = - (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs); - if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, local_uniscribe_funcs, nullptr)) + hb_uniscribe_shaper_funcs_t *local_uniscribe_funcs = uniscribe_funcs.get (); + if (unlikely (!uniscribe_funcs.cmpexch (local_uniscribe_funcs, nullptr))) goto retry; - free (uniscribe_funcs); + free (local_uniscribe_funcs); } #endif @@ -240,7 +239,7 @@ static hb_uniscribe_shaper_funcs_t * hb_uniscribe_shaper_get_funcs (void) { retry: - hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs); + hb_uniscribe_shaper_funcs_t *funcs = uniscribe_funcs.get (); if (unlikely (!funcs)) { @@ -250,7 +249,8 @@ retry: funcs->init (); - if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, nullptr, funcs)) { + if (unlikely (!uniscribe_funcs.cmpexch (nullptr, funcs))) + { free (funcs); goto retry; } -- 2.7.4