X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..ef6cf650f4a75c3f97de06b51fa104f2069b9ea2:/icuSources/common/locutil.cpp diff --git a/icuSources/common/locutil.cpp b/icuSources/common/locutil.cpp index 777403d7..e5fe18c4 100644 --- a/icuSources/common/locutil.cpp +++ b/icuSources/common/locutil.cpp @@ -1,9 +1,7 @@ -/** - ******************************************************************************* - * Copyright (C) 2002-2005, 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" @@ -20,7 +18,8 @@ #include "umutex.h" // see LocaleUtility::getAvailableLocaleNames -static 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) @@ -41,6 +40,25 @@ static UBool U_CALLCONV service_cleanup(void) { } 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 @@ -191,34 +209,13 @@ LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) // 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) { - 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); @@ -227,9 +224,9 @@ LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) 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); @@ -244,8 +241,17 @@ LocaleUtility::getAvailableLocaleNames(const UnicodeString& bundleID) return NULL; } umtx_lock(NULL); - cache->put(bundleID, (void*)htp, status); - umtx_unlock(NULL); + Hashtable *t = static_cast(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;