Fix set implementation to be truly threadsafe even with destroy() callbacks The test/object test is passing again, instead of deadlocking.
diff --git a/src/hb-common.cc b/src/hb-common.cc index 02314b3..782d85a 100644 --- a/src/hb-common.cc +++ b/src/hb-common.cc
@@ -162,7 +162,7 @@ void finish (void) { free (lang); } }; -static hb_threadsafe_set_t<hb_language_item_t> langs; +static hb_static_threadsafe_set_t<hb_language_item_t> langs; hb_language_t hb_language_from_string (const char *str) @@ -293,8 +293,7 @@ * should switch to using that insted for these too. */ -/* XXX this can result in deadlocks because we call user callbacks */ -static hb_static_mutex_t user_data_mutex; +static hb_static_mutex_t user_data_lock; bool hb_user_data_array_t::set (hb_user_data_key_t *key, @@ -304,16 +303,12 @@ if (!key) return false; - hb_mutex_lock (&user_data_mutex); - if (!data && !destroy) { - items.remove (key); + items.remove (key, user_data_lock); return true; } hb_user_data_item_t item = {key, data, destroy}; - bool ret = !!items.insert (item); - - hb_mutex_unlock (&user_data_mutex); + bool ret = !!items.replace_or_insert (item, user_data_lock); return ret; } @@ -321,14 +316,15 @@ void * hb_user_data_array_t::get (hb_user_data_key_t *key) { - hb_mutex_lock (&user_data_mutex); + hb_user_data_item_t item = {NULL }; - hb_user_data_item_t *item = items.find (key); - void *ret = item ? item->data : NULL; + return items.find (key, &item, user_data_lock) ? item.data : NULL; +} - hb_mutex_unlock (&user_data_mutex); - - return ret; +void +hb_user_data_array_t::finish (void) +{ + items.finish (user_data_lock); }