]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/locutil.cpp
ICU-57132.0.1.tar.gz
[apple/icu.git] / icuSources / common / locutil.cpp
index e70b61628cffb01923eaa7df3d2483a955c56343..e5fe18c4c3c42e74deb738b4d5c0ab106d45b52c 100644 (file)
@@ -1,9 +1,7 @@
-/**
- *******************************************************************************
- * Copyright (C) 2002-2006, International Business Machines Corporation and    *
- * others. All Rights Reserved.                                                *
+/*
  *******************************************************************************
  *******************************************************************************
- *
+ * Copyright (C) 2002-2014, International Business Machines Corporation and
+ * others. All Rights Reserved.
  *******************************************************************************
  */
 #include "unicode/utypes.h"
  *******************************************************************************
  */
 #include "unicode/utypes.h"
@@ -20,7 +18,8 @@
 #include "umutex.h"
 
 // see LocaleUtility::getAvailableLocaleNames
 #include "umutex.h"
 
 // see LocaleUtility::getAvailableLocaleNames
-static U_NAMESPACE_QUALIFIER Hashtable * LocaleUtility_cache = NULL;
+static icu::UInitOnce   LocaleUtilityInitOnce = U_INITONCE_INITIALIZER;
+static icu::Hashtable * LocaleUtility_cache = NULL;
 
 #define UNDERSCORE_CHAR ((UChar)0x005f)
 #define AT_SIGN_CHAR    ((UChar)64)
 
 #define UNDERSCORE_CHAR ((UChar)0x005f)
 #define AT_SIGN_CHAR    ((UChar)64)
@@ -41,6 +40,25 @@ static UBool U_CALLCONV service_cleanup(void) {
     }
     return TRUE;
 }
     }
     return TRUE;
 }
+
+
+static void U_CALLCONV locale_utility_init(UErrorCode &status) {
+    using namespace icu;
+    U_ASSERT(LocaleUtility_cache == NULL);
+    ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup);
+    LocaleUtility_cache = new Hashtable(status);
+    if (U_FAILURE(status)) {
+        delete LocaleUtility_cache;
+        LocaleUtility_cache = NULL;
+        return;
+    }
+    if (LocaleUtility_cache == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return;
+    }
+    LocaleUtility_cache->setValueDeleter(uhash_deleteHashtable);
+}
+
 U_CDECL_END
 
 U_NAMESPACE_BEGIN
 U_CDECL_END
 
 U_NAMESPACE_BEGIN
@@ -191,34 +209,13 @@ LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
     // garbage ((void*)1 or other random pointer).
 
     UErrorCode status = U_ZERO_ERROR;
     // garbage ((void*)1 or other random pointer).
 
     UErrorCode status = U_ZERO_ERROR;
-    Hashtable* cache;
-    umtx_lock(NULL);
-    cache = LocaleUtility_cache;
-    umtx_unlock(NULL);
-
+    umtx_initOnce(LocaleUtilityInitOnce, locale_utility_init, status);
+    Hashtable *cache = LocaleUtility_cache;
     if (cache == NULL) {
     if (cache == NULL) {
-        cache = new Hashtable(status);
-        if (cache == NULL || U_FAILURE(status)) {
-            return NULL; // catastrophic failure; e.g. out of memory
-        }
-        cache->setValueDeleter(uhash_deleteHashtable);
-        Hashtable* h; // set this to final LocaleUtility_cache value
-        umtx_lock(NULL);
-        h = LocaleUtility_cache;
-        if (h == NULL) {
-            LocaleUtility_cache = h = cache;
-            cache = NULL;
-            ucln_common_registerCleanup(UCLN_COMMON_SERVICE, service_cleanup);
-        }
-        umtx_unlock(NULL);
-        if(cache != NULL) {
-          delete cache;
-        }
-        cache = h;
+        // Catastrophic failure.
+        return NULL;
     }
 
     }
 
-    U_ASSERT(cache != NULL);
-
     Hashtable* htp;
     umtx_lock(NULL);
     htp = (Hashtable*) cache->get(bundleID);
     Hashtable* htp;
     umtx_lock(NULL);
     htp = (Hashtable*) cache->get(bundleID);
@@ -227,9 +224,9 @@ LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
     if (htp == NULL) {
         htp = new Hashtable(status);
         if (htp && U_SUCCESS(status)) {
     if (htp == NULL) {
         htp = new Hashtable(status);
         if (htp && U_SUCCESS(status)) {
-            CharString cbundleID(bundleID);
-            const char* path = (const char*) cbundleID;
-            if (*path == 0) path = NULL; // empty string => NULL
+            CharString cbundleID;
+            cbundleID.appendInvariantChars(bundleID, status);
+            const char* path = cbundleID.isEmpty() ? NULL : cbundleID.data();
             UEnumeration *uenum = ures_openAvailableLocales(path, &status);
             for (;;) {
                 const UChar* id = uenum_unext(uenum, NULL, &status);
             UEnumeration *uenum = ures_openAvailableLocales(path, &status);
             for (;;) {
                 const UChar* id = uenum_unext(uenum, NULL, &status);
@@ -244,8 +241,17 @@ LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID)
                 return NULL;
             }
             umtx_lock(NULL);
                 return NULL;
             }
             umtx_lock(NULL);
-            cache->put(bundleID, (void*)htp, status);
-            umtx_unlock(NULL);
+            Hashtable *t = static_cast<Hashtable *>(cache->get(bundleID));
+            if (t != NULL) {
+                // Another thread raced through this code, creating the cache entry first.
+                // Discard ours and return theirs.
+                umtx_unlock(NULL);
+                delete htp;
+                htp = t;
+            } else {
+                cache->put(bundleID, (void*)htp, status);
+                umtx_unlock(NULL);
+            }
         }
     }
     return htp;
         }
     }
     return htp;