diff --git a/src/locale/__setlocalecat.c b/src/locale/__setlocalecat.c index c93e9ba0de0334da84a382e942274456cee090d7..e829da56759b5ae7f42132abb6d48e37c9d97dfc 100644 --- a/src/locale/__setlocalecat.c +++ b/src/locale/__setlocalecat.c @@ -17,8 +17,9 @@ char *__strchrnul(const char *, int); static struct __locale_map *findlocale(const char *name, size_t n) { + static int lock[2]; static void *volatile loc_head; - struct __locale_map *p, *new, *old_head; + struct __locale_map *p, *new = 0; const char *path = 0, *z; char buf[256]; size_t l; @@ -28,11 +29,18 @@ static struct __locale_map *findlocale(const char *name, size_t n) for (p=loc_head; p; p=p->next) if (!strcmp(name, p->name)) return p; + LOCK(lock); + + for (p=loc_head; p; p=p->next) + if (!strcmp(name, p->name)) { + UNLOCK(lock); + return p; + } + if (!libc.secure) path = getenv("MUSL_LOCPATH"); /* FIXME: add a default path? */ - if (!path) return 0; - for (; *path; path=z+!!*z) { + if (path) for (; *path; path=z+!!*z) { z = __strchrnul(path, ':'); l = z - path - !!*z; if (l >= sizeof buf - n - 2) continue; @@ -45,20 +53,19 @@ static struct __locale_map *findlocale(const char *name, size_t n) new = malloc(sizeof *new); if (!new) { __munmap((void *)map, map_size); - return 0; + break; } new->map = map; new->map_size = map_size; memcpy(new->name, name, n); new->name[n] = 0; - do { - old_head = loc_head; - new->next = old_head; - } while (a_cas_p(&loc_head, old_head, new) != old_head); - return new; + new->next = loc_head; + loc_head = new; + break; } } - return 0; + UNLOCK(lock); + return new; } static const char envvars[][12] = { @@ -85,11 +92,10 @@ int __setlocalecat(locale_t loc, int cat, const char *val) int builtin = (val[0]=='C' && !val[1]) || !strcmp(val, "C.UTF-8") || !strcmp(val, "POSIX"); - struct __locale_map *data, *old; switch (cat) { case LC_CTYPE: - a_store(&loc->ctype_utf8, !builtin || val[1]=='.'); + loc->ctype_utf8 = !builtin || val[1]=='.'; break; case LC_MESSAGES: if (builtin) { @@ -100,10 +106,7 @@ int __setlocalecat(locale_t loc, int cat, const char *val) } /* fall through */ default: - data = builtin ? 0 : findlocale(val, n); - if (data == loc->cat[cat-2]) break; - do old = loc->cat[cat-2]; - while (a_cas_p(&loc->cat[cat-2], old, data) != old); + loc->cat[cat-2] = builtin ? 0 : findlocale(val, n); case LC_NUMERIC: break; } diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c index d797f43fe8855c3393fb41b965eaefabb578542c..32a8fcab5fde043654ed06a16820f9464bce1981 100644 --- a/src/locale/setlocale.c +++ b/src/locale/setlocale.c @@ -7,8 +7,29 @@ static char buf[2+4*(LOCALE_NAME_MAX+1)]; +static char *setlocale_one_unlocked(int cat, const char *name) +{ + struct __locale_map *lm; + + if (name) __setlocalecat(&libc.global_locale, cat, name); + + switch (cat) { + case LC_CTYPE: + return libc.global_locale.ctype_utf8 ? "C.UTF-8" : "C"; + case LC_NUMERIC: + return "C"; + case LC_MESSAGES: + return libc.global_locale.messages_name[0] + ? libc.global_locale.messages_name : "C"; + default: + lm = libc.global_locale.cat[cat-2]; + return lm ? lm->name : "C"; + } +} + char *setlocale(int cat, const char *name) { + static volatile int lock[2]; struct __locale_map *lm; int i, j; @@ -19,6 +40,8 @@ char *setlocale(int cat, const char *name) if ((unsigned)cat > LC_ALL) return 0; + LOCK(lock); + /* For LC_ALL, setlocale is required to return a string which * encodes the current setting for all categories. The format of * this string is unspecified, and only the following code, which @@ -37,12 +60,13 @@ char *setlocale(int cat, const char *name) memcpy(part, name + 2 + (i-2)*(LOCALE_NAME_MAX+1), LOCALE_NAME_MAX); for (j=LOCALE_NAME_MAX-1; j && part[j]==';'; j--) part[j] = 0; - setlocale(i, part); + setlocale_one_unlocked(i, part); } - setlocale(LC_MESSAGES, name + 2 + 3*(LOCALE_NAME_MAX+1)); + setlocale_one_unlocked(LC_MESSAGES, name + + 2 + 3*(LOCALE_NAME_MAX+1)); } else { for (i=0; iname, strlen(lm->name)); } + UNLOCK(lock); return buf; } - if (name) __setlocalecat(&libc.global_locale, cat, name); + char *ret = setlocale_one_unlocked(cat, name); - switch (cat) { - case LC_CTYPE: - return libc.global_locale.ctype_utf8 ? "C.UTF-8" : "C"; - case LC_NUMERIC: - return "C"; - case LC_MESSAGES: - return libc.global_locale.messages_name[0] - ? libc.global_locale.messages_name : "C"; - default: - lm = libc.global_locale.cat[cat-2]; - return lm ? lm->name : "C"; - } + UNLOCK(lock); + + return ret; }