Implement lock-free hb_language_t
Another static-initialization down. One more to go.
This commit is contained in:
parent
6843ce01be
commit
093171ccec
@ -114,18 +114,16 @@ static const char canon_map[256] = {
|
||||
};
|
||||
|
||||
static hb_bool_t
|
||||
lang_equal (const void *v1,
|
||||
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])
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user