Implement lock-free hb_language_t
Another static-initialization down. One more to go.
diff --git a/src/hb-common.cc b/src/hb-common.cc
index c7ee9af..6972aa5 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -114,18 +114,16 @@
};
static hb_bool_t
-lang_equal (const void *v1,
- const void *v2)
+lang_equal (hb_language_t v1,
+ const void *v2)
{
const unsigned char *p1 = (const unsigned char *) v1;
const unsigned char *p2 = (const unsigned char *) v2;
- while (canon_map[*p1] && canon_map[*p1] == canon_map[*p2])
- {
- p1++, p2++;
- }
+ while (*p1 && *p1 == canon_map[*p2])
+ p1++, p2++;
- return (canon_map[*p1] == canon_map[*p2]);
+ return *p1 == canon_map[*p2];
}
#if 0
@@ -147,6 +145,7 @@
struct hb_language_item_t {
+ struct hb_language_item_t *next;
hb_language_t lang;
inline bool operator == (const char *s) const {
@@ -164,10 +163,53 @@
void finish (void) { free (lang); }
};
-static struct hb_static_lang_set_t : hb_lockable_set_t<hb_language_item_t, hb_static_mutex_t> {
- ~hb_static_lang_set_t (void) { this->finish (lock); }
- hb_static_mutex_t lock;
-} langs;
+
+/* Thread-safe lock-free language list */
+
+static hb_language_item_t *langs;
+
+static
+void free_langs (void)
+{
+ while (langs) {
+ hb_language_item_t *next = langs->next;
+ langs->finish ();
+ free (langs);
+ langs = next;
+ }
+}
+
+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);
+
+ for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
+ if (*lang == key)
+ return lang;
+
+ /* Not found; allocate one. */
+ hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
+ if (unlikely (!lang))
+ return NULL;
+ lang->next = first_lang;
+ *lang = key;
+
+ if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
+ free (lang);
+ goto retry;
+ }
+
+#ifdef HAVE_ATEXIT
+ if (!first_lang) /* First person registers atexit() callback. */
+ atexit (free_langs);
+#endif
+
+ return lang;
+}
+
hb_language_t
hb_language_from_string (const char *str, int len)
@@ -182,7 +224,7 @@
strbuf[len] = '\0';
}
- hb_language_item_t *item = langs.find_or_insert (str, langs.lock);
+ hb_language_item_t *item = lang_find_or_insert (str);
return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
}