From 63c188ec42e76ff768e81f6b65b11c68fc43351e Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Wed, 27 May 2015 00:22:43 -0400 Subject: replace atomics with locks in locale-setting code this is part of a general program of removing direct use of atomics where they are not necessary to meet correctness or performance needs, but in this case it's also an optimization. only the global locale needs synchronization; allocated locales referenced with locale_t handles are immutable during their lifetimes, and using atomics to initialize them increases their cost of setup. --- src/locale/setlocale.c | 48 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) (limited to 'src/locale/setlocale.c') diff --git a/src/locale/setlocale.c b/src/locale/setlocale.c index d797f43f..32a8fcab 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; } -- cgit v1.2.1