Print this page
Thread safety fixes.

*** 41,50 **** --- 41,51 ---- #include <locale.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <stdio.h> + #include "mtlib.h" #include "collate.h" #include "lnumeric.h" /* for struct lc_numeric */ #include "lctype.h" /* for struct lc_ctype */ #include "setlocale.h" #include "../i18n/_loc_path.h"
*** 57,71 **** char *_PathLocale = _DFLT_LOC_PATH; static char *current_locale(locale_t, int); static void install_legacy(locale_t, int); char * setlocale(int category, const char *locname) { ! locale_t oldloc; ! locale_t newloc; int mask; if (category < 0 || category > LC_ALL) { errno = EINVAL; return (NULL); --- 58,75 ---- char *_PathLocale = _DFLT_LOC_PATH; static char *current_locale(locale_t, int); static void install_legacy(locale_t, int); + static mutex_t setlocale_lock = DEFAULTMUTEX; + static locale_t setlocale_list = NULL; + char * setlocale(int category, const char *locname) { ! locale_t loc; ! locale_t srch; int mask; if (category < 0 || category > LC_ALL) { errno = EINVAL; return (NULL);
*** 72,99 **** } if (locname == NULL) return (current_locale(___global_locale, category)); - if ((oldloc = duplocale(___global_locale)) == NULL) - return (NULL); - mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category)); ! newloc = newlocale(mask, locname, oldloc); ! if (newloc == NULL) { ! freelocale(oldloc); return (NULL); } ! oldloc = ___global_locale; ! ___global_locale = newloc; ! install_legacy(newloc, mask); ! freelocale(oldloc); ! return (current_locale(newloc, category)); } static char * current_locale(locale_t loc, int cat) { --- 76,125 ---- } if (locname == NULL) return (current_locale(___global_locale, category)); mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category)); ! loc = newlocale(mask, locname, NULL); ! if (loc == NULL) { return (NULL); } ! /* ! * This next logic looks to see if we have ever used the same locale ! * settings before. If so, we reuse it. We avoid ever calling ! * freelocale() on a locale setting built up by setlocale, this ! * ensures that consumers (uselocale) will always be thread safe; ! * the actual locale data objects are never freed, and unique ! * locale objects are also never freed. We reuse to avoid leaking ! * memory in applications that call setlocale repeatedly. ! */ ! lmutex_lock(&setlocale_lock); ! for (srch = setlocale_list; srch != NULL; srch = srch->next) { ! if (memcmp(srch->locdata, loc->locdata, ! sizeof (loc->locdata[0]) * LC_ALL) != 0) { ! continue; ! } ! break; ! } ! if (srch == NULL) { ! /* this is a new locale, save it for reuse later */ ! loc->next = setlocale_list; ! setlocale_list = loc; ! } else { ! /* we already had it, toss the new, and use what we found */ ! freelocale(loc); ! loc = srch; ! } ! ___global_locale = loc; ! install_legacy(loc, mask); ! lmutex_unlock(&setlocale_lock); ! ! return (current_locale(loc, category)); } static char * current_locale(locale_t loc, int cat) {