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;
 }