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
|
static hb_bool_t
|
||||||
lang_equal (const void *v1,
|
lang_equal (hb_language_t v1,
|
||||||
const void *v2)
|
const void *v2)
|
||||||
{
|
{
|
||||||
const unsigned char *p1 = (const unsigned char *) v1;
|
const unsigned char *p1 = (const unsigned char *) v1;
|
||||||
const unsigned char *p2 = (const unsigned char *) v2;
|
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++;
|
||||||
p1++, p2++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (canon_map[*p1] == canon_map[*p2]);
|
return *p1 == canon_map[*p2];
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -147,6 +145,7 @@ lang_hash (const void *key)
|
||||||
|
|
||||||
struct hb_language_item_t {
|
struct hb_language_item_t {
|
||||||
|
|
||||||
|
struct hb_language_item_t *next;
|
||||||
hb_language_t lang;
|
hb_language_t lang;
|
||||||
|
|
||||||
inline bool operator == (const char *s) const {
|
inline bool operator == (const char *s) const {
|
||||||
|
@ -164,10 +163,53 @@ struct hb_language_item_t {
|
||||||
void finish (void) { free (lang); }
|
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); }
|
/* Thread-safe lock-free language list */
|
||||||
hb_static_mutex_t lock;
|
|
||||||
} langs;
|
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_t
|
||||||
hb_language_from_string (const char *str, int len)
|
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';
|
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;
|
return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue