Implement lock-free hb_language_t

Another static-initialization down.  One more to go.
This commit is contained in:
Behdad Esfahbod 2012-06-05 18:00:45 -04:00
parent 6843ce01be
commit 093171ccec
1 changed files with 54 additions and 12 deletions

View File

@ -114,18 +114,16 @@ static const char canon_map[256] = {
};
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 @@ lang_hash (const void *key)
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 @@ struct hb_language_item_t {
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 @@ hb_language_from_string (const char *str, int len)
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;
}