The test/object test is passing again, instead of deadlocking.
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)
* 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,
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;
}
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;
-
- hb_mutex_unlock (&user_data_mutex);
+ return items.find (key, &item, user_data_lock) ? item.data : NULL;
+}
- return ret;
+void
+hb_user_data_array_t::finish (void)
+{
+ items.finish (user_data_lock);
}
hb_static_mutex_t (void) {
hb_mutex_init (this);
}
+
+ inline void lock (void) { hb_mutex_lock (this); }
+ inline void unlock (void) { hb_mutex_unlock (this); }
};
HB_END_DECLS
-/* XXX If the finish() callbacks of items in the set recursively try to
- * modify the set, deadlock occurs. This needs fixing in set proper in
- * fact. */
-
template <typename item_t>
-struct hb_threadsafe_set_t
+struct hb_static_threadsafe_set_t
{
- hb_set_t <item_t> set;
- hb_static_mutex_t mutex;
+ hb_lockable_set_t <item_t, hb_static_mutex_t> set;
+ hb_static_mutex_t lock;
template <typename T>
- inline item_t *insert (T v)
+ inline item_t *replace_or_insert (T v)
{
- hb_mutex_lock (&mutex);
- item_t *item = set.insert (v);
- hb_mutex_unlock (&mutex);
- return item;
+ return set.replace_or_insert (v, lock);
}
template <typename T>
inline void remove (T v)
{
- hb_mutex_lock (&mutex);
- set.remove (v);
- hb_mutex_unlock (&mutex);
+ set.remove (v, lock);
}
template <typename T>
- inline item_t *find (T v)
+ inline bool find (T v, item_t *i)
{
- hb_mutex_lock (&mutex);
- item_t *item = set.find (v);
- hb_mutex_unlock (&mutex);
- return item;
+ return set.find (v, i, lock);
}
template <typename T>
- inline item_t *find_or_insert (T v) {
- hb_mutex_lock (&mutex);
- item_t *item = set.find_or_insert (v);
- hb_mutex_unlock (&mutex);
- return item;
+ inline item_t *find_or_insert (T v)
+ {
+ return set.find_or_insert (v, lock);
}
- void finish (void) {
- hb_mutex_lock (&mutex);
- set.finish ();
- hb_mutex_unlock (&mutex);
+ void finish (void)
+ {
+ set.finish (lock);
}
-
};
#include "hb-private.hh"
+#include "hb-mutex-private.hh"
+
HB_BEGIN_DECLS
void finish (void) { if (destroy) destroy (data); }
};
- hb_set_t<hb_user_data_item_t> items;
+ hb_lockable_set_t<hb_user_data_item_t, hb_static_mutex_t> items;
HB_INTERNAL bool set (hb_user_data_key_t *key,
void * data,
HB_INTERNAL void *get (hb_user_data_key_t *key);
- void finish (void) { items.finish (); }
+ HB_INTERNAL void finish (void);
};
struct hb_array_t : hb_prealloced_array_t<Type, 2> {};
-template <typename item_t>
-struct hb_set_t
+template <typename item_t, typename lock_t>
+struct hb_lockable_set_t
{
hb_array_t <item_t> items;
template <typename T>
- inline item_t *insert (T v)
+ inline item_t *replace_or_insert (T v, lock_t &l)
{
+ l.lock ();
item_t *item = items.find (v);
- if (item)
- item->finish ();
- else
+ if (item) {
+ item_t old = *item;
+ *item = v;
+ l.unlock ();
+ old.finish ();
+ } else {
item = items.push ();
- if (unlikely (!item)) return NULL;
- *item = v;
+ if (likely (item))
+ *item = v;
+ l.unlock ();
+ }
return item;
}
template <typename T>
- inline void remove (T v)
+ inline void remove (T v, lock_t &l)
{
+ l.lock ();
item_t *item = items.find (v);
- if (!item) return;
-
- item->finish ();
- *item = items[items.len - 1];
- items.pop ();
+ if (item) {
+ item_t old = *item;
+ *item = items[items.len - 1];
+ items.pop ();
+ l.unlock ();
+ old.finish ();
+ } else {
+ l.unlock ();
+ }
}
template <typename T>
- inline item_t *find (T v)
+ inline bool find (T v, item_t *i, lock_t &l)
{
- return items.find (v);
+ l.lock ();
+ item_t *item = items.find (v);
+ if (item)
+ *i = *item;
+ l.unlock ();
+ return !!item;
}
template <typename T>
- inline item_t *find_or_insert (T v) {
- item_t *item = find (v);
+ inline item_t *find_or_insert (T v, lock_t &l)
+ {
+ l.lock ();
+ item_t *item = items.find (v);
if (!item) {
item = items.push ();
if (likely (item))
*item = v;
}
+ l.unlock ();
return item;
}
- void finish (void) {
- for (unsigned i = 0; i < items.len; i++)
- items[i].finish ();
+ inline void finish (lock_t &l)
+ {
+ l.lock ();
+ while (items.len) {
+ item_t old = items[items.len - 1];
+ items.pop ();
+ l.unlock ();
+ old.finish ();
+ l.lock ();
+ }
items.shrink (0);
+ l.unlock ();
+ }
+
+};
+
+template <typename item_t>
+struct hb_set_t
+{
+ struct lock_t {
+ int unused;
+
+ inline void lock (void) {}
+ inline void unlock (void) {}
+ };
+
+ hb_lockable_set_t <item_t, lock_t> set;
+
+ template <typename T>
+ inline item_t *replace_or_insert (T v)
+ {
+ lock_t lock;
+ return set.replace_or_insert (v, lock);
+ }
+
+ template <typename T>
+ inline void remove (T v)
+ {
+ lock_t lock;
+ set.remove (v, lock);
+ }
+
+ template <typename T>
+ inline bool find (T v, item_t *i)
+ {
+ lock_t lock;
+ return set.find (v, i, lock);
+ }
+
+ template <typename T>
+ inline item_t *find_or_insert (T v)
+ {
+ lock_t lock;
+ return set.find_or_insert (v, lock);
+ }
+
+ void finish (void)
+ {
+ lock_t lock;
+ set.finish (lock);
}
};