Print this page
Thread safety fixes.

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libc/port/locale/setlocale.c
          +++ new/usr/src/lib/libc/port/locale/setlocale.c
↓ open down ↓ 35 lines elided ↑ open up ↑
  36   36  #include "lint.h"
  37   37  #include <sys/types.h>
  38   38  #include <sys/stat.h>
  39   39  #include <errno.h>
  40   40  #include <limits.h>
  41   41  #include <locale.h>
  42   42  #include <stdlib.h>
  43   43  #include <string.h>
  44   44  #include <unistd.h>
  45   45  #include <stdio.h>
       46 +#include "mtlib.h"
  46   47  #include "collate.h"
  47   48  #include "lnumeric.h"   /* for struct lc_numeric */
  48   49  #include "lctype.h"     /* for struct lc_ctype */
  49   50  #include "setlocale.h"
  50   51  #include "../i18n/_loc_path.h"
  51   52  #include "localeimpl.h"
  52   53  #include "../i18n/_locale.h"
  53   54  
  54   55  /*
  55   56   * Path to locale storage directory.  See ../i18n/_loc_path.h
  56   57   */
  57   58  char    *_PathLocale = _DFLT_LOC_PATH;
  58   59  
  59   60  static char     *current_locale(locale_t, int);
  60   61  static void     install_legacy(locale_t, int);
  61   62  
       63 +static mutex_t setlocale_lock = DEFAULTMUTEX;
       64 +static locale_t setlocale_list = NULL;
       65 +
  62   66  char *
  63   67  setlocale(int category, const char *locname)
  64   68  {
  65      -        locale_t oldloc;
  66      -        locale_t newloc;
       69 +        locale_t loc;
       70 +        locale_t srch;
  67   71          int mask;
  68   72  
  69   73          if (category < 0 || category > LC_ALL) {
  70   74                  errno = EINVAL;
  71   75                  return (NULL);
  72   76          }
  73   77  
  74   78          if (locname == NULL)
  75   79                  return (current_locale(___global_locale, category));
  76   80  
  77      -        if ((oldloc = duplocale(___global_locale)) == NULL)
  78      -                return (NULL);
  79      -
  80   81          mask = (category == LC_ALL ? LC_ALL_MASK : (1 << category));
  81   82  
  82      -        newloc = newlocale(mask, locname, oldloc);
  83      -        if (newloc == NULL) {
  84      -                freelocale(oldloc);
       83 +        loc = newlocale(mask, locname, NULL);
       84 +        if (loc == NULL) {
  85   85                  return (NULL);
  86   86          }
  87   87  
  88      -        oldloc = ___global_locale;
  89      -        ___global_locale = newloc;
       88 +        /*
       89 +         * This next logic looks to see if we have ever used the same locale
       90 +         * settings before.  If so, we reuse it.  We avoid ever calling
       91 +         * freelocale() on a locale setting built up by setlocale, this
       92 +         * ensures that consumers (uselocale) will always be thread safe;
       93 +         * the actual locale data objects are never freed, and unique
       94 +         * locale objects are also never freed.  We reuse to avoid leaking
       95 +         * memory in applications that call setlocale repeatedly.
       96 +         */
       97 +        lmutex_lock(&setlocale_lock);
       98 +        for (srch = setlocale_list; srch != NULL; srch = srch->next) {
       99 +                if (memcmp(srch->locdata, loc->locdata,
      100 +                    sizeof (loc->locdata[0]) * LC_ALL) != 0) {
      101 +                        continue;
      102 +                }
      103 +                break;
      104 +        }
  90  105  
  91      -        install_legacy(newloc, mask);
      106 +        if (srch == NULL) {
      107 +                /* this is a new locale, save it for reuse later */
      108 +                loc->next = setlocale_list;
      109 +                setlocale_list = loc;
      110 +        } else {
      111 +                /* we already had it, toss the new, and use what we found */
      112 +                freelocale(loc);
      113 +                loc = srch;
      114 +        }
      115 +        ___global_locale = loc;
  92  116  
  93      -        freelocale(oldloc);
  94      -        return (current_locale(newloc, category));
      117 +        install_legacy(loc, mask);
      118 +        lmutex_unlock(&setlocale_lock);
      119 +
      120 +        return (current_locale(loc, category));
  95  121  }
  96  122  
  97  123  static char *
  98  124  current_locale(locale_t loc, int cat)
  99  125  {
 100  126          int composite = 0;
 101  127          static char buf[LC_ALL * (ENCODING_LEN + 1 + 1)];
 102  128  
 103  129          if (cat != LC_ALL) {
 104  130                  return (loc->locdata[cat]->l_lname);
↓ open down ↓ 77 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX