Make atexit callbacks threadsafe (#930)

diff --git a/src/hb-common.cc b/src/hb-common.cc
index ce3d01b..b16c932 100644
--- a/src/hb-common.cc
+++ b/src/hb-common.cc
@@ -60,12 +60,12 @@
 
 /**
  * hb_tag_from_string:
- * @str: (array length=len) (element-type uint8_t): 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -90,10 +90,10 @@
 
 /**
  * hb_tag_to_string:
- * @tag: 
- * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): 
+ * @tag:
+ * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
  *
- * 
+ *
  *
  * Since: 0.9.5
  **/
@@ -118,12 +118,12 @@
 
 /**
  * hb_direction_from_string:
- * @str: (array length=len) (element-type uint8_t): 
- * @len: 
+ * @str: (array length=len) (element-type uint8_t):
+ * @len:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -146,11 +146,11 @@
 
 /**
  * hb_direction_to_string:
- * @direction: 
+ * @direction:
  *
- * 
  *
- * Return value: (transfer none): 
+ *
+ * Return value: (transfer none):
  *
  * Since: 0.9.2
  **/
@@ -361,7 +361,7 @@
 /**
  * hb_language_get_default:
  *
- * 
+ *
  *
  * Return value: (transfer none):
  *
@@ -390,7 +390,7 @@
  *
  * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
  *
- * Return value: 
+ * Return value:
  * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
@@ -439,7 +439,7 @@
  * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
  * hb_script_from_iso15924_tag().
  *
- * Return value: 
+ * Return value:
  * An #hb_script_t corresponding to the ISO 15924 tag.
  *
  * Since: 0.9.2
@@ -469,11 +469,11 @@
 
 /**
  * hb_script_get_horizontal_direction:
- * @script: 
+ * @script:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.2
  **/
@@ -613,13 +613,13 @@
 
 /**
  * hb_version_atleast:
- * @major: 
- * @minor: 
- * @micro: 
+ * @major:
+ * @minor:
+ * @micro:
  *
- * 
  *
- * Return value: 
+ *
+ * Return value:
  *
  * Since: 0.9.30
  **/
@@ -724,8 +724,14 @@
 static void
 free_C_locale (void)
 {
-  if (C_locale)
-    HB_FREE_LOCALE (C_locale);
+retry:
+  HB_LOCALE_T locale = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
+
+  if (!hb_atomic_ptr_cmpexch (&C_locale, locale, nullptr))
+    goto retry;
+
+  if (locale)
+    HB_FREE_LOCALE (locale);
 }
 #endif
 
diff --git a/src/hb-ft.cc b/src/hb-ft.cc
index fc4b112..e68960d 100644
--- a/src/hb-ft.cc
+++ b/src/hb-ft.cc
@@ -109,7 +109,7 @@
  * @font:
  * @load_flags:
  *
- * 
+ *
  *
  * Since: 1.0.5
  **/
@@ -131,7 +131,7 @@
  * hb_ft_font_get_load_flags:
  * @font:
  *
- * 
+ *
  *
  * Return value:
  * Since: 1.0.5
@@ -423,7 +423,12 @@
 static
 void free_static_ft_funcs (void)
 {
-  hb_font_funcs_destroy (static_ft_funcs);
+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))
+    goto retry;
+
+  hb_font_funcs_destroy (ft_funcs);
 }
 #endif
 
@@ -502,12 +507,12 @@
 
 /**
  * hb_ft_face_create:
- * @ft_face: (destroy destroy) (scope notified): 
+ * @ft_face: (destroy destroy) (scope notified):
  * @destroy:
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  * Since: 0.9.2
  **/
 hb_face_t *
@@ -539,9 +544,9 @@
  * hb_ft_face_create_referenced:
  * @ft_face:
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  * Since: 0.9.38
  **/
 hb_face_t *
@@ -559,11 +564,11 @@
 
 /**
  * hb_ft_face_create_cached:
- * @ft_face: 
+ * @ft_face:
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  * Since: 0.9.2
  **/
 hb_face_t *
@@ -584,12 +589,12 @@
 
 /**
  * hb_ft_font_create:
- * @ft_face: (destroy destroy) (scope notified): 
+ * @ft_face: (destroy destroy) (scope notified):
  * @destroy:
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  * Since: 0.9.2
  **/
 hb_font_t *
@@ -664,9 +669,9 @@
  * hb_ft_font_create_referenced:
  * @ft_face:
  *
- * 
  *
- * Return value: (transfer full): 
+ *
+ * Return value: (transfer full):
  * Since: 0.9.38
  **/
 hb_font_t *
@@ -685,7 +690,12 @@
 static
 void free_ft_library (void)
 {
-  FT_Done_FreeType (ft_library);
+retry:
+  FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
+  if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
+    goto retry;
+
+  FT_Done_FreeType (library);
 }
 #endif
 
diff --git a/src/hb-glib.cc b/src/hb-glib.cc
index 50c30e9..246380a 100644
--- a/src/hb-glib.cc
+++ b/src/hb-glib.cc
@@ -370,7 +370,12 @@
 static
 void free_static_glib_funcs (void)
 {
-  hb_unicode_funcs_destroy (static_glib_funcs);
+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))
+    goto retry;
+
+  hb_unicode_funcs_destroy (glib_funcs);
 }
 #endif
 
diff --git a/src/hb-icu.cc b/src/hb-icu.cc
index 552eaec..c52e165 100644
--- a/src/hb-icu.cc
+++ b/src/hb-icu.cc
@@ -351,7 +351,12 @@
 static
 void free_static_icu_funcs (void)
 {
-  hb_unicode_funcs_destroy (static_icu_funcs);
+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))
+    goto retry;
+
+  hb_unicode_funcs_destroy (icu_funcs);
 }
 #endif
 
diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc
index 0e373d3..5e7a6da 100644
--- a/src/hb-ot-font.cc
+++ b/src/hb-ot-font.cc
@@ -217,7 +217,12 @@
 static
 void free_static_ot_funcs (void)
 {
-  hb_font_funcs_destroy (static_ot_funcs);
+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))
+    goto retry;
+
+  hb_font_funcs_destroy (ot_funcs);
 }
 #endif
 
diff --git a/src/hb-shape.cc b/src/hb-shape.cc
index 39355b3..c1e7365 100644
--- a/src/hb-shape.cc
+++ b/src/hb-shape.cc
@@ -51,7 +51,12 @@
 static
 void free_static_shaper_list (void)
 {
-  free (static_shaper_list);
+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))
+    goto retry;
+
+  free (shaper_list);
 }
 #endif
 
diff --git a/src/hb-shaper.cc b/src/hb-shaper.cc
index 2c44cf2..d44d8c9 100644
--- a/src/hb-shaper.cc
+++ b/src/hb-shaper.cc
@@ -44,8 +44,13 @@
 static
 void free_static_shapers (void)
 {
-  if (unlikely (static_shapers != all_shapers))
-    free ((void *) static_shapers);
+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))
+    goto retry;
+
+  if (unlikely (shapers != all_shapers))
+    free ((void *) shapers);
 }
 #endif
 
diff --git a/src/hb-ucdn.cc b/src/hb-ucdn.cc
index 9515bda..02ea366 100644
--- a/src/hb-ucdn.cc
+++ b/src/hb-ucdn.cc
@@ -237,7 +237,12 @@
 static
 void free_static_ucdn_funcs (void)
 {
-  hb_unicode_funcs_destroy (static_ucdn_funcs);
+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))
+    goto retry;
+
+  hb_unicode_funcs_destroy (ucdn_funcs);
 }
 #endif
 
diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc
index e780f88..b4717a3 100644
--- a/src/hb-uniscribe.cc
+++ b/src/hb-uniscribe.cc
@@ -223,11 +223,19 @@
 };
 static hb_uniscribe_shaper_funcs_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))
+    goto retry;
+
   free (uniscribe_funcs);
 }
+#endif
 
 static hb_uniscribe_shaper_funcs_t *
 hb_uniscribe_shaper_get_funcs (void)