From 978f71fe7801d195ef048fd9e6330cc1757cf2e9 Mon Sep 17 00:00:00 2001 From: Andy Heninger Date: Fri, 31 May 2013 23:50:15 +0000 Subject: [PATCH] ICU-10051 Mutexes: introduce UInitOnce; remove UMTX_CHECK; replace all uses of UMTX_CHECK. X-SVN-Rev: 33787 --- icu4c/source/i18n/buddhcal.cpp | 89 ++---- icu4c/source/i18n/buddhcal.h | 45 +-- icu4c/source/i18n/calendar.cpp | 85 +++-- icu4c/source/i18n/chnsecal.cpp | 97 ++---- icu4c/source/i18n/chnsecal.h | 29 -- icu4c/source/i18n/coll.cpp | 112 +++---- icu4c/source/i18n/coptccal.cpp | 72 ++--- icu4c/source/i18n/coptccal.h | 32 +- icu4c/source/i18n/csdetect.cpp | 147 ++++----- icu4c/source/i18n/dangical.cpp | 67 ++-- icu4c/source/i18n/decfmtst.cpp | 94 +++--- icu4c/source/i18n/decfmtst.h | 15 +- icu4c/source/i18n/decimfmt.cpp | 44 ++- icu4c/source/i18n/ethpccal.cpp | 69 ++-- icu4c/source/i18n/ethpccal.h | 32 +- icu4c/source/i18n/gender.cpp | 54 ++-- icu4c/source/i18n/gregocal.cpp | 95 ++---- icu4c/source/i18n/hebrwcal.cpp | 92 ++---- icu4c/source/i18n/hebrwcal.h | 45 +-- icu4c/source/i18n/i18n.vcxproj | 8 +- icu4c/source/i18n/islamcal.cpp | 92 ++---- icu4c/source/i18n/islamcal.h | 45 +-- icu4c/source/i18n/numfmt.cpp | 120 +++---- icu4c/source/i18n/olsontz.cpp | 28 +- icu4c/source/i18n/olsontz.h | 6 +- icu4c/source/i18n/persncal.cpp | 81 ++--- icu4c/source/i18n/persncal.h | 45 +-- icu4c/source/i18n/rbt.cpp | 7 +- icu4c/source/i18n/rbtz.cpp | 14 +- icu4c/source/i18n/regexst.cpp | 42 +-- icu4c/source/i18n/simpletz.cpp | 25 +- icu4c/source/i18n/smpdtfst.cpp | 75 ++--- icu4c/source/i18n/smpdtfst.h | 7 +- icu4c/source/i18n/taiwncal.cpp | 87 ++--- icu4c/source/i18n/taiwncal.h | 45 +-- icu4c/source/i18n/timezone.cpp | 462 ++++++++++++--------------- icu4c/source/i18n/tzfmt.cpp | 134 ++++---- icu4c/source/i18n/tzgnames.cpp | 38 +-- icu4c/source/i18n/tznames.cpp | 128 ++++---- icu4c/source/i18n/tznames_impl.cpp | 19 +- icu4c/source/i18n/ucol_bld.cpp | 85 +++-- icu4c/source/i18n/ucol_res.cpp | 68 ++-- icu4c/source/i18n/ucurr.cpp | 81 +++-- icu4c/source/i18n/unicode/decimfmt.h | 10 +- icu4c/source/i18n/unicode/gender.h | 5 + icu4c/source/i18n/unicode/gregocal.h | 47 --- icu4c/source/i18n/unicode/timezone.h | 29 +- icu4c/source/i18n/uregex.cpp | 18 +- icu4c/source/i18n/uspoof_impl.h | 2 +- icu4c/source/i18n/zonemeta.cpp | 285 ++++++++--------- icu4c/source/i18n/zonemeta.h | 1 - 51 files changed, 1274 insertions(+), 2180 deletions(-) diff --git a/icu4c/source/i18n/buddhcal.cpp b/icu4c/source/i18n/buddhcal.cpp index d61f68810da..a4fa7b66f1d 100644 --- a/icu4c/source/i18n/buddhcal.cpp +++ b/icu4c/source/i18n/buddhcal.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2003-2012, International Business Machines Corporation and * +* Copyright (C) 2003-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -124,12 +124,14 @@ void BuddhistCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& stat } #endif -// default century -const UDate BuddhistCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t BuddhistCalendar::fgSystemDefaultCenturyYear = -1; - -UDate BuddhistCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t BuddhistCalendar::fgSystemDefaultCenturyStartYear = -1; +/** + * The system maintains a static default century start date. This is initialized + * the first time it is used. Once the system default century date and year + * are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gBCInitOnce; UBool BuddhistCalendar::haveDefaultCentury() const @@ -137,75 +139,40 @@ UBool BuddhistCalendar::haveDefaultCentury() const return TRUE; } -UDate BuddhistCalendar::defaultCenturyStart() const -{ - return internalGetDefaultCenturyStart(); -} - -int32_t BuddhistCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} - -UDate -BuddhistCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -BuddhistCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -BuddhistCalendar::initializeSystemDefaultCentury() +static void U_CALLCONV +initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. UErrorCode status = U_ZERO_ERROR; BuddhistCalendar calendar(Locale("@calendar=buddhist"),status); - if (U_SUCCESS(status)) - { + if (U_SUCCESS(status)) { calendar.setTime(Calendar::getNow(), status); calendar.add(UCAL_YEAR, -80, status); UDate newStart = calendar.getTime(status); int32_t newYear = calendar.get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); + gSystemDefaultCenturyStartYear = newYear; + gSystemDefaultCenturyStart = newStart; } // We have no recourse upon failure unless we want to propagate the failure // out. } +UDate BuddhistCalendar::defaultCenturyStart() const +{ + // lazy-evaluate systemDefaultCenturyStart and systemDefaultCenturyStartYear + umtx_initOnce(gBCInitOnce, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t BuddhistCalendar::defaultCenturyStartYear() const +{ + // lazy-evaluate systemDefaultCenturyStartYear and systemDefaultCenturyStart + umtx_initOnce(gBCInitOnce, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} + U_NAMESPACE_END diff --git a/icu4c/source/i18n/buddhcal.h b/icu4c/source/i18n/buddhcal.h index 735f61890a7..6b6befd39a5 100644 --- a/icu4c/source/i18n/buddhcal.h +++ b/icu4c/source/i18n/buddhcal.h @@ -1,6 +1,6 @@ /* ******************************************************************************** - * Copyright (C) 2003-2007, International Business Machines Corporation + * Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ******************************************************************************** * @@ -189,49 +189,6 @@ private: * @internal */ virtual int32_t defaultCenturyStartYear() const; - - private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates - * with 2-digit years are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with - * 2-digit years are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/calendar.cpp b/icu4c/source/i18n/calendar.cpp index 8cf95671e77..238b4d6c67a 100644 --- a/icu4c/source/i18n/calendar.cpp +++ b/icu4c/source/i18n/calendar.cpp @@ -60,6 +60,7 @@ #if !UCONFIG_NO_SERVICE static icu::ICULocaleService* gService = NULL; +static UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER; #endif // INTERNAL - for cleanup @@ -71,6 +72,7 @@ static UBool calendar_cleanup(void) { delete gService; gService = NULL; } + gServiceInitOnce.reset(); #endif return TRUE; } @@ -517,64 +519,51 @@ CalendarService::~CalendarService() {} static inline UBool isCalendarServiceUsed() { - UBool retVal; - UMTX_CHECK(NULL, gService != NULL, retVal); - return retVal; + return !gServiceInitOnce.isReset(); } // ------------------------------------- +static void U_CALLCONV +initCalendarService(UErrorCode &status) +{ +#ifdef U_DEBUG_CALSVC + fprintf(stderr, "Spinning up Calendar Service\n"); +#endif + ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup); + gService = new CalendarService(); + if (gService == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } +#ifdef U_DEBUG_CALSVC + fprintf(stderr, "Registering classes..\n"); +#endif + + // Register all basic instances. + gService->registerFactory(new BasicCalendarFactory(),status); + +#ifdef U_DEBUG_CALSVC + fprintf(stderr, "Done..\n"); +#endif + + if(U_FAILURE(status)) { +#ifdef U_DEBUG_CALSVC + fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status)); +#endif + delete gService; + gService = NULL; + } +} + static ICULocaleService* getCalendarService(UErrorCode &status) { - UBool needInit; - UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit); - if (needInit) { -#ifdef U_DEBUG_CALSVC - fprintf(stderr, "Spinning up Calendar Service\n"); -#endif - ICULocaleService * newservice = new CalendarService(); - if (newservice == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return newservice; - } -#ifdef U_DEBUG_CALSVC - fprintf(stderr, "Registering classes..\n"); -#endif - - // Register all basic instances. - newservice->registerFactory(new BasicCalendarFactory(),status); - -#ifdef U_DEBUG_CALSVC - fprintf(stderr, "Done..\n"); -#endif - - if(U_FAILURE(status)) { -#ifdef U_DEBUG_CALSVC - fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status)); -#endif - delete newservice; - newservice = NULL; - } - - if (newservice) { - umtx_lock(NULL); - if (gService == NULL) { - gService = newservice; - newservice = NULL; - } - umtx_unlock(NULL); - } - if (newservice) { - delete newservice; - } else { - // we won the contention - we can register the cleanup. - ucln_i18n_registerCleanup(UCLN_I18N_CALENDAR, calendar_cleanup); - } - } + umtx_initOnce(gServiceInitOnce, &initCalendarService, status); return gService; } + URegistryKey Calendar::registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status) { return getCalendarService(status)->registerFactory(toAdopt, status); diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp index 16a3c9a061b..c32b0611c67 100644 --- a/icu4c/source/i18n/chnsecal.cpp +++ b/icu4c/source/i18n/chnsecal.cpp @@ -54,7 +54,7 @@ static icu::CalendarAstronomer *gChineseCalendarAstro = NULL; static icu::CalendarCache *gChineseCalendarWinterSolsticeCache = NULL; static icu::CalendarCache *gChineseCalendarNewYearCache = NULL; static icu::TimeZone *gChineseCalendarZoneAstroCalc = NULL; -static UBool gChineseCalendarZoneAstroCalcInitialized = FALSE; +static UInitOnce gChineseCalendarZoneAstroCalcInitOnce = U_INITONCE_INITIALIZER; /** * The start year of the Chinese calendar, the 61st year of the reign @@ -97,7 +97,7 @@ static UBool calendar_chinese_cleanup(void) { delete gChineseCalendarZoneAstroCalc; gChineseCalendarZoneAstroCalc = NULL; } - gChineseCalendarZoneAstroCalcInitialized = FALSE; + gChineseCalendarZoneAstroCalcInitOnce.reset(); return TRUE; } U_CDECL_END @@ -150,20 +150,13 @@ const char *ChineseCalendar::getType() const { return "chinese"; } +static void U_CALLCONV initChineseCalZoneAstroCalc() { + gChineseCalendarZoneAstroCalc = new SimpleTimeZone(CHINA_OFFSET, UNICODE_STRING_SIMPLE("CHINA_ZONE") ); + ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup); +} + const TimeZone* ChineseCalendar::getChineseCalZoneAstroCalc(void) const { - UBool initialized; - UMTX_CHECK(&astroLock, gChineseCalendarZoneAstroCalcInitialized, initialized); - if (!initialized) { - umtx_lock(&astroLock); - { - if (!gChineseCalendarZoneAstroCalcInitialized) { - gChineseCalendarZoneAstroCalc = new SimpleTimeZone(CHINA_OFFSET, UNICODE_STRING_SIMPLE("CHINA_ZONE") ); - gChineseCalendarZoneAstroCalcInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup); - } - } - umtx_unlock(&astroLock); - } + umtx_initOnce(gChineseCalendarZoneAstroCalcInitOnce, &initChineseCalZoneAstroCalc); return gChineseCalendarZoneAstroCalc; } @@ -842,11 +835,10 @@ ChineseCalendar::inDaylightTime(UErrorCode& status) const } // default century -const UDate ChineseCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t ChineseCalendar::fgSystemDefaultCenturyYear = -1; -UDate ChineseCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t ChineseCalendar::fgSystemDefaultCenturyStartYear = -1; +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInitOnce = U_INITONCE_INITIALIZER; UBool ChineseCalendar::haveDefaultCentury() const @@ -864,66 +856,39 @@ int32_t ChineseCalendar::defaultCenturyStartYear() const return internalGetDefaultCenturyStartYear(); } -UDate -ChineseCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -ChineseCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -ChineseCalendar::initializeSystemDefaultCentury() +static void U_CALLCONV initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. UErrorCode status = U_ZERO_ERROR; ChineseCalendar calendar(Locale("@calendar=chinese"),status); - if (U_SUCCESS(status)) - { + if (U_SUCCESS(status)) { calendar.setTime(Calendar::getNow(), status); calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); } // We have no recourse upon failure unless we want to propagate the failure // out. } +UDate +ChineseCalendar::internalGetDefaultCenturyStart() const +{ + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInitOnce, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t +ChineseCalendar::internalGetDefaultCenturyStartYear() const +{ + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInitOnce, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ChineseCalendar) U_NAMESPACE_END diff --git a/icu4c/source/i18n/chnsecal.h b/icu4c/source/i18n/chnsecal.h index 7d0e2a1fc8a..ac14a679eee 100644 --- a/icu4c/source/i18n/chnsecal.h +++ b/icu4c/source/i18n/chnsecal.h @@ -259,28 +259,6 @@ class U_I18N_API ChineseCalendar : public Calendar { virtual int32_t defaultCenturyStartYear() const; private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; /** * Returns the beginning date of the 100-year window that dates @@ -294,13 +272,6 @@ class U_I18N_API ChineseCalendar : public Calendar { */ int32_t internalGetDefaultCenturyStartYear(void) const; - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); - ChineseCalendar(); // default constructor not implemented }; diff --git a/icu4c/source/i18n/coll.cpp b/icu4c/source/i18n/coll.cpp index 9e9ca0239d0..c12f9d4e2cf 100644 --- a/icu4c/source/i18n/coll.cpp +++ b/icu4c/source/i18n/coll.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** - * Copyright (C) 1996-2012, International Business Machines Corporation and + * Copyright (C) 1996-2013, International Business Machines Corporation and * others. All Rights Reserved. ****************************************************************************** */ @@ -50,6 +50,7 @@ #include "cmemory.h" #include "umutex.h" #include "servloc.h" +#include "uassert.h" #include "ustrenum.h" #include "uresimp.h" #include "ucln_in.h" @@ -57,6 +58,8 @@ static icu::Locale* availableLocaleList = NULL; static int32_t availableLocaleListCount; static icu::ICULocaleService* gService = NULL; +static UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER; +static UInitOnce gAvailableLocaleListInitOnce; /** * Release all static memory held by collator. @@ -68,13 +71,14 @@ static UBool U_CALLCONV collator_cleanup(void) { delete gService; gService = NULL; } + gServiceInitOnce.reset(); #endif if (availableLocaleList) { delete []availableLocaleList; availableLocaleList = NULL; } availableLocaleListCount = 0; - + gAvailableLocaleListInitOnce.reset(); return TRUE; } @@ -199,28 +203,16 @@ ICUCollatorService::~ICUCollatorService() {} // ------------------------------------- +static void U_CALLCONV initService() { + gService = new ICUCollatorService(); + ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); +} + + static ICULocaleService* getService(void) { - UBool needInit; - UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit); - if(needInit) { - ICULocaleService *newservice = new ICUCollatorService(); - if(newservice) { - umtx_lock(NULL); - if(gService == NULL) { - gService = newservice; - newservice = NULL; - } - umtx_unlock(NULL); - } - if(newservice) { - delete newservice; - } - else { - ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); - } - } + umtx_initOnce(gServiceInitOnce, &initService); return gService; } @@ -229,8 +221,7 @@ getService(void) static inline UBool hasService(void) { - UBool retVal; - UMTX_CHECK(NULL, gService != NULL, retVal); + UBool retVal = !gServiceInitOnce.isReset() && (getService() != NULL); return retVal; } @@ -270,57 +261,44 @@ Collator::createUCollator(const char *loc, } #endif /* UCONFIG_NO_SERVICE */ -static UBool isAvailableLocaleListInitialized(UErrorCode &status) { +static void U_CALLCONV +initAvailableLocaleList(UErrorCode &status) { + U_ASSERT(availableLocaleListCount == 0); + U_ASSERT(availableLocaleList == NULL); // for now, there is a hardcoded list, so just walk through that list and set it up. - UBool needInit; - UMTX_CHECK(NULL, availableLocaleList == NULL, needInit); - - if (needInit) { - UResourceBundle *index = NULL; - UResourceBundle installed; - Locale * temp; - int32_t i = 0; - int32_t localeCount; + UResourceBundle *index = NULL; + UResourceBundle installed; + int32_t i = 0; + + ures_initStackObject(&installed); + index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status); + ures_getByKey(index, "InstalledLocales", &installed, &status); + + if(U_SUCCESS(status)) { + availableLocaleListCount = ures_getSize(&installed); + availableLocaleList = new Locale[availableLocaleListCount]; - ures_initStackObject(&installed); - index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status); - ures_getByKey(index, "InstalledLocales", &installed, &status); - - if(U_SUCCESS(status)) { - localeCount = ures_getSize(&installed); - temp = new Locale[localeCount]; - - if (temp != NULL) { - ures_resetIterator(&installed); - while(ures_hasNext(&installed)) { - const char *tempKey = NULL; - ures_getNextString(&installed, NULL, &tempKey, &status); - temp[i++] = Locale(tempKey); - } - - umtx_lock(NULL); - if (availableLocaleList == NULL) - { - availableLocaleListCount = localeCount; - availableLocaleList = temp; - temp = NULL; - ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); - } - umtx_unlock(NULL); - - needInit = FALSE; - if (temp) { - delete []temp; - } + if (availableLocaleList != NULL) { + ures_resetIterator(&installed); + while(ures_hasNext(&installed)) { + const char *tempKey = NULL; + ures_getNextString(&installed, NULL, &tempKey, &status); + availableLocaleList[i++] = Locale(tempKey); } - - ures_close(&installed); } - ures_close(index); + U_ASSERT(availableLocaleListCount == i); + ures_close(&installed); } - return !needInit; + ures_close(index); + ucln_i18n_registerCleanup(UCLN_I18N_COLLATOR, collator_cleanup); } +static UBool isAvailableLocaleListInitialized(UErrorCode &status) { + umtx_initOnce(gAvailableLocaleListInitOnce, &initAvailableLocaleList, status); + return U_SUCCESS(status); +} + + // Collator public methods ----------------------------------------------- Collator* U_EXPORT2 Collator::createInstance(UErrorCode& success) diff --git a/icu4c/source/i18n/coptccal.cpp b/icu4c/source/i18n/coptccal.cpp index 84bbad797ea..9b19e8adbf7 100644 --- a/icu4c/source/i18n/coptccal.cpp +++ b/icu4c/source/i18n/coptccal.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2003 - 2009, International Business Machines Corporation and * +* Copyright (C) 2003 - 2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -94,62 +94,46 @@ CopticCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*status*/) internalSet(UCAL_DAY_OF_YEAR, (30 * month) + day); } -const UDate CopticCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t CopticCalendar::fgSystemDefaultCenturyYear = -1; +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; -UDate CopticCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t CopticCalendar::fgSystemDefaultCenturyStartYear = -1; + +static void U_CALLCONV initializeSystemDefaultCentury() { + UErrorCode status = U_ZERO_ERROR; + CopticCalendar calendar(Locale("@calendar=coptic"), status); + if (U_SUCCESS(status)) { + calendar.setTime(Calendar::getNow(), status); + calendar.add(UCAL_YEAR, -80, status); + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); + } + // We have no recourse upon failure unless we want to propagate the failure + // out. +} UDate CopticCalendar::defaultCenturyStart() const { - initializeSystemDefaultCentury(); - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - return fgSystemDefaultCenturyStart; + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; } int32_t CopticCalendar::defaultCenturyStartYear() const -{ - initializeSystemDefaultCentury(); - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - return fgSystemDefaultCenturyStartYear; -} - -void -CopticCalendar::initializeSystemDefaultCentury() { // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (!needsUpdate) { - return; - } - - UErrorCode status = U_ZERO_ERROR; - - CopticCalendar calendar(Locale("@calendar=coptic"), status); - if (U_SUCCESS(status)) { - calendar.setTime(Calendar::getNow(), status); - calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - { - umtx_lock(NULL); - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - umtx_unlock(NULL); - } - } - // We have no recourse upon failure unless we want to propagate the failure - // out. + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; } + int32_t CopticCalendar::getJDEpochOffset() const { diff --git a/icu4c/source/i18n/coptccal.h b/icu4c/source/i18n/coptccal.h index f42230dff4c..5d2e306c632 100644 --- a/icu4c/source/i18n/coptccal.h +++ b/icu4c/source/i18n/coptccal.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2003 - 2008, International Business Machines Corporation and * +* Copyright (C) 2003 - 2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -188,36 +188,6 @@ protected: */ virtual int32_t getJDEpochOffset() const; -private: - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); public: /** diff --git a/icu4c/source/i18n/csdetect.cpp b/icu4c/source/i18n/csdetect.cpp index 3ad7136f878..415c85421db 100644 --- a/icu4c/source/i18n/csdetect.cpp +++ b/icu4c/source/i18n/csdetect.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) 2005-2012, International Business Machines + * Copyright (C) 2005-2013, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -32,13 +32,14 @@ #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type)) #define DELETE_ARRAY(array) uprv_free((void *) (array)) -U_CDECL_BEGIN static icu::CharsetRecognizer **fCSRecognizers = NULL; - +static UInitOnce gCSRecognizersInitOnce; static int32_t fCSRecognizers_size = 0; +U_CDECL_BEGIN static UBool U_CALLCONV csdet_cleanup(void) { + U_NAMESPACE_USE if (fCSRecognizers != NULL) { for(int32_t r = 0; r < fCSRecognizers_size; r += 1) { delete fCSRecognizers[r]; @@ -49,6 +50,7 @@ static UBool U_CALLCONV csdet_cleanup(void) fCSRecognizers = NULL; fCSRecognizers_size = 0; } + gCSRecognizersInitOnce.reset(); return TRUE; } @@ -65,96 +67,67 @@ charsetMatchComparator(const void * /*context*/, const void *left, const void *r return (*csm_r)->getConfidence() - (*csm_l)->getConfidence(); } +static void U_CALLCONV initRecognizers(UErrorCode &status) { + U_NAMESPACE_USE + ucln_i18n_registerCleanup(UCLN_I18N_CSDET, csdet_cleanup); + CharsetRecognizer *tempArray[] = { + new CharsetRecog_UTF8(), + + new CharsetRecog_UTF_16_BE(), + new CharsetRecog_UTF_16_LE(), + new CharsetRecog_UTF_32_BE(), + new CharsetRecog_UTF_32_LE(), + + new CharsetRecog_8859_1(), + new CharsetRecog_8859_2(), + new CharsetRecog_8859_5_ru(), + new CharsetRecog_8859_6_ar(), + new CharsetRecog_8859_7_el(), + new CharsetRecog_8859_8_I_he(), + new CharsetRecog_8859_8_he(), + new CharsetRecog_windows_1251(), + new CharsetRecog_windows_1256(), + new CharsetRecog_KOI8_R(), + new CharsetRecog_8859_9_tr(), + new CharsetRecog_sjis(), + new CharsetRecog_gb_18030(), + new CharsetRecog_euc_jp(), + new CharsetRecog_euc_kr(), + new CharsetRecog_big5(), + + new CharsetRecog_2022JP(), + new CharsetRecog_2022KR(), + new CharsetRecog_2022CN(), + + new CharsetRecog_IBM424_he_rtl(), + new CharsetRecog_IBM424_he_ltr(), + new CharsetRecog_IBM420_ar_rtl(), + new CharsetRecog_IBM420_ar_ltr() + }; + int32_t rCount = ARRAY_SIZE(tempArray); + + fCSRecognizers = NEW_ARRAY(CharsetRecognizer *, rCount); + + if (fCSRecognizers == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + fCSRecognizers_size = rCount; + for (int32_t r = 0; r < rCount; r += 1) { + fCSRecognizers[r] = tempArray[r]; + if (fCSRecognizers[r] == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } + } + } +} + U_CDECL_END U_NAMESPACE_BEGIN void CharsetDetector::setRecognizers(UErrorCode &status) { - UBool needsInit; - CharsetRecognizer **recognizers; - - if (U_FAILURE(status)) { - return; - } - - UMTX_CHECK(NULL, (UBool) (fCSRecognizers == NULL), needsInit); - - if (needsInit) { - CharsetRecognizer *tempArray[] = { - new CharsetRecog_UTF8(), - - new CharsetRecog_UTF_16_BE(), - new CharsetRecog_UTF_16_LE(), - new CharsetRecog_UTF_32_BE(), - new CharsetRecog_UTF_32_LE(), - - new CharsetRecog_8859_1(), - new CharsetRecog_8859_2(), - new CharsetRecog_8859_5_ru(), - new CharsetRecog_8859_6_ar(), - new CharsetRecog_8859_7_el(), - new CharsetRecog_8859_8_I_he(), - new CharsetRecog_8859_8_he(), - new CharsetRecog_windows_1251(), - new CharsetRecog_windows_1256(), - new CharsetRecog_KOI8_R(), - new CharsetRecog_8859_9_tr(), - new CharsetRecog_sjis(), - new CharsetRecog_gb_18030(), - new CharsetRecog_euc_jp(), - new CharsetRecog_euc_kr(), - new CharsetRecog_big5(), - - new CharsetRecog_2022JP(), - new CharsetRecog_2022KR(), - new CharsetRecog_2022CN(), - - new CharsetRecog_IBM424_he_rtl(), - new CharsetRecog_IBM424_he_ltr(), - new CharsetRecog_IBM420_ar_rtl(), - new CharsetRecog_IBM420_ar_ltr() - }; - int32_t rCount = ARRAY_SIZE(tempArray); - int32_t r; - - recognizers = NEW_ARRAY(CharsetRecognizer *, rCount); - - if (recognizers == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } else { - for (r = 0; r < rCount; r += 1) { - recognizers[r] = tempArray[r]; - - if (recognizers[r] == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - break; - } - } - } - - if (U_SUCCESS(status)) { - umtx_lock(NULL); - if (fCSRecognizers == NULL) { - fCSRecognizers_size = rCount; - fCSRecognizers = recognizers; - } - umtx_unlock(NULL); - } - - if (fCSRecognizers != recognizers) { - for (r = 0; r < rCount; r += 1) { - delete recognizers[r]; - recognizers[r] = NULL; - } - - DELETE_ARRAY(recognizers); - } - - recognizers = NULL; - ucln_i18n_registerCleanup(UCLN_I18N_CSDET, csdet_cleanup); - } + umtx_initOnce(gCSRecognizersInitOnce, &initRecognizers, status); } CharsetDetector::CharsetDetector(UErrorCode &status) diff --git a/icu4c/source/i18n/dangical.cpp b/icu4c/source/i18n/dangical.cpp index 489821baf60..94e1458b8d0 100644 --- a/icu4c/source/i18n/dangical.cpp +++ b/icu4c/source/i18n/dangical.cpp @@ -13,16 +13,16 @@ #if !UCONFIG_NO_FORMATTING -#include "umutex.h" #include "gregoimp.h" // Math +#include "uassert.h" +#include "ucln_in.h" +#include "umutex.h" #include "unicode/rbtz.h" #include "unicode/tzrule.h" -#include "ucln_in.h" // --- The cache -- -static UMutex dangiLock = U_MUTEX_INITIALIZER; static icu::TimeZone *gDangiCalendarZoneAstroCalc = NULL; -static UBool gDangiCalendarZoneAstroCalcInitialized = FALSE; +static UInitOnce gDangiCalendarInitOnce = U_INITONCE_INITIALIZER; /** * The start year of the Korean traditional calendar (Dan-gi) is the inaugural @@ -36,7 +36,7 @@ static UBool calendar_dangi_cleanup(void) { delete gDangiCalendarZoneAstroCalc; gDangiCalendarZoneAstroCalc = NULL; } - gDangiCalendarZoneAstroCalcInitialized = FALSE; + gDangiCalendarInitOnce.reset(); return TRUE; } U_CDECL_END @@ -101,41 +101,36 @@ const char *DangiCalendar::getType() const { * 1898-1911: GMT+8 * 1912- : GMT+9 */ -const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(void) const { - UBool initialized; - UMTX_CHECK(&dangiLock, gDangiCalendarZoneAstroCalcInitialized, initialized); - if (!initialized) { - umtx_lock(&dangiLock); - { - if (!gDangiCalendarZoneAstroCalcInitialized) { - const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here - const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here - const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20 - InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UNICODE_STRING_SIMPLE("GMT+8"), 8*kOneHour, 0); - TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME); - TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME); - TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME); - UErrorCode status = U_ZERO_ERROR; - RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UNICODE_STRING_SIMPLE("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone - dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897 - dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status); - dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status); - dangiCalZoneAstroCalc->complete(status); - if (U_SUCCESS(status)) { - gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc; - } else { - delete dangiCalZoneAstroCalc; - gDangiCalendarZoneAstroCalc = NULL; - } - gDangiCalendarZoneAstroCalcInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup); - } - } - umtx_unlock(&dangiLock); +static void U_CALLCONV initDangiCalZoneAstroCalc(void) { + U_ASSERT(gDangiCalendarZoneAstroCalc == NULL); + const UDate millis1897[] = { (UDate)((1897 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here + const UDate millis1898[] = { (UDate)((1898 - 1970) * 365 * kOneDay) }; // some days of error is not a problem here + const UDate millis1912[] = { (UDate)((1912 - 1970) * 365 * kOneDay) }; // this doesn't create an issue for 1911/12/20 + InitialTimeZoneRule* initialTimeZone = new InitialTimeZoneRule(UNICODE_STRING_SIMPLE("GMT+8"), 8*kOneHour, 0); + TimeZoneRule* rule1897 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1897"), 7*kOneHour, 0, millis1897, 1, DateTimeRule::STANDARD_TIME); + TimeZoneRule* rule1898to1911 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1898-1911"), 8*kOneHour, 0, millis1898, 1, DateTimeRule::STANDARD_TIME); + TimeZoneRule* ruleFrom1912 = new TimeArrayTimeZoneRule(UNICODE_STRING_SIMPLE("Korean 1912-"), 9*kOneHour, 0, millis1912, 1, DateTimeRule::STANDARD_TIME); + UErrorCode status = U_ZERO_ERROR; + RuleBasedTimeZone* dangiCalZoneAstroCalc = new RuleBasedTimeZone(UNICODE_STRING_SIMPLE("KOREA_ZONE"), initialTimeZone); // adopts initialTimeZone + dangiCalZoneAstroCalc->addTransitionRule(rule1897, status); // adopts rule1897 + dangiCalZoneAstroCalc->addTransitionRule(rule1898to1911, status); + dangiCalZoneAstroCalc->addTransitionRule(ruleFrom1912, status); + dangiCalZoneAstroCalc->complete(status); + if (U_SUCCESS(status)) { + gDangiCalendarZoneAstroCalc = dangiCalZoneAstroCalc; + } else { + delete dangiCalZoneAstroCalc; + gDangiCalendarZoneAstroCalc = NULL; } + ucln_i18n_registerCleanup(UCLN_I18N_DANGI_CALENDAR, calendar_dangi_cleanup); +} + +const TimeZone* DangiCalendar::getDangiCalZoneAstroCalc(void) const { + umtx_initOnce(gDangiCalendarInitOnce, &initDangiCalZoneAstroCalc); return gDangiCalendarZoneAstroCalc; } + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DangiCalendar) U_NAMESPACE_END diff --git a/icu4c/source/i18n/decfmtst.cpp b/icu4c/source/i18n/decfmtst.cpp index c991c0098e0..c9df897e1a4 100644 --- a/icu4c/source/i18n/decfmtst.cpp +++ b/icu4c/source/i18n/decfmtst.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2009-2011, International Business Machines Corporation and * +* Copyright (C) 2009-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -70,9 +70,7 @@ static const UChar gStrictDashEquivalentsPattern[] = { 0x005B, 0x005C, 0x002D, 0x2212, 0x005D, 0x0000}; -DecimalFormatStaticSets *DecimalFormatStaticSets::gStaticSets = NULL; - -DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode *status) +DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode &status) : fDotEquivalents(NULL), fCommaEquivalents(NULL), fOtherGroupingSeparators(NULL), @@ -84,15 +82,15 @@ DecimalFormatStaticSets::DecimalFormatStaticSets(UErrorCode *status) fDefaultGroupingSeparators(NULL), fStrictDefaultGroupingSeparators(NULL) { - fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), *status); - fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), *status); - fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), *status); - fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), *status); + fDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gDotEquivalentsPattern, -1), status); + fCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gCommaEquivalentsPattern, -1), status); + fOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gOtherGroupingSeparatorsPattern, -1), status); + fDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gDashEquivalentsPattern, -1), status); - fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), *status); - fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), *status); - fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), *status); - fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), *status); + fStrictDotEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDotEquivalentsPattern, -1), status); + fStrictCommaEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictCommaEquivalentsPattern, -1), status); + fStrictOtherGroupingSeparators = new UnicodeSet(UnicodeString(TRUE, gStrictOtherGroupingSeparatorsPattern, -1), status); + fStrictDashEquivalents = new UnicodeSet(UnicodeString(TRUE, gStrictDashEquivalentsPattern, -1), status); fDefaultGroupingSeparators = new UnicodeSet(*fDotEquivalents); @@ -137,7 +135,7 @@ ExitConstrDeleteAll: // Remove fPropSets and fRuleSets and return error delete fStrictDefaultGroupingSeparators; fStrictDefaultGroupingSeparators = NULL; delete fStrictOtherGroupingSeparators; fStrictOtherGroupingSeparators = NULL; - *status = U_MEMORY_ALLOCATION_ERROR; + status = U_MEMORY_ALLOCATION_ERROR; } @@ -156,68 +154,50 @@ DecimalFormatStaticSets::~DecimalFormatStaticSets() { } +static DecimalFormatStaticSets *gStaticSets; +static UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER; + + //------------------------------------------------------------------------------ // // decfmt_cleanup Memory cleanup function, free/delete all // cached memory. Called by ICU's u_cleanup() function. // //------------------------------------------------------------------------------ -UBool -DecimalFormatStaticSets::cleanup(void) -{ - delete DecimalFormatStaticSets::gStaticSets; - DecimalFormatStaticSets::gStaticSets = NULL; - - return TRUE; -} - U_CDECL_BEGIN static UBool U_CALLCONV decimfmt_cleanup(void) { - return DecimalFormatStaticSets::cleanup(); + delete gStaticSets; + gStaticSets = NULL; + gStaticSetsInitOnce.reset(); + return TRUE; +} + +static void U_CALLCONV initSets(UErrorCode &status) { + ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup); + gStaticSets = new DecimalFormatStaticSets(status); + if (U_FAILURE(status)) { + delete gStaticSets; + gStaticSets = NULL; + return; + } + if (gStaticSets == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } } U_CDECL_END -void DecimalFormatStaticSets::initSets(UErrorCode *status) -{ - DecimalFormatStaticSets *p; - - UMTX_CHECK(NULL, gStaticSets, p); - if (p == NULL) { - p = new DecimalFormatStaticSets(status); - - if (p == NULL) { - *status = U_MEMORY_ALLOCATION_ERROR; - return; - } - - if (U_FAILURE(*status)) { - delete p; - return; - } - - umtx_lock(NULL); - if (gStaticSets == NULL) { - gStaticSets = p; - p = NULL; - } - - umtx_unlock(NULL); - if (p != NULL) { - delete p; - } - - ucln_i18n_registerCleanup(UCLN_I18N_DECFMT, decimfmt_cleanup); - } +const DecimalFormatStaticSets *DecimalFormatStaticSets::getStaticSets(UErrorCode &status) { + umtx_initOnce(gStaticSetsInitOnce, initSets, status); + return gStaticSets; } + const UnicodeSet *DecimalFormatStaticSets::getSimilarDecimals(UChar32 decimal, UBool strictParse) { UErrorCode status = U_ZERO_ERROR; - - initSets(&status); - + umtx_initOnce(gStaticSetsInitOnce, initSets, status); if (U_FAILURE(status)) { return NULL; } diff --git a/icu4c/source/i18n/decfmtst.h b/icu4c/source/i18n/decfmtst.h index 16c5b7c950e..e3208421d61 100644 --- a/icu4c/source/i18n/decfmtst.h +++ b/icu4c/source/i18n/decfmtst.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2009-2011, International Business Machines Corporation and * +* Copyright (C) 2009-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -26,14 +26,15 @@ class UnicodeSet; class DecimalFormatStaticSets : public UMemory { public: - static DecimalFormatStaticSets *gStaticSets; // Ptr to all lazily initialized constant - // shared sets. - - DecimalFormatStaticSets(UErrorCode *status); + // Constructor and Destructor not for general use. + // Public to permit access from plain C implementation functions. + DecimalFormatStaticSets(UErrorCode &status); ~DecimalFormatStaticSets(); - static void initSets(UErrorCode *status); - static UBool cleanup(); + /** + * Return a pointer to a lazy-initialized singleton instance of this class. + */ + static const DecimalFormatStaticSets *getStaticSets(UErrorCode &status); static const UnicodeSet *getSimilarDecimals(UChar32 decimal, UBool strictParse); diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index e1499478bef..cf8f2a8ed5b 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -269,7 +269,7 @@ inline int32_t _max(int32_t a, int32_t b) { return (afStrictDefaultGroupingSeparators; + groupingSet = fStaticSets->fStrictDefaultGroupingSeparators; } else { - groupingSet = DecimalFormatStaticSets::gStaticSets->fDefaultGroupingSeparators; + groupingSet = fStaticSets->fDefaultGroupingSeparators; } } @@ -2837,9 +2842,14 @@ int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, int32_t inputLength = input.length(); int32_t affixCharLength = U16_LENGTH(affixChar); UnicodeSet *affixSet; + UErrorCode status = U_ZERO_ERROR; + const DecimalFormatStaticSets *staticSets = DecimalFormatStaticSets::getStaticSets(status); + if (U_FAILURE(status)) { + return -1; + } if (!lenient) { - affixSet = DecimalFormatStaticSets::gStaticSets->fStrictDashEquivalents; + affixSet = staticSets->fStrictDashEquivalents; // If the affix is exactly one character long and that character // is in the dash set and the very next input character is also @@ -2905,7 +2915,7 @@ int32_t DecimalFormat::compareSimpleAffix(const UnicodeString& affix, } else { UBool match = FALSE; - affixSet = DecimalFormatStaticSets::gStaticSets->fDashEquivalents; + affixSet = staticSets->fDashEquivalents; if (affixCharLength == affixLength && affixSet->contains(affixChar)) { pos = skipUWhiteSpace(input, pos); diff --git a/icu4c/source/i18n/ethpccal.cpp b/icu4c/source/i18n/ethpccal.cpp index 9317dead0ae..dd386025c64 100644 --- a/icu4c/source/i18n/ethpccal.cpp +++ b/icu4c/source/i18n/ethpccal.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2003 - 2009, International Business Machines Corporation and * +* Copyright (C) 2003 - 2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -134,58 +134,49 @@ EthiopicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType return CECalendar::handleGetLimit(field, limitType); } -const UDate EthiopicCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t EthiopicCalendar::fgSystemDefaultCenturyYear = -1; +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; -UDate EthiopicCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t EthiopicCalendar::fgSystemDefaultCenturyStartYear = -1; +static void U_CALLCONV initializeSystemDefaultCentury() +{ + UErrorCode status = U_ZERO_ERROR; + EthiopicCalendar calendar(Locale("@calendar=ethiopic"), status); + if (U_SUCCESS(status)) { + calendar.setTime(Calendar::getNow(), status); + calendar.add(UCAL_YEAR, -80, status); + + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); + } + // We have no recourse upon failure unless we want to propagate the failure + // out. +} UDate EthiopicCalendar::defaultCenturyStart() const { - initializeSystemDefaultCentury(); - return fgSystemDefaultCenturyStart; + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; } int32_t EthiopicCalendar::defaultCenturyStartYear() const { - initializeSystemDefaultCentury(); + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); if (isAmeteAlemEra()) { - return fgSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA; + return gSystemDefaultCenturyStartYear + AMETE_MIHRET_DELTA; } - return fgSystemDefaultCenturyStartYear; + return gSystemDefaultCenturyStartYear; } -void -EthiopicCalendar::initializeSystemDefaultCentury() -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (!needsUpdate) { - return; - } - - UErrorCode status = U_ZERO_ERROR; - - EthiopicCalendar calendar(Locale("@calendar=ethiopic"), status); - if (U_SUCCESS(status)) { - calendar.setTime(Calendar::getNow(), status); - calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - { - umtx_lock(NULL); - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - umtx_unlock(NULL); - } - } - // We have no recourse upon failure unless we want to propagate the failure - // out. -} int32_t EthiopicCalendar::getJDEpochOffset() const diff --git a/icu4c/source/i18n/ethpccal.h b/icu4c/source/i18n/ethpccal.h index 01db826a79f..6aba6828f20 100644 --- a/icu4c/source/i18n/ethpccal.h +++ b/icu4c/source/i18n/ethpccal.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2003 - 2008, International Business Machines Corporation and * +* Copyright (C) 2003 - 2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -205,36 +205,6 @@ protected: virtual int32_t getJDEpochOffset() const; private: - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); - /** * When eraType is AMETE_ALEM_ERA, then this calendar use only AMETE_ALEM * for the era. Otherwise (default), this calendar uses both AMETE_ALEM diff --git a/icu4c/source/i18n/gender.cpp b/icu4c/source/i18n/gender.cpp index 4eac9e17740..8e6e0d15bfd 100644 --- a/icu4c/source/i18n/gender.cpp +++ b/icu4c/source/i18n/gender.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2008-2012, International Business Machines Corporation and +* Copyright (C) 2008-2013, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * @@ -24,6 +24,7 @@ #include "cmemory.h" #include "cstring.h" #include "mutex.h" +#include "uassert.h" #include "ucln_in.h" #include "umutex.h" #include "uhash.h" @@ -34,6 +35,7 @@ static const char* gNeutralStr = "neutral"; static const char* gMailTaintsStr = "maleTaints"; static const char* gMixedNeutralStr = "mixedNeutral"; static icu::GenderInfo* gObjs = NULL; +static UInitOnce gGenderInitOnce = U_INITONCE_INITIALIZER; enum GenderStyle { NEUTRAL, @@ -50,6 +52,7 @@ static UBool U_CALLCONV gender_cleanup(void) { gGenderInfoCache = NULL; delete [] gObjs; } + gGenderInitOnce.reset(); return TRUE; } @@ -57,6 +60,29 @@ U_CDECL_END U_NAMESPACE_BEGIN +void U_CALLCONV GenderInfo_initCache(UErrorCode &status) { + ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO, gender_cleanup); + U_ASSERT(gGenderInfoCache == NULL); + if (U_FAILURE(status)) { + return; + } + gObjs = new GenderInfo[GENDER_STYLE_LENGTH]; + if (gObjs == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + for (int i = 0; i < GENDER_STYLE_LENGTH; i++) { + gObjs[i]._style = i; + } + gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); + if (U_FAILURE(status)) { + delete [] gObjs; + return; + } + uhash_setKeyDeleter(gGenderInfoCache, uprv_free); +} + + GenderInfo::GenderInfo() { } @@ -64,34 +90,12 @@ GenderInfo::~GenderInfo() { } const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& status) { + // Make sure our cache exists. + umtx_initOnce(gGenderInitOnce, &GenderInfo_initCache, status); if (U_FAILURE(status)) { return NULL; } - // Make sure our cache exists. - UBool needed; - UMTX_CHECK(&gGenderMetaLock, (gGenderInfoCache == NULL), needed); - if (needed) { - Mutex lock(&gGenderMetaLock); - if (gGenderInfoCache == NULL) { - gObjs = new GenderInfo[GENDER_STYLE_LENGTH]; - if (gObjs == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - for (int i = 0; i < GENDER_STYLE_LENGTH; i++) { - gObjs[i]._style = i; - } - gGenderInfoCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); - if (U_FAILURE(status)) { - delete [] gObjs; - return NULL; - } - uhash_setKeyDeleter(gGenderInfoCache, uprv_free); - ucln_i18n_registerCleanup(UCLN_I18N_GENDERINFO, gender_cleanup); - } - } - const GenderInfo* result = NULL; const char* key = locale.getName(); { diff --git a/icu4c/source/i18n/gregocal.cpp b/icu4c/source/i18n/gregocal.cpp index c2a635a87d1..9e00b4266b9 100644 --- a/icu4c/source/i18n/gregocal.cpp +++ b/icu4c/source/i18n/gregocal.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2012, International Business Machines Corporation and * +* Copyright (C) 1997-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -1264,11 +1264,14 @@ GregorianCalendar::getType() const { return "gregorian"; } -const UDate GregorianCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t GregorianCalendar::fgSystemDefaultCenturyYear = -1; - -UDate GregorianCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t GregorianCalendar::fgSystemDefaultCenturyStartYear = -1; +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; UBool GregorianCalendar::haveDefaultCentury() const @@ -1276,78 +1279,36 @@ UBool GregorianCalendar::haveDefaultCentury() const return TRUE; } -UDate GregorianCalendar::defaultCenturyStart() const -{ - return internalGetDefaultCenturyStart(); -} - -int32_t GregorianCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} - -UDate -GregorianCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -GregorianCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -GregorianCalendar::initializeSystemDefaultCentury() +static void U_CALLCONV +initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. UErrorCode status = U_ZERO_ERROR; - Calendar *calendar = new GregorianCalendar(status); - if (calendar != NULL && U_SUCCESS(status)) - { - calendar->setTime(Calendar::getNow(), status); - calendar->add(UCAL_YEAR, -80, status); + GregorianCalendar calendar(status); + if (U_SUCCESS(status)) { + calendar.setTime(Calendar::getNow(), status); + calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar->getTime(status); - int32_t newYear = calendar->get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); - delete calendar; + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); } // We have no recourse upon failure unless we want to propagate the failure // out. } +UDate GregorianCalendar::defaultCenturyStart() const { + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t GregorianCalendar::defaultCenturyStartYear() const { + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} U_NAMESPACE_END diff --git a/icu4c/source/i18n/hebrwcal.cpp b/icu4c/source/i18n/hebrwcal.cpp index 12e850a593b..cdd76953830 100644 --- a/icu4c/source/i18n/hebrwcal.cpp +++ b/icu4c/source/i18n/hebrwcal.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 2003-2011, International Business Machines Corporation +* Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -668,88 +668,52 @@ HebrewCalendar::inDaylightTime(UErrorCode& status) const return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE); } -// default century -const UDate HebrewCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t HebrewCalendar::fgSystemDefaultCenturyYear = -1; - -UDate HebrewCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t HebrewCalendar::fgSystemDefaultCenturyStartYear = -1; - +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; UBool HebrewCalendar::haveDefaultCentury() const { return TRUE; } -UDate HebrewCalendar::defaultCenturyStart() const -{ - return internalGetDefaultCenturyStart(); -} - -int32_t HebrewCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} - -UDate -HebrewCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -HebrewCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -HebrewCalendar::initializeSystemDefaultCentury() +static void U_CALLCONV initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. UErrorCode status = U_ZERO_ERROR; HebrewCalendar calendar(Locale("@calendar=hebrew"),status); - if (U_SUCCESS(status)) - { + if (U_SUCCESS(status)) { calendar.setTime(Calendar::getNow(), status); calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); + + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); } // We have no recourse upon failure unless we want to propagate the failure // out. } + +UDate HebrewCalendar::defaultCenturyStart() const { + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t HebrewCalendar::defaultCenturyStartYear() const { + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} + + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar) U_NAMESPACE_END diff --git a/icu4c/source/i18n/hebrwcal.h b/icu4c/source/i18n/hebrwcal.h index 76f100fea95..50c86364634 100644 --- a/icu4c/source/i18n/hebrwcal.h +++ b/icu4c/source/i18n/hebrwcal.h @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 2003-2009, International Business Machines Corporation +* Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -395,49 +395,6 @@ public: */ virtual int32_t defaultCenturyStartYear() const; - private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates - * with 2-digit years are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with - * 2-digit years are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); - private: // Calendar-specific implementation /** * Finds the day # of the first day in the given Hebrew year. diff --git a/icu4c/source/i18n/i18n.vcxproj b/icu4c/source/i18n/i18n.vcxproj index 020fcf96218..0b3598e8f21 100644 --- a/icu4c/source/i18n/i18n.vcxproj +++ b/icu4c/source/i18n/i18n.vcxproj @@ -91,7 +91,7 @@ true MultiThreadedDLL true - true + false true .\x86\Release/i18n.pch .\x86\Release/ @@ -133,7 +133,7 @@ EnableFastChecks MultiThreadedDebugDLL true - true + false true .\x86\Debug/i18n.pch .\x86\Debug/ @@ -176,7 +176,7 @@ true MultiThreadedDLL true - true + false true .\x64\Release/i18n.pch .\x64\Release/ @@ -216,7 +216,7 @@ EnableFastChecks MultiThreadedDebugDLL true - true + false true .\x64\Debug/i18n.pch .\x64\Debug/ diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp index 6d553787da3..ea8e1013a21 100644 --- a/icu4c/source/i18n/islamcal.cpp +++ b/icu4c/source/i18n/islamcal.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 2003-2012, International Business Machines Corporation +* Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -457,89 +457,51 @@ IslamicCalendar::inDaylightTime(UErrorCode& status) const return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE); } -// default century -const UDate IslamicCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t IslamicCalendar::fgSystemDefaultCenturyYear = -1; - -UDate IslamicCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t IslamicCalendar::fgSystemDefaultCenturyStartYear = -1; - +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; UBool IslamicCalendar::haveDefaultCentury() const { return TRUE; } -UDate IslamicCalendar::defaultCenturyStart() const -{ - return internalGetDefaultCenturyStart(); -} - -int32_t IslamicCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} - -UDate -IslamicCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -IslamicCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -IslamicCalendar::initializeSystemDefaultCentury() +static void U_CALLCONV initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. UErrorCode status = U_ZERO_ERROR; IslamicCalendar calendar(Locale("@calendar=islamic-civil"),status); - if (U_SUCCESS(status)) - { + if (U_SUCCESS(status)) { calendar.setTime(Calendar::getNow(), status); calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); + + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); } // We have no recourse upon failure unless we want to propagate the failure // out. } +UDate IslamicCalendar::defaultCenturyStart() const { + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t IslamicCalendar::defaultCenturyStartYear() const { + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} + + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar) U_NAMESPACE_END diff --git a/icu4c/source/i18n/islamcal.h b/icu4c/source/i18n/islamcal.h index e3647bc0ffd..b9c964cfadf 100644 --- a/icu4c/source/i18n/islamcal.h +++ b/icu4c/source/i18n/islamcal.h @@ -1,6 +1,6 @@ /* ******************************************************************************** - * Copyright (C) 2003-2009, International Business Machines Corporation + * Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -409,49 +409,6 @@ class IslamicCalendar : public Calendar { * @internal */ virtual int32_t defaultCenturyStartYear() const; - - private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates - * with 2-digit years are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with - * 2-digit years are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index 8c08c1742e5..922bc2fffa6 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 1997-2012, International Business Machines Corporation and * +* Copyright (C) 1997-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -45,6 +45,7 @@ #include "ucln_in.h" #include "cstring.h" #include "putilimp.h" +#include "uassert.h" #include "umutex.h" #include "mutex.h" #include "digitlst.h" @@ -138,11 +139,12 @@ static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = { // Static hashtable cache of NumberingSystem objects used by NumberFormat static UHashtable * NumberingSystem_cache = NULL; - static UMutex nscacheMutex = U_MUTEX_INITIALIZER; +static UInitOnce gNSCacheInitOnce = U_INITONCE_INITIALIZER; #if !UCONFIG_NO_SERVICE static icu::ICULocaleService* gService = NULL; +static UInitOnce gServiceInitOnce = U_INITONCE_INITIALIZER; #endif /** @@ -156,11 +158,13 @@ deleteNumberingSystem(void *obj) { static UBool U_CALLCONV numfmt_cleanup(void) { #if !UCONFIG_NO_SERVICE + gServiceInitOnce.reset(); if (gService) { delete gService; gService = NULL; } #endif + gNSCacheInitOnce.reset(); if (NumberingSystem_cache) { // delete NumberingSystem_cache; uhash_close(NumberingSystem_cache); @@ -902,31 +906,23 @@ ICUNumberFormatService::~ICUNumberFormatService() {} // ------------------------------------- +static void U_CALLCONV initNumberFormatService() { + U_ASSERT(gService == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); + gService = new ICUNumberFormatService(); +} + static ICULocaleService* getNumberFormatService(void) { - UBool needInit; - UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit); - if (needInit) { - ICULocaleService * newservice = new ICUNumberFormatService(); - if (newservice) { - umtx_lock(NULL); - if (gService == NULL) { - gService = newservice; - newservice = NULL; - } - umtx_unlock(NULL); - } - if (newservice) { - delete newservice; - } else { - // we won the contention, this thread can register cleanup. - ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); - } - } + umtx_initOnce(gServiceInitOnce, &initNumberFormatService); return gService; } +static UBool haveService() { + return !gServiceInitOnce.isReset() && (getNumberFormatService() != NULL); +} + // ------------------------------------- URegistryKey U_EXPORT2 @@ -948,15 +944,15 @@ NumberFormat::registerFactory(NumberFormatFactory* toAdopt, UErrorCode& status) UBool U_EXPORT2 NumberFormat::unregister(URegistryKey key, UErrorCode& status) { - if (U_SUCCESS(status)) { - UBool haveService; - UMTX_CHECK(NULL, gService != NULL, haveService); - if (haveService) { - return gService->unregister(key, status); - } - status = U_ILLEGAL_ARGUMENT_ERROR; + if (U_FAILURE(status)) { + return FALSE; + } + if (haveService()) { + return gService->unregister(key, status); + } else { + status = U_ILLEGAL_ARGUMENT_ERROR; + return FALSE; } - return FALSE; } // ------------------------------------- @@ -965,7 +961,7 @@ NumberFormat::getAvailableLocales(void) { ICULocaleService *service = getNumberFormatService(); if (service) { - return service->getAvailableLocales(); + return service->getAvailableLocales(); } return NULL; // no way to return error condition } @@ -973,19 +969,13 @@ NumberFormat::getAvailableLocales(void) // ------------------------------------- NumberFormat* U_EXPORT2 -NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) -{ +NumberFormat::createInstance(const Locale& loc, UNumberFormatStyle kind, UErrorCode& status) { #if !UCONFIG_NO_SERVICE - UBool haveService; - UMTX_CHECK(NULL, gService != NULL, haveService); - if (haveService) { + if (haveService()) { return (NumberFormat*)gService->get(loc, kind, status); } - else #endif - { - return makeInstance(loc, kind, status); - } + return makeInstance(loc, kind, status); } @@ -1132,6 +1122,22 @@ void NumberFormat::getEffectiveCurrency(UChar* result, UErrorCode& ec) const { // Creates the NumberFormat instance of the specified style (number, currency, // or percent) for the desired locale. +static void U_CALLCONV nscacheInit() { + U_ASSERT(NumberingSystem_cache == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); + UErrorCode status = U_ZERO_ERROR; + NumberingSystem_cache = uhash_open(uhash_hashLong, + uhash_compareLong, + NULL, + &status); + if (U_FAILURE(status)) { + // Number Format code will run with no cache if creation fails. + NumberingSystem_cache = NULL; + return; + } + uhash_setValueDeleter(NumberingSystem_cache, deleteNumberingSystem); +} + UBool NumberFormat::isStyleSupported(UNumberFormatStyle style) { return gLastResortNumberPatterns[style] != NULL; @@ -1200,48 +1206,20 @@ NumberFormat::makeInstance(const Locale& desiredLocale, } #endif // Use numbering system cache hashtable - UHashtable *cache; - UMTX_CHECK(&nscacheMutex, NumberingSystem_cache, cache); - - // Check cache we got, create if non-existant - if (cache == NULL) { - cache = uhash_open(uhash_hashLong, - uhash_compareLong, - NULL, - &status); - - if (U_FAILURE(status)) { - // cache not created - out of memory - status = U_ZERO_ERROR; // work without the cache - cache = NULL; - } else { - // cache created - uhash_setValueDeleter(cache, deleteNumberingSystem); - - // set final NumberingSystem_cache value - Mutex lock(&nscacheMutex); - if (NumberingSystem_cache == NULL) { - NumberingSystem_cache = cache; - ucln_i18n_registerCleanup(UCLN_I18N_NUMFMT, numfmt_cleanup); - } else { - uhash_close(cache); - cache = NumberingSystem_cache; - } - } - } + umtx_initOnce(gNSCacheInitOnce, &nscacheInit); // Get cached numbering system LocalPointer ownedNs; NumberingSystem *ns = NULL; - if (cache != NULL) { + if (NumberingSystem_cache != NULL) { // TODO: Bad hash key usage, see ticket #8504. int32_t hashKey = desiredLocale.hashCode(); Mutex lock(&nscacheMutex); - ns = (NumberingSystem *)uhash_iget(cache, hashKey); + ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey); if (ns == NULL) { ns = NumberingSystem::createInstance(desiredLocale,status); - uhash_iput(cache, hashKey, (void*)ns, &status); + uhash_iput(NumberingSystem_cache, hashKey, (void*)ns, &status); } } else { ownedNs.adoptInstead(NumberingSystem::createInstance(desiredLocale,status)); diff --git a/icu4c/source/i18n/olsontz.cpp b/icu4c/source/i18n/olsontz.cpp index a39a4e6cf1d..244876b065b 100644 --- a/icu4c/source/i18n/olsontz.cpp +++ b/icu4c/source/i18n/olsontz.cpp @@ -119,7 +119,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top, const UResourceBundle* res, const UnicodeString& tzid, UErrorCode& ec) : - BasicTimeZone(tzid), finalZone(NULL), transitionRulesInitialized(FALSE) + BasicTimeZone(tzid), finalZone(NULL) { clearTransitionRules(); U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res))); @@ -658,7 +658,7 @@ OlsonTimeZone::clearTransitionRules(void) { historicRuleCount = 0; finalZoneWithStartYear = NULL; firstTZTransitionIdx = 0; - transitionRulesInitialized = FALSE; + transitionRulesInitOnce.reset(); } void @@ -689,23 +689,15 @@ OlsonTimeZone::deleteTransitionRules(void) { /* * Lazy transition rules initializer */ -static UMutex gLock = U_MUTEX_INITIALIZER; +static void U_CALLCONV initRules(OlsonTimeZone *This, UErrorCode &status) { + This->initTransitionRules(status); +} + void OlsonTimeZone::checkTransitionRules(UErrorCode& status) const { - if (U_FAILURE(status)) { - return; - } - UBool initialized; - UMTX_CHECK(&gLock, transitionRulesInitialized, initialized); - if (!initialized) { - umtx_lock(&gLock); - if (!transitionRulesInitialized) { - OlsonTimeZone *ncThis = const_cast(this); - ncThis->initTransitionRules(status); - } - umtx_unlock(&gLock); - } + OlsonTimeZone *ncThis = const_cast(this); + umtx_initOnce(ncThis->transitionRulesInitOnce, &initRules, ncThis, status); } void @@ -713,9 +705,6 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) { if(U_FAILURE(status)) { return; } - if (transitionRulesInitialized) { - return; - } deleteTransitionRules(); UnicodeString tzid; getID(tzid); @@ -884,7 +873,6 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) { firstFinalTZTransition->adoptFrom(prevRule->clone()); firstFinalTZTransition->adoptTo(firstFinalRule); } - transitionRulesInitialized = TRUE; } UBool diff --git a/icu4c/source/i18n/olsontz.h b/icu4c/source/i18n/olsontz.h index a263ec05aa4..17409abf20c 100644 --- a/icu4c/source/i18n/olsontz.h +++ b/icu4c/source/i18n/olsontz.h @@ -16,6 +16,7 @@ #if !UCONFIG_NO_FORMATTING #include "unicode/basictz.h" +#include "umutex.h" struct UResourceBundle; @@ -383,7 +384,10 @@ private: void clearTransitionRules(void); void deleteTransitionRules(void); void checkTransitionRules(UErrorCode& status) const; + + public: // Internal, for access from plain C code void initTransitionRules(UErrorCode& status); + private: InitialTimeZoneRule *initialRule; TimeZoneTransition *firstTZTransition; @@ -392,7 +396,7 @@ private: TimeArrayTimeZoneRule **historicRules; int16_t historicRuleCount; SimpleTimeZone *finalZoneWithStartYear; // hack - UBool transitionRulesInitialized; + UInitOnce transitionRulesInitOnce; }; inline int16_t diff --git a/icu4c/source/i18n/persncal.cpp b/icu4c/source/i18n/persncal.cpp index 957db9c08a7..60afeb4eb9e 100644 --- a/icu4c/source/i18n/persncal.cpp +++ b/icu4c/source/i18n/persncal.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** - * Copyright (C) 2003-2012, International Business Machines Corporation + * Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -245,64 +245,17 @@ PersianCalendar::inDaylightTime(UErrorCode& status) const } // default century -const UDate PersianCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t PersianCalendar::fgSystemDefaultCenturyYear = -1; -UDate PersianCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t PersianCalendar::fgSystemDefaultCenturyStartYear = -1; +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; UBool PersianCalendar::haveDefaultCentury() const { return TRUE; } -UDate PersianCalendar::defaultCenturyStart() const -{ - return internalGetDefaultCenturyStart(); -} - -int32_t PersianCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} - -UDate -PersianCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -PersianCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -PersianCalendar::initializeSystemDefaultCentury() -{ +static void U_CALLCONV initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. @@ -312,20 +265,26 @@ PersianCalendar::initializeSystemDefaultCentury() { calendar.setTime(Calendar::getNow(), status); calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); + + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); } // We have no recourse upon failure unless we want to propagate the failure // out. } +UDate PersianCalendar::defaultCenturyStart() const { + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t PersianCalendar::defaultCenturyStartYear() const { + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PersianCalendar) U_NAMESPACE_END diff --git a/icu4c/source/i18n/persncal.h b/icu4c/source/i18n/persncal.h index b926da5ef25..e6be055e68a 100644 --- a/icu4c/source/i18n/persncal.h +++ b/icu4c/source/i18n/persncal.h @@ -1,6 +1,6 @@ /* ****************************************************************************** - * Copyright (C) 2003-2008, International Business Machines Corporation + * Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -310,49 +310,6 @@ class PersianCalendar : public Calendar { * @internal */ virtual int32_t defaultCenturyStartYear() const; - - private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates - * with 2-digit years are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with - * 2-digit years are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/rbt.cpp b/icu4c/source/i18n/rbt.cpp index b987ade2c72..beb6067b943 100644 --- a/icu4c/source/i18n/rbt.cpp +++ b/icu4c/source/i18n/rbt.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (C) 1999-2012, International Business Machines +* Copyright (C) 1999-2013, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * Date Name Description @@ -248,8 +248,11 @@ RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition& // some other transliteration that is still in progress and holding the // transliteration mutex. If so, do not lock the transliteration // mutex again. + // TODO(andy): Need a better scheme for handling this. UBool needToLock; - UMTX_CHECK(NULL, (&text != gLockedText), needToLock); + umtx_lock(NULL); + needToLock = (&text != gLockedText); + umtx_unlock(NULL); if (needToLock) { umtx_lock(&transliteratorDataMutex); gLockedText = &text; diff --git a/icu4c/source/i18n/rbtz.cpp b/icu4c/source/i18n/rbtz.cpp index 6abc6d1e651..5f3addce313 100644 --- a/icu4c/source/i18n/rbtz.cpp +++ b/icu4c/source/i18n/rbtz.cpp @@ -151,16 +151,12 @@ RuleBasedTimeZone::completeConst(UErrorCode& status) const { if (U_FAILURE(status)) { return; } - UBool updated; - UMTX_CHECK(&gLock, fUpToDate, updated); - if (!updated) { - umtx_lock(&gLock); - if (!fUpToDate) { - RuleBasedTimeZone *ncThis = const_cast(this); - ncThis->complete(status); - } - umtx_unlock(&gLock); + umtx_lock(&gLock); + if (!fUpToDate) { + RuleBasedTimeZone *ncThis = const_cast(this); + ncThis->complete(status); } + umtx_unlock(&gLock); } void diff --git a/icu4c/source/i18n/regexst.cpp b/icu4c/source/i18n/regexst.cpp index d8652499091..fa61c3de401 100644 --- a/icu4c/source/i18n/regexst.cpp +++ b/icu4c/source/i18n/regexst.cpp @@ -1,7 +1,7 @@ // // regexst.h // -// Copyright (C) 2004-2012, International Business Machines Corporation and others. +// Copyright (C) 2004-2013, International Business Machines Corporation and others. // All Rights Reserved. // // This file contains class RegexStaticSets @@ -144,6 +144,7 @@ static const UChar gGC_LVTPattern[] = { RegexStaticSets *RegexStaticSets::gStaticSets = NULL; +UInitOnce gStaticSetsInitOnce = U_INITONCE_INITIALIZER; RegexStaticSets::RegexStaticSets(UErrorCode *status) : @@ -255,6 +256,7 @@ UBool RegexStaticSets::cleanup(void) { delete RegexStaticSets::gStaticSets; RegexStaticSets::gStaticSets = NULL; + gStaticSetsInitOnce.reset(); return TRUE; } @@ -263,34 +265,24 @@ static UBool U_CALLCONV regex_cleanup(void) { return RegexStaticSets::cleanup(); } + +static void U_CALLCONV initStaticSets(UErrorCode &status) { + U_ASSERT(RegexStaticSets::gStaticSets == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup); + RegexStaticSets::gStaticSets = new RegexStaticSets(&status); + if (U_FAILURE(status)) { + delete RegexStaticSets::gStaticSets; + RegexStaticSets::gStaticSets = NULL; + } + if (RegexStaticSets::gStaticSets == NULL && U_SUCCESS(status)) { + status = U_MEMORY_ALLOCATION_ERROR; + } +} U_CDECL_END void RegexStaticSets::initGlobals(UErrorCode *status) { - RegexStaticSets *p; - UMTX_CHECK(NULL, gStaticSets, p); - if (p == NULL) { - p = new RegexStaticSets(status); - if (p == NULL) { - *status = U_MEMORY_ALLOCATION_ERROR; - return; - } - if (U_FAILURE(*status)) { - delete p; - return; - } - umtx_lock(NULL); - if (gStaticSets == NULL) { - gStaticSets = p; - p = NULL; - } - umtx_unlock(NULL); - if (p) { - delete p; - } - ucln_i18n_registerCleanup(UCLN_I18N_REGEX, regex_cleanup); - } + umtx_initOnce(gStaticSetsInitOnce, &initStaticSets, *status); } - U_NAMESPACE_END #endif // !UCONFIG_NO_REGULAR_EXPRESSIONS diff --git a/icu4c/source/i18n/simpletz.cpp b/icu4c/source/i18n/simpletz.cpp index 2faa55893b9..dc8defabcec 100644 --- a/icu4c/source/i18n/simpletz.cpp +++ b/icu4c/source/i18n/simpletz.cpp @@ -1063,6 +1063,17 @@ SimpleTimeZone::deleteTransitionRules(void) { /* * Lazy transition rules initializer + * + * Note On the removal of UMTX_CHECK from checkTransitionRules(): + * + * It would be faster to have a UInitOnce as part of a SimpleTimeZone object, + * which would avoid needing to lock a mutex to check the initialization state. + * But we can't easily because simpletz.h is a public header, and including + * a UInitOnce as a member of SimpleTimeZone would publicly expose internal ICU headers. + * + * Alternatively we could have a pointer to a UInitOnce in the SimpleTimeZone object, + * allocate it in the constructors. This would be a more intrusive change, but doable + * if performance turns out to be an issue. */ static UMutex gLock = U_MUTEX_INITIALIZER; @@ -1071,16 +1082,12 @@ SimpleTimeZone::checkTransitionRules(UErrorCode& status) const { if (U_FAILURE(status)) { return; } - UBool initialized; - UMTX_CHECK(&gLock, transitionRulesInitialized, initialized); - if (!initialized) { - umtx_lock(&gLock); - if (!transitionRulesInitialized) { - SimpleTimeZone *ncThis = const_cast(this); - ncThis->initTransitionRules(status); - } - umtx_unlock(&gLock); + umtx_lock(&gLock); + if (!transitionRulesInitialized) { + SimpleTimeZone *ncThis = const_cast(this); + ncThis->initTransitionRules(status); } + umtx_unlock(&gLock); } void diff --git a/icu4c/source/i18n/smpdtfst.cpp b/icu4c/source/i18n/smpdtfst.cpp index 2e138b84fb8..8bbcea199ab 100644 --- a/icu4c/source/i18n/smpdtfst.cpp +++ b/icu4c/source/i18n/smpdtfst.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2009-2011, International Business Machines Corporation and * +* Copyright (C) 2009-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -18,6 +18,7 @@ #include "unicode/uniset.h" #include "unicode/udat.h" #include "cmemory.h" +#include "uassert.h" #include "ucln_in.h" #include "umutex.h" @@ -26,16 +27,17 @@ U_NAMESPACE_BEGIN -SimpleDateFormatStaticSets *SimpleDateFormatStaticSets::gStaticSets = NULL; +SimpleDateFormatStaticSets *gStaticSets = NULL; +UInitOnce gSimpleDateFormatStaticSetsInitOnce = U_INITONCE_INITIALIZER; -SimpleDateFormatStaticSets::SimpleDateFormatStaticSets(UErrorCode *status) +SimpleDateFormatStaticSets::SimpleDateFormatStaticSets(UErrorCode &status) : fDateIgnorables(NULL), fTimeIgnorables(NULL), fOtherIgnorables(NULL) { - fDateIgnorables = new UnicodeSet(UNICODE_STRING("[-,./[:whitespace:]]", 20), *status); - fTimeIgnorables = new UnicodeSet(UNICODE_STRING("[-.:[:whitespace:]]", 19), *status); - fOtherIgnorables = new UnicodeSet(UNICODE_STRING("[:whitespace:]", 14), *status); + fDateIgnorables = new UnicodeSet(UNICODE_STRING("[-,./[:whitespace:]]", 20), status); + fTimeIgnorables = new UnicodeSet(UNICODE_STRING("[-.:[:whitespace:]]", 19), status); + fOtherIgnorables = new UnicodeSet(UNICODE_STRING("[:whitespace:]", 14), status); // Check for null pointers if (fDateIgnorables == NULL || fTimeIgnorables == NULL || fOtherIgnorables == NULL) { @@ -54,7 +56,7 @@ ExitConstrDeleteAll: // Remove all sets and return error delete fTimeIgnorables; fTimeIgnorables = NULL; delete fOtherIgnorables; fOtherIgnorables = NULL; - *status = U_MEMORY_ALLOCATION_ERROR; + status = U_MEMORY_ALLOCATION_ERROR; } @@ -74,9 +76,9 @@ SimpleDateFormatStaticSets::~SimpleDateFormatStaticSets() { UBool SimpleDateFormatStaticSets::cleanup(void) { - delete SimpleDateFormatStaticSets::gStaticSets; - SimpleDateFormatStaticSets::gStaticSets = NULL; - + delete gStaticSets; + gStaticSets = NULL; + gSimpleDateFormatStaticSetsInitOnce.reset(); return TRUE; } @@ -86,50 +88,26 @@ smpdtfmt_cleanup(void) { return SimpleDateFormatStaticSets::cleanup(); } -U_CDECL_END -void SimpleDateFormatStaticSets::initSets(UErrorCode *status) -{ - SimpleDateFormatStaticSets *p; - - UMTX_CHECK(NULL, gStaticSets, p); - if (p == NULL) { - p = new SimpleDateFormatStaticSets(status); - - if (p == NULL) { - *status = U_MEMORY_ALLOCATION_ERROR; - return; - } - - if (U_FAILURE(*status)) { - delete p; - return; - } - - umtx_lock(NULL); - if (gStaticSets == NULL) { - gStaticSets = p; - p = NULL; - } - - umtx_unlock(NULL); - if (p != NULL) { - delete p; - } - - ucln_i18n_registerCleanup(UCLN_I18N_SMPDTFMT, smpdtfmt_cleanup); +static void U_CALLCONV smpdtfmt_initSets(UErrorCode &status) { + ucln_i18n_registerCleanup(UCLN_I18N_SMPDTFMT, smpdtfmt_cleanup); + U_ASSERT(gStaticSets == NULL); + gStaticSets = new SimpleDateFormatStaticSets(status); + if (gStaticSets == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; } } +U_CDECL_END + UnicodeSet *SimpleDateFormatStaticSets::getIgnorables(UDateFormatField fieldIndex) { - UErrorCode status = U_ZERO_ERROR; - - initSets(&status); - - if (U_FAILURE(status)) { - return NULL; - } + UErrorCode status = U_ZERO_ERROR; + umtx_initOnce(gSimpleDateFormatStaticSetsInitOnce, &smpdtfmt_initSets, status); + if (U_FAILURE(status)) { + return NULL; + } switch (fieldIndex) { case UDAT_YEAR_FIELD: @@ -152,7 +130,6 @@ UnicodeSet *SimpleDateFormatStaticSets::getIgnorables(UDateFormatField fieldInde } } - U_NAMESPACE_END #endif // #if !UCONFIG_NO_FORMATTING diff --git a/icu4c/source/i18n/smpdtfst.h b/icu4c/source/i18n/smpdtfst.h index 48a2c6cdc26..153e007f157 100644 --- a/icu4c/source/i18n/smpdtfst.h +++ b/icu4c/source/i18n/smpdtfst.h @@ -1,6 +1,6 @@ /* ******************************************************************************* -* Copyright (C) 2009-2011, International Business Machines Corporation and * +* Copyright (C) 2009-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -28,10 +28,7 @@ class UnicodeSet; class SimpleDateFormatStaticSets : public UMemory { public: - static SimpleDateFormatStaticSets *gStaticSets; // Ptr to all lazily initialized constant - // shared sets. - - SimpleDateFormatStaticSets(UErrorCode *status); + SimpleDateFormatStaticSets(UErrorCode &status); ~SimpleDateFormatStaticSets(); static void initSets(UErrorCode *status); diff --git a/icu4c/source/i18n/taiwncal.cpp b/icu4c/source/i18n/taiwncal.cpp index 4a895251df7..0b244fe3b36 100644 --- a/icu4c/source/i18n/taiwncal.cpp +++ b/icu4c/source/i18n/taiwncal.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 2003-2008, International Business Machines Corporation and * + * Copyright (C) 2003-2013, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -131,65 +131,21 @@ void TaiwanCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status } #endif -// default century -const UDate TaiwanCalendar::fgSystemDefaultCentury = DBL_MIN; -const int32_t TaiwanCalendar::fgSystemDefaultCenturyYear = -1; - -UDate TaiwanCalendar::fgSystemDefaultCenturyStart = DBL_MIN; -int32_t TaiwanCalendar::fgSystemDefaultCenturyStartYear = -1; - +/** + * The system maintains a static default century start date and Year. They are + * initialized the first time they are used. Once the system default century date + * and year are set, they do not change. + */ +static UDate gSystemDefaultCenturyStart = DBL_MIN; +static int32_t gSystemDefaultCenturyStartYear = -1; +static UInitOnce gSystemDefaultCenturyInit = U_INITONCE_INITIALIZER; UBool TaiwanCalendar::haveDefaultCentury() const { return TRUE; } -UDate TaiwanCalendar::defaultCenturyStart() const -{ - return internalGetDefaultCenturyStart(); -} - -int32_t TaiwanCalendar::defaultCenturyStartYear() const -{ - return internalGetDefaultCenturyStartYear(); -} - -UDate -TaiwanCalendar::internalGetDefaultCenturyStart() const -{ - // lazy-evaluate systemDefaultCenturyStart - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStart - - return fgSystemDefaultCenturyStart; -} - -int32_t -TaiwanCalendar::internalGetDefaultCenturyStartYear() const -{ - // lazy-evaluate systemDefaultCenturyStartYear - UBool needsUpdate; - UMTX_CHECK(NULL, (fgSystemDefaultCenturyStart == fgSystemDefaultCentury), needsUpdate); - - if (needsUpdate) { - initializeSystemDefaultCentury(); - } - - // use defaultCenturyStart unless it's the flag value; - // then use systemDefaultCenturyStartYear - - return fgSystemDefaultCenturyStartYear; -} - -void -TaiwanCalendar::initializeSystemDefaultCentury() +static void U_CALLCONV initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before @@ -200,20 +156,25 @@ TaiwanCalendar::initializeSystemDefaultCentury() { calendar.setTime(Calendar::getNow(), status); calendar.add(UCAL_YEAR, -80, status); - UDate newStart = calendar.getTime(status); - int32_t newYear = calendar.get(UCAL_YEAR, status); - umtx_lock(NULL); - if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) - { - fgSystemDefaultCenturyStartYear = newYear; - fgSystemDefaultCenturyStart = newStart; - } - umtx_unlock(NULL); + + gSystemDefaultCenturyStart = calendar.getTime(status); + gSystemDefaultCenturyStartYear = calendar.get(UCAL_YEAR, status); } // We have no recourse upon failure unless we want to propagate the failure // out. } +UDate TaiwanCalendar::defaultCenturyStart() const { + // lazy-evaluate systemDefaultCenturyStart + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStart; +} + +int32_t TaiwanCalendar::defaultCenturyStartYear() const { + // lazy-evaluate systemDefaultCenturyStartYear + umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury); + return gSystemDefaultCenturyStartYear; +} U_NAMESPACE_END diff --git a/icu4c/source/i18n/taiwncal.h b/icu4c/source/i18n/taiwncal.h index fe6f89b1902..8bd0b5ce2d6 100644 --- a/icu4c/source/i18n/taiwncal.h +++ b/icu4c/source/i18n/taiwncal.h @@ -1,6 +1,6 @@ /* ******************************************************************************** - * Copyright (C) 2003-2007, International Business Machines Corporation + * Copyright (C) 2003-2013, International Business Machines Corporation * and others. All Rights Reserved. ******************************************************************************** * @@ -171,49 +171,6 @@ private: * @internal */ virtual int32_t defaultCenturyStartYear() const; - - private: // default century stuff. - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * start of default century, as a date - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates - * with 2-digit years are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with - * 2-digit years are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years - * are considered to fall within so that its start date is 80 years - * before the current time. - */ - static void initializeSystemDefaultCentury(void); }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index 34e03a9d8b7..aaecff7b27e 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -39,6 +39,7 @@ #include "unicode/utypes.h" #include "unicode/ustring.h" +#include "uassert.h" #include "ustr_imp.h" #ifdef U_DEBUG_TZ @@ -109,14 +110,15 @@ static const UChar UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x static const int32_t GMT_ID_LENGTH = 3; static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11; -static UMutex LOCK = U_MUTEX_INITIALIZER; -static UMutex TZSET_LOCK = U_MUTEX_INITIALIZER; static icu::TimeZone* DEFAULT_ZONE = NULL; +static UInitOnce gDefaultZoneInitOnce = U_INITONCE_INITIALIZER; + static icu::TimeZone* _GMT = NULL; static icu::TimeZone* _UNKNOWN_ZONE = NULL; +static UInitOnce gStaticZonesInitOnce = U_INITONCE_INITIALIZER; static char TZDATA_VERSION[16]; -static UBool TZDataVersionInitialized = FALSE; +static UInitOnce gTZDataVersionInitOnce = U_INITONCE_INITIALIZER; static int32_t* MAP_SYSTEM_ZONES = NULL; static int32_t* MAP_CANONICAL_SYSTEM_ZONES = NULL; @@ -126,32 +128,41 @@ static int32_t LEN_SYSTEM_ZONES = 0; static int32_t LEN_CANONICAL_SYSTEM_ZONES = 0; static int32_t LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0; +static UInitOnce gSystemZonesInitOnce = U_INITONCE_INITIALIZER; +static UInitOnce gCanonicalZonesInitOnce = U_INITONCE_INITIALIZER; +static UInitOnce gCanonicalLocationZonesInitOnce = U_INITONCE_INITIALIZER; + U_CDECL_BEGIN static UBool U_CALLCONV timeZone_cleanup(void) { + U_NAMESPACE_USE delete DEFAULT_ZONE; DEFAULT_ZONE = NULL; + gDefaultZoneInitOnce.reset(); delete _GMT; _GMT = NULL; - delete _UNKNOWN_ZONE; _UNKNOWN_ZONE = NULL; + gStaticZonesInitOnce.reset(); uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION)); - TZDataVersionInitialized = FALSE; + gTZDataVersionInitOnce.reset(); LEN_SYSTEM_ZONES = 0; uprv_free(MAP_SYSTEM_ZONES); MAP_SYSTEM_ZONES = 0; + gSystemZonesInitOnce.reset(); LEN_CANONICAL_SYSTEM_ZONES = 0; uprv_free(MAP_CANONICAL_SYSTEM_ZONES); MAP_CANONICAL_SYSTEM_ZONES = 0; + gCanonicalZonesInitOnce.reset(); LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0; uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES); MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0; + gCanonicalLocationZonesInitOnce.reset(); return TRUE; } @@ -287,31 +298,12 @@ static UResourceBundle* openOlsonResource(const UnicodeString& id, namespace { -void -ensureStaticTimeZones() { - UBool needsInit; - UMTX_CHECK(&LOCK, (_GMT == NULL), needsInit); /* This is here to prevent race conditions. */ - +void U_CALLCONV initStaticTimeZones() { // Initialize _GMT independently of other static data; it should // be valid even if we can't load the time zone UDataMemory. - if (needsInit) { - SimpleTimeZone *tmpUnknown = - new SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)); - SimpleTimeZone *tmpGMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH)); - umtx_lock(&LOCK); - if (_UNKNOWN_ZONE == 0) { - _UNKNOWN_ZONE = tmpUnknown; - tmpUnknown = NULL; - } - if (_GMT == 0) { - _GMT = tmpGMT; - tmpGMT = NULL; - } - umtx_unlock(&LOCK); - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - delete tmpUnknown; - delete tmpGMT; - } + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + _UNKNOWN_ZONE = new SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)); + _GMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH)); } } // anonymous namespace @@ -319,14 +311,14 @@ ensureStaticTimeZones() { const TimeZone& U_EXPORT2 TimeZone::getUnknown() { - ensureStaticTimeZones(); + umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones); return *_UNKNOWN_ZONE; } const TimeZone* U_EXPORT2 TimeZone::getGMT(void) { - ensureStaticTimeZones(); + umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones); return _GMT; } @@ -381,43 +373,9 @@ TimeZone::operator==(const TimeZone& that) const // ------------------------------------- -TimeZone* U_EXPORT2 -TimeZone::createTimeZone(const UnicodeString& ID) -{ - /* We first try to lookup the zone ID in our system list. If this - * fails, we try to parse it as a custom string GMT[+-]hh:mm. If - * all else fails, we return GMT, which is probably not what the - * user wants, but at least is a functioning TimeZone object. - * - * We cannot return NULL, because that would break compatibility - * with the JDK. - */ - TimeZone* result = createSystemTimeZone(ID); - - if (result == 0) { - U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom")); - result = createCustomTimeZone(ID); - } - if (result == 0) { - U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)")); - result = getUnknown().clone(); - } - return result; -} - -/** - * Lookup the given name in our system zone table. If found, - * instantiate a new zone of that name and return it. If not - * found, return 0. - */ +namespace { TimeZone* -TimeZone::createSystemTimeZone(const UnicodeString& id) { - UErrorCode ec = U_ZERO_ERROR; - return createSystemTimeZone(id, ec); -} - -TimeZone* -TimeZone::createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) { +createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) { if (U_FAILURE(ec)) { return NULL; } @@ -443,19 +401,60 @@ TimeZone::createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) { return z; } +/** + * Lookup the given name in our system zone table. If found, + * instantiate a new zone of that name and return it. If not + * found, return 0. + */ +TimeZone* +createSystemTimeZone(const UnicodeString& id) { + UErrorCode ec = U_ZERO_ERROR; + return createSystemTimeZone(id, ec); +} + +} + +TimeZone* U_EXPORT2 +TimeZone::createTimeZone(const UnicodeString& ID) +{ + /* We first try to lookup the zone ID in our system list. If this + * fails, we try to parse it as a custom string GMT[+-]hh:mm. If + * all else fails, we return GMT, which is probably not what the + * user wants, but at least is a functioning TimeZone object. + * + * We cannot return NULL, because that would break compatibility + * with the JDK. + */ + TimeZone* result = createSystemTimeZone(ID); + + if (result == 0) { + U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom")); + result = createCustomTimeZone(ID); + } + if (result == 0) { + U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)")); + result = getUnknown().clone(); + } + return result; +} + // ------------------------------------- /** - * Initialize DEFAULT_ZONE from the system default time zone. The - * caller should confirm that DEFAULT_ZONE is NULL before calling. + * Initialize DEFAULT_ZONE from the system default time zone. * Upon return, DEFAULT_ZONE will not be NULL, unless operator new() * returns NULL. - * - * Must be called OUTSIDE mutex. */ -void -TimeZone::initDefault() +static void U_CALLCONV initDefault() { + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + + // If setDefault() has already been called we can skip getting the + // default zone information from the system. + if (DEFAULT_ZONE != NULL) { + return; + } + // We access system timezone data through TPlatformUtilities, // including tzset(), timezone, and tzname[]. int32_t rawOffset = 0; @@ -463,38 +462,27 @@ TimeZone::initDefault() // First, try to create a system timezone, based // on the string ID in tzname[0]. - { - // NOTE: Local mutex here. TimeZone mutex below - // mutexed to avoid threading issues in the platform functions. - // Some of the locale/timezone OS functions may not be thread safe, - // so the intent is that any setting from anywhere within ICU - // happens while the ICU mutex is held. - // The operating system might actually use ICU to implement timezones. - // So we may have ICU calling ICU here, like on AIX. - // In order to prevent a double lock of a non-reentrant mutex in a - // different part of ICU, we use TZSET_LOCK to allow only one instance - // of ICU to query these thread unsafe OS functions at any given time. - Mutex lock(&TZSET_LOCK); - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - uprv_tzset(); // Initialize tz... system data + // NOTE: this code is safely single threaded, being only + // run via umtx_initOnce(). + // + // Some of the locale/timezone OS functions may not be thread safe, + // + // The operating system might actually use ICU to implement timezones. + // So we may have ICU calling ICU here, like on AIX. + // There shouldn't be a problem with this; initOnce does not hold a mutex + // while the init function is being run. - // Get the timezone ID from the host. This function should do - // any required host-specific remapping; e.g., on Windows this - // function maps the Date and Time control panel setting to an - // ICU timezone ID. - hostID = uprv_tzname(0); + uprv_tzset(); // Initialize tz... system data - // Invert sign because UNIX semantics are backwards - rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND; - } + // Get the timezone ID from the host. This function should do + // any required host-specific remapping; e.g., on Windows this + // function maps the Date and Time control panel setting to an + // ICU timezone ID. + hostID = uprv_tzname(0); - UBool initialized; - UMTX_CHECK(&LOCK, (DEFAULT_ZONE != NULL), initialized); - if (initialized) { - /* Hrmph? Either a race condition happened, or tzset initialized ICU. */ - return; - } + // Invert sign because UNIX semantics are backwards + rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND; TimeZone* default_zone = NULL; @@ -527,7 +515,7 @@ TimeZone::initDefault() // If we _still_ don't have a time zone, use GMT. if (default_zone == NULL) { - const TimeZone* temptz = getGMT(); + const TimeZone* temptz = TimeZone::getGMT(); // If we can't use GMT, get out. if (temptz == NULL) { return; @@ -535,16 +523,12 @@ TimeZone::initDefault() default_zone = temptz->clone(); } - // If DEFAULT_ZONE is still NULL, set it up. - umtx_lock(&LOCK); - if (DEFAULT_ZONE == NULL) { - DEFAULT_ZONE = default_zone; - default_zone = NULL; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - } - umtx_unlock(&LOCK); + // The only way for DEFAULT_ZONE to be non-null at this point is if the user + // made a thread-unsafe call to setDefault() or adoptDefault() in another + // thread while this thread was doing something that required getting the default. + U_ASSERT(DEFAULT_ZONE == NULL); - delete default_zone; + DEFAULT_ZONE = default_zone; } // ------------------------------------- @@ -552,14 +536,7 @@ TimeZone::initDefault() TimeZone* U_EXPORT2 TimeZone::createDefault() { - /* This is here to prevent race conditions. */ - UBool needsInit; - UMTX_CHECK(&LOCK, (DEFAULT_ZONE == NULL), needsInit); - if (needsInit) { - initDefault(); - } - - Mutex lock(&LOCK); // In case adoptDefault is called + umtx_initOnce(gDefaultZoneInitOnce, initDefault); return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL; } @@ -570,13 +547,8 @@ TimeZone::adoptDefault(TimeZone* zone) { if (zone != NULL) { - TimeZone* old = NULL; - - umtx_lock(&LOCK); - old = DEFAULT_ZONE; + TimeZone *old = DEFAULT_ZONE; DEFAULT_ZONE = zone; - umtx_unlock(&LOCK); - delete old; ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); } @@ -591,6 +563,84 @@ TimeZone::setDefault(const TimeZone& zone) //---------------------------------------------------------------------- + +static void U_CALLCONV initMap(USystemTimeZoneType type, UErrorCode& ec) { + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + + UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec); + res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section + if (U_SUCCESS(ec)) { + int32_t size = ures_getSize(res); + int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t)); + if (m == NULL) { + ec = U_MEMORY_ALLOCATION_ERROR; + } else { + int32_t numEntries = 0; + for (int32_t i = 0; i < size; i++) { + UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec); + if (U_FAILURE(ec)) { + break; + } + if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) { + // exclude Etc/Unknown + continue; + } + if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { + UnicodeString canonicalID; + ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec); + if (U_FAILURE(ec)) { + break; + } + if (canonicalID != id) { + // exclude aliases + continue; + } + } + if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { + const UChar *region = TimeZone::getRegion(id, ec); + if (U_FAILURE(ec)) { + break; + } + if (u_strcmp(region, WORLD) == 0) { + // exclude non-location ("001") + continue; + } + } + m[numEntries++] = i; + } + if (U_SUCCESS(ec)) { + int32_t *tmp = m; + m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t)); + if (m == NULL) { + // realloc failed.. use the original one even it has unused + // area at the end + m = tmp; + } + + switch(type) { + case UCAL_ZONE_TYPE_ANY: + U_ASSERT(MAP_SYSTEM_ZONES == NULL); + MAP_SYSTEM_ZONES = m; + LEN_SYSTEM_ZONES = numEntries; + break; + case UCAL_ZONE_TYPE_CANONICAL: + U_ASSERT(MAP_CANONICAL_SYSTEM_ZONES == NULL); + MAP_CANONICAL_SYSTEM_ZONES = m; + LEN_CANONICAL_SYSTEM_ZONES = numEntries; + break; + case UCAL_ZONE_TYPE_CANONICAL_LOCATION: + U_ASSERT(MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL); + MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m; + LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries; + break; + } + } + } + } + ures_close(res); +} + + /** * This is the default implementation for subclasses that do not * override this method. This implementation calls through to the @@ -688,129 +738,29 @@ private: int32_t* m = NULL; switch (type) { case UCAL_ZONE_TYPE_ANY: + umtx_initOnce(gSystemZonesInitOnce, &initMap, type, ec); m = MAP_SYSTEM_ZONES; len = LEN_SYSTEM_ZONES; break; case UCAL_ZONE_TYPE_CANONICAL: + umtx_initOnce(gCanonicalZonesInitOnce, &initMap, type, ec); m = MAP_CANONICAL_SYSTEM_ZONES; len = LEN_CANONICAL_SYSTEM_ZONES; break; case UCAL_ZONE_TYPE_CANONICAL_LOCATION: + umtx_initOnce(gCanonicalLocationZonesInitOnce, &initMap, type, ec); m = MAP_CANONICAL_SYSTEM_LOCATION_ZONES; len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES; break; - } - UBool needsInit = FALSE; - UMTX_CHECK(&LOCK, (len == 0), needsInit); - if (needsInit) { - m = initMap(type, len, ec); + default: + ec = U_ILLEGAL_ARGUMENT_ERROR; + m = NULL; + len = 0; + break; } return m; } - static int32_t* initMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) { - len = 0; - if (U_FAILURE(ec)) { - return NULL; - } - - int32_t *result = NULL; - - UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec); - res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section - if (U_SUCCESS(ec)) { - int32_t size = ures_getSize(res); - int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t)); - if (m == NULL) { - ec = U_MEMORY_ALLOCATION_ERROR; - } else { - int32_t numEntries = 0; - for (int32_t i = 0; i < size; i++) { - UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec); - if (U_FAILURE(ec)) { - break; - } - if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) { - // exclude Etc/Unknown - continue; - } - if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { - UnicodeString canonicalID; - ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec); - if (U_FAILURE(ec)) { - break; - } - if (canonicalID != id) { - // exclude aliases - continue; - } - } - if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { - const UChar *region = TimeZone::getRegion(id, ec); - if (U_FAILURE(ec)) { - break; - } - if (u_strcmp(region, WORLD) == 0) { - // exclude non-location ("001") - continue; - } - } - m[numEntries++] = i; - } - if (U_SUCCESS(ec)) { - int32_t *tmp = m; - m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t)); - if (m == NULL) { - // realloc failed.. use the original one even it has unused - // area at the end - m = tmp; - } - - umtx_lock(&LOCK); - { - switch(type) { - case UCAL_ZONE_TYPE_ANY: - if (MAP_SYSTEM_ZONES == NULL) { - MAP_SYSTEM_ZONES = m; - LEN_SYSTEM_ZONES = numEntries; - m = NULL; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - } - result = MAP_SYSTEM_ZONES; - len = LEN_SYSTEM_ZONES; - break; - case UCAL_ZONE_TYPE_CANONICAL: - if (MAP_CANONICAL_SYSTEM_ZONES == NULL) { - MAP_CANONICAL_SYSTEM_ZONES = m; - LEN_CANONICAL_SYSTEM_ZONES = numEntries; - m = NULL; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - } - result = MAP_CANONICAL_SYSTEM_ZONES; - len = LEN_CANONICAL_SYSTEM_ZONES; - break; - case UCAL_ZONE_TYPE_CANONICAL_LOCATION: - if (MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL) { - MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m; - LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries; - m = NULL; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - } - result = MAP_CANONICAL_SYSTEM_LOCATION_ZONES; - len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES; - break; - } - } - umtx_unlock(&LOCK); - } - uprv_free(m); - } - } - - ures_close(res); - return result; - } - public: #define DEFAULT_FILTERED_MAP_SIZE 8 @@ -866,7 +816,7 @@ public: if (rawOffset != NULL) { // Filter by raw offset // Note: This is VERY inefficient - TimeZone *z = TimeZone::createSystemTimeZone(id, ec); + TimeZone *z = createSystemTimeZone(id, ec); if (U_FAILURE(ec)) { break; } @@ -1516,37 +1466,27 @@ TimeZone::hasSameRules(const TimeZone& other) const useDaylightTime() == other.useDaylightTime()); } +static void U_CALLCONV initTZDataVersion(UErrorCode &status) { + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); + int32_t len = 0; + UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status); + const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION, &len, &status); + + if (U_SUCCESS(status)) { + if (len >= (int32_t)sizeof(TZDATA_VERSION)) { + // Ensure that there is always space for a trailing nul in TZDATA_VERSION + len = sizeof(TZDATA_VERSION) - 1; + } + u_UCharsToChars(tzver, TZDATA_VERSION, len); + } + ures_close(bundle); + +} + const char* TimeZone::getTZDataVersion(UErrorCode& status) { - /* This is here to prevent race conditions. */ - UBool needsInit; - UMTX_CHECK(&LOCK, !TZDataVersionInitialized, needsInit); - if (needsInit) { - int32_t len = 0; - UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status); - const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION, - &len, &status); - - if (U_SUCCESS(status)) { - if (len >= (int32_t)sizeof(TZDATA_VERSION)) { - // Ensure that there is always space for a trailing nul in TZDATA_VERSION - len = sizeof(TZDATA_VERSION) - 1; - } - umtx_lock(&LOCK); - if (!TZDataVersionInitialized) { - u_UCharsToChars(tzver, TZDATA_VERSION, len); - TZDataVersionInitialized = TRUE; - } - umtx_unlock(&LOCK); - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); - } - - ures_close(bundle); - } - if (U_FAILURE(status)) { - return NULL; - } + umtx_initOnce(gTZDataVersionInitOnce, &initTZDataVersion, status); return (const char*)TZDATA_VERSION; } diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp index 95f0421e8f5..ab5b451d359 100644 --- a/icu4c/source/i18n/tzfmt.cpp +++ b/icu4c/source/i18n/tzfmt.cpp @@ -136,10 +136,10 @@ static const int32_t ALL_GENERIC_NAME_TYPES = UTZGNM_LOCATION | UTZGNM_LONG | UT // Time Zone ID/Short ID trie static TextTrieMap *gZoneIdTrie = NULL; -static UBool gZoneIdTrieInitialized = FALSE; +static UInitOnce gZoneIdTrieInitOnce = U_INITONCE_INITIALIZER; static TextTrieMap *gShortZoneIdTrie = NULL; -static UBool gShortZoneIdTrieInitialized = FALSE; +static UInitOnce gShortZoneIdTrieInitOnce = U_INITONCE_INITIALIZER; static UMutex gLock = U_MUTEX_INITIALIZER; @@ -153,13 +153,13 @@ static UBool U_CALLCONV tzfmt_cleanup(void) delete gZoneIdTrie; } gZoneIdTrie = NULL; - gZoneIdTrieInitialized = FALSE; + gZoneIdTrieInitOnce.reset(); if (gShortZoneIdTrie != NULL) { delete gShortZoneIdTrie; } gShortZoneIdTrie = NULL; - gShortZoneIdTrieInitialized = FALSE; + gShortZoneIdTrieInitOnce.reset(); return TRUE; } @@ -438,6 +438,7 @@ TimeZoneFormat::operator=(const TimeZoneFormat& other) { fTimeZoneNames = other.fTimeZoneNames->clone(); if (other.fTimeZoneGenericNames) { + // TODO: this test has dubious thread safety. fTimeZoneGenericNames = other.fTimeZoneGenericNames->clone(); } @@ -1291,18 +1292,12 @@ TimeZoneFormat::getTimeZoneGenericNames(UErrorCode& status) const { return NULL; } - UBool create; - UMTX_CHECK(&gZoneMetaLock, (fTimeZoneGenericNames == NULL), create); - if (create) { + umtx_lock(&gLock); + if (fTimeZoneGenericNames == NULL) { TimeZoneFormat *nonConstThis = const_cast(this); - umtx_lock(&gLock); - { - if (fTimeZoneGenericNames == NULL) { - nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status); - } - } - umtx_unlock(&gLock); + nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status); } + umtx_unlock(&gLock); return fTimeZoneGenericNames; } @@ -2634,44 +2629,37 @@ ZoneIdMatchHandler::getMatchLen() { return fLen; } + +static void U_CALLCONV initZoneIdTrie(UErrorCode &status) { + U_ASSERT(gZoneIdTrie == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup); + gZoneIdTrie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta + if (gZoneIdTrie == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + StringEnumeration *tzenum = TimeZone::createEnumeration(); + const UnicodeString *id; + while ((id = tzenum->snext(status))) { + const UChar* uid = ZoneMeta::findTimeZoneID(*id); + if (uid) { + gZoneIdTrie->put(uid, const_cast(uid), status); + } + } + delete tzenum; +} + + UnicodeString& TimeZoneFormat::parseZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const { UErrorCode status = U_ZERO_ERROR; - UBool initialized; - UMTX_CHECK(&gLock, gZoneIdTrieInitialized, initialized); - if (!initialized) { - umtx_lock(&gLock); - { - if (!gZoneIdTrieInitialized) { - StringEnumeration *tzenum = TimeZone::createEnumeration(); - TextTrieMap* trie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta - if (trie) { - const UnicodeString *id; - while ((id = tzenum->snext(status))) { - const UChar* uid = ZoneMeta::findTimeZoneID(*id); - if (uid) { - trie->put(uid, const_cast(uid), status); - } - } - if (U_SUCCESS(status)) { - gZoneIdTrie = trie; - gZoneIdTrieInitialized = initialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup); - } else { - delete trie; - } - } - delete tzenum; - } - } - umtx_unlock(&gLock); - } + umtx_initOnce(gZoneIdTrieInitOnce, &initZoneIdTrie, status); int32_t start = pos.getIndex(); int32_t len = 0; tzID.setToBogus(); - if (initialized) { + if (U_SUCCESS(status)) { LocalPointer handler(new ZoneIdMatchHandler()); gZoneIdTrie->search(text, start, handler.getAlias(), status); len = handler->getMatchLen(); @@ -2689,47 +2677,39 @@ TimeZoneFormat::parseZoneID(const UnicodeString& text, ParsePosition& pos, Unico return tzID; } +static void U_CALLCONV initShortZoneIdTrie(UErrorCode &status) { + U_ASSERT(gShortZoneIdTrie == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup); + StringEnumeration *tzenum = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status); + if (U_SUCCESS(status)) { + gShortZoneIdTrie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta + if (gShortZoneIdTrie == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + const UnicodeString *id; + while ((id = tzenum->snext(status))) { + const UChar* uID = ZoneMeta::findTimeZoneID(*id); + const UChar* shortID = ZoneMeta::getShortID(*id); + if (shortID && uID) { + gShortZoneIdTrie->put(shortID, const_cast(uID), status); + } + } + } + } + delete tzenum; +} + + UnicodeString& TimeZoneFormat::parseShortZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const { UErrorCode status = U_ZERO_ERROR; - UBool initialized; - UMTX_CHECK(&gLock, gShortZoneIdTrieInitialized, initialized); - if (!initialized) { - umtx_lock(&gLock); - { - if (!gShortZoneIdTrieInitialized) { - StringEnumeration *tzenum = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status); - if (U_SUCCESS(status)) { - TextTrieMap* trie = new TextTrieMap(TRUE, NULL); // No deleter, because values are pooled by ZoneMeta - if (trie) { - const UnicodeString *id; - while ((id = tzenum->snext(status))) { - const UChar* uID = ZoneMeta::findTimeZoneID(*id); - const UChar* shortID = ZoneMeta::getShortID(*id); - if (shortID && uID) { - trie->put(shortID, const_cast(uID), status); - } - } - if (U_SUCCESS(status)) { - gShortZoneIdTrie = trie; - gShortZoneIdTrieInitialized = initialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup); - } else { - delete trie; - } - } - } - delete tzenum; - } - } - umtx_unlock(&gLock); - } + umtx_initOnce(gShortZoneIdTrieInitOnce, &initShortZoneIdTrie, status); int32_t start = pos.getIndex(); int32_t len = 0; tzID.setToBogus(); - if (initialized) { + if (U_SUCCESS(status)) { LocalPointer handler(new ZoneIdMatchHandler()); gShortZoneIdTrie->search(text, start, handler.getAlias(), status); len = handler->getMatchLen(); diff --git a/icu4c/source/i18n/tzgnames.cpp b/icu4c/source/i18n/tzgnames.cpp index 0666cfba29d..e6bd109b749 100644 --- a/icu4c/source/i18n/tzgnames.cpp +++ b/icu4c/source/i18n/tzgnames.cpp @@ -20,6 +20,7 @@ #include "cmemory.h" #include "cstring.h" +#include "mutex.h" #include "uhash.h" #include "uassert.h" #include "umutex.h" @@ -1222,33 +1223,25 @@ TimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) { return NULL; } - UBool initialized; - UMTX_CHECK(&gTZGNLock, gTZGNCoreCacheInitialized, initialized); - if (!initialized) { - // Create empty hashtable - umtx_lock(&gTZGNLock); - { - if (!gTZGNCoreCacheInitialized) { - gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); - if (U_SUCCESS(status)) { - uhash_setKeyDeleter(gTZGNCoreCache, uprv_free); - uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef); - gTZGNCoreCacheInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup); - } + TZGNCoreRef *cacheEntry = NULL; + { + Mutex lock(&gTZGNLock); + + if (!gTZGNCoreCacheInitialized) { + // Create empty hashtable + gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); + if (U_SUCCESS(status)) { + uhash_setKeyDeleter(gTZGNCoreCache, uprv_free); + uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef); + gTZGNCoreCacheInitialized = TRUE; + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup); } } - umtx_unlock(&gTZGNLock); - if (U_FAILURE(status)) { return NULL; } - } - // Check the cache, if not available, create new one and cache - TZGNCoreRef *cacheEntry = NULL; - umtx_lock(&gTZGNLock); - { + // Check the cache, if not available, create new one and cache const char *key = locale.getName(); cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key); if (cacheEntry == NULL) { @@ -1302,8 +1295,7 @@ TimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) { sweepCache(); gAccessCount = 0; } - } - umtx_unlock(&gTZGNLock); + } // End of mutex locked block if (cacheEntry == NULL) { delete instance; diff --git a/icu4c/source/i18n/tznames.cpp b/icu4c/source/i18n/tznames.cpp index c887997e82d..bb1e863cd8b 100644 --- a/icu4c/source/i18n/tznames.cpp +++ b/icu4c/source/i18n/tznames.cpp @@ -14,6 +14,7 @@ #include "unicode/uenum.h" #include "cmemory.h" #include "cstring.h" +#include "mutex.h" #include "putilimp.h" #include "tznames_impl.h" #include "uassert.h" @@ -126,89 +127,78 @@ TimeZoneNamesDelegate::TimeZoneNamesDelegate() } TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) { - UBool initialized; - UMTX_CHECK(&gTimeZoneNamesLock, gTimeZoneNamesCacheInitialized, initialized); - if (!initialized) { - // Create empty hashtable - umtx_lock(&gTimeZoneNamesLock); - { - if (!gTimeZoneNamesCacheInitialized) { - gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); - if (U_SUCCESS(status)) { - uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free); - uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry); - gTimeZoneNamesCacheInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup); - } - } + Mutex lock(&gTimeZoneNamesLock); + if (!gTimeZoneNamesCacheInitialized) { + // Create empty hashtable if it is not already initialized. + gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status); + if (U_SUCCESS(status)) { + uhash_setKeyDeleter(gTimeZoneNamesCache, uprv_free); + uhash_setValueDeleter(gTimeZoneNamesCache, deleteTimeZoneNamesCacheEntry); + gTimeZoneNamesCacheInitialized = TRUE; + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONENAMES, timeZoneNames_cleanup); } - umtx_unlock(&gTimeZoneNamesLock); + } - if (U_FAILURE(status)) { - return; - } + if (U_FAILURE(status)) { + return; } // Check the cache, if not available, create new one and cache TimeZoneNamesCacheEntry *cacheEntry = NULL; - umtx_lock(&gTimeZoneNamesLock); - { - const char *key = locale.getName(); - cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key); - if (cacheEntry == NULL) { - TimeZoneNames *tznames = NULL; - char *newKey = NULL; - tznames = new TimeZoneNamesImpl(locale, status); - if (tznames == NULL) { + const char *key = locale.getName(); + cacheEntry = (TimeZoneNamesCacheEntry *)uhash_get(gTimeZoneNamesCache, key); + if (cacheEntry == NULL) { + TimeZoneNames *tznames = NULL; + char *newKey = NULL; + + tznames = new TimeZoneNamesImpl(locale, status); + if (tznames == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } + if (U_SUCCESS(status)) { + newKey = (char *)uprv_malloc(uprv_strlen(key) + 1); + if (newKey == NULL) { status = U_MEMORY_ALLOCATION_ERROR; + } else { + uprv_strcpy(newKey, key); } - if (U_SUCCESS(status)) { - newKey = (char *)uprv_malloc(uprv_strlen(key) + 1); - if (newKey == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } else { - uprv_strcpy(newKey, key); - } - } - if (U_SUCCESS(status)) { - cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry)); - if (cacheEntry == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } else { - cacheEntry->names = tznames; - cacheEntry->refCount = 1; - cacheEntry->lastAccess = (double)uprv_getUTCtime(); + } + if (U_SUCCESS(status)) { + cacheEntry = (TimeZoneNamesCacheEntry *)uprv_malloc(sizeof(TimeZoneNamesCacheEntry)); + if (cacheEntry == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } else { + cacheEntry->names = tznames; + cacheEntry->refCount = 1; + cacheEntry->lastAccess = (double)uprv_getUTCtime(); - uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status); - } + uhash_put(gTimeZoneNamesCache, newKey, cacheEntry, &status); } - if (U_FAILURE(status)) { - if (tznames != NULL) { - delete tznames; - } - if (newKey != NULL) { - uprv_free(newKey); - } - if (cacheEntry != NULL) { - uprv_free(cacheEntry); - } - cacheEntry = NULL; + } + if (U_FAILURE(status)) { + if (tznames != NULL) { + delete tznames; } - } else { - // Update the reference count - cacheEntry->refCount++; - cacheEntry->lastAccess = (double)uprv_getUTCtime(); - } - gAccessCount++; - if (gAccessCount >= SWEEP_INTERVAL) { - // sweep - sweepCache(); - gAccessCount = 0; + if (newKey != NULL) { + uprv_free(newKey); + } + if (cacheEntry != NULL) { + uprv_free(cacheEntry); + } + cacheEntry = NULL; } + } else { + // Update the reference count + cacheEntry->refCount++; + cacheEntry->lastAccess = (double)uprv_getUTCtime(); + } + gAccessCount++; + if (gAccessCount >= SWEEP_INTERVAL) { + // sweep + sweepCache(); + gAccessCount = 0; } - umtx_unlock(&gTimeZoneNamesLock); - fTZnamesCacheEntry = cacheEntry; } diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp index e3b0c3c0431..d11d787cfc7 100644 --- a/icu4c/source/i18n/tznames_impl.cpp +++ b/icu4c/source/i18n/tznames_impl.cpp @@ -20,6 +20,7 @@ #include "cmemory.h" #include "cstring.h" #include "uassert.h" +#include "mutex.h" #include "uresimp.h" #include "ureslocs.h" #include "zonemeta.h" @@ -290,7 +291,6 @@ static UMutex TextTrieMutex = U_MUTEX_INITIALIZER; // needed for parsing operations, which are less common than formatting, // and the Trie is big, which is why its creation is deferred until first use. void TextTrieMap::buildTrie(UErrorCode &status) { - umtx_lock(&TextTrieMutex); if (fLazyContents != NULL) { for (int32_t i=0; isize(); i+=2) { const UChar *key = (UChar *)fLazyContents->elementAt(i); @@ -301,17 +301,22 @@ void TextTrieMap::buildTrie(UErrorCode &status) { delete fLazyContents; fLazyContents = NULL; } - umtx_unlock(&TextTrieMutex); } void TextTrieMap::search(const UnicodeString &text, int32_t start, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const { - UBool trieNeedsInitialization = FALSE; - UMTX_CHECK(&TextTrieMutex, fLazyContents != NULL, trieNeedsInitialization); - if (trieNeedsInitialization) { - TextTrieMap *nonConstThis = const_cast(this); - nonConstThis->buildTrie(status); + { + // TODO: if locking the mutex for each check proves to be a performance problem, + // add a flag of type atomic_int32_t to class TextTrieMap, and use only + // the ICU atomic safe functions for assigning and testing. + // Don't test the pointer fLazyContents. + // Don't do unless it's really required. + Mutex lock(&TextTrieMutex); + if (fLazyContents != NULL) { + TextTrieMap *nonConstThis = const_cast(this); + nonConstThis->buildTrie(status); + } } if (fNodes == NULL) { return; diff --git a/icu4c/source/i18n/ucol_bld.cpp b/icu4c/source/i18n/ucol_bld.cpp index 15088310983..22ca64055e2 100644 --- a/icu4c/source/i18n/ucol_bld.cpp +++ b/icu4c/source/i18n/ucol_bld.cpp @@ -29,6 +29,7 @@ #include "unicode/ustring.h" #include "unicode/utf16.h" #include "normalizer2impl.h" +#include "uassert.h" #include "ucol_bld.h" #include "ucol_elm.h" #include "ucol_cnt.h" @@ -41,6 +42,7 @@ static const InverseUCATableHeader* _staticInvUCA = NULL; static UDataMemory* invUCA_DATA_MEM = NULL; +static UInitOnce gStaticInvUCAInitOnce = U_INITONCE_INITIALIZER; U_CDECL_BEGIN static UBool U_CALLCONV @@ -1330,61 +1332,48 @@ ucol_bld_cleanup(void) udata_close(invUCA_DATA_MEM); invUCA_DATA_MEM = NULL; _staticInvUCA = NULL; + gStaticInvUCAInitOnce.reset(); return TRUE; } U_CDECL_END +static void U_CALLCONV initInverseUCA(UErrorCode &status) { + U_ASSERT(invUCA_DATA_MEM == NULL); + U_ASSERT(_staticInvUCA == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_UCOL_BLD, ucol_bld_cleanup); + InverseUCATableHeader *newInvUCA = NULL; + UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, INVC_DATA_TYPE, INVC_DATA_NAME, isAcceptableInvUCA, NULL, &status); + + if(U_FAILURE(status)) { + if (result) { + udata_close(result); + } + // This is not needed, as we are talking about + // memory we got from UData + //uprv_free(newInvUCA); + return; + } + + if(result != NULL) { /* It looks like sometimes we can fail to find the data file */ + newInvUCA = (InverseUCATableHeader *)udata_getMemory(result); + UCollator *UCA = ucol_initUCA(&status); + // UCA versions of UCA and inverse UCA should match + if(uprv_memcmp(newInvUCA->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0) { + status = U_INVALID_FORMAT_ERROR; + udata_close(result); + return; + } + + invUCA_DATA_MEM = result; + _staticInvUCA = newInvUCA; + } +} + + U_CAPI const InverseUCATableHeader * U_EXPORT2 ucol_initInverseUCA(UErrorCode *status) { - if(U_FAILURE(*status)) return NULL; - - UBool needsInit; - UMTX_CHECK(NULL, (_staticInvUCA == NULL), needsInit); - - if(needsInit) { - InverseUCATableHeader *newInvUCA = NULL; - UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, INVC_DATA_TYPE, INVC_DATA_NAME, isAcceptableInvUCA, NULL, status); - - if(U_FAILURE(*status)) { - if (result) { - udata_close(result); - } - // This is not needed, as we are talking about - // memory we got from UData - //uprv_free(newInvUCA); - } - - if(result != NULL) { /* It looks like sometimes we can fail to find the data file */ - newInvUCA = (InverseUCATableHeader *)udata_getMemory(result); - UCollator *UCA = ucol_initUCA(status); - // UCA versions of UCA and inverse UCA should match - if(uprv_memcmp(newInvUCA->UCAVersion, UCA->image->UCAVersion, sizeof(UVersionInfo)) != 0) { - *status = U_INVALID_FORMAT_ERROR; - udata_close(result); - return NULL; - } - - umtx_lock(NULL); - if(_staticInvUCA == NULL) { - invUCA_DATA_MEM = result; - _staticInvUCA = newInvUCA; - result = NULL; - newInvUCA = NULL; - } - umtx_unlock(NULL); - - if(newInvUCA != NULL) { - udata_close(result); - // This is not needed, as we are talking about - // memory we got from UData - //uprv_free(newInvUCA); - } - else { - ucln_i18n_registerCleanup(UCLN_I18N_UCOL_BLD, ucol_bld_cleanup); - } - } - } + umtx_initOnce(gStaticInvUCAInitOnce, &initInverseUCA, *status); return _staticInvUCA; } diff --git a/icu4c/source/i18n/ucol_res.cpp b/icu4c/source/i18n/ucol_res.cpp index 5ceb2c6cd33..853de6e08aa 100644 --- a/icu4c/source/i18n/ucol_res.cpp +++ b/icu4c/source/i18n/ucol_res.cpp @@ -44,6 +44,7 @@ #include "putilimp.h" #include "utracimp.h" #include "cmemory.h" +#include "uassert.h" #include "uenumimp.h" #include "ulist.h" @@ -54,6 +55,7 @@ static void ucol_setReorderCodesFromParser(UCollator *coll, UColTokenParser *par // static UCA. There is only one. Collators don't use it. // It is referenced only in ucol_initUCA and ucol_cleanup static UCollator* _staticUCA = NULL; +static UInitOnce gStaticUCAInitOnce = U_INITONCE_INITIALIZER; // static pointer to udata memory. Inited in ucol_initUCA // used for cleanup in ucol_cleanup static UDataMemory* UCA_DATA_MEM = NULL; @@ -70,6 +72,7 @@ ucol_res_cleanup(void) ucol_close(_staticUCA); _staticUCA = NULL; } + gStaticUCAInitOnce.reset(); return TRUE; } @@ -106,47 +109,35 @@ isAcceptableUCA(void * /*context*/, } U_CDECL_END +static void U_CALLCONV ucol_initStaticUCA(UErrorCode &status) { + U_ASSERT(_staticUCA == NULL); + U_ASSERT(UCA_DATA_MEM == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup); + + UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, &status); + if(U_FAILURE(status)){ + udata_close(result); + return; + } + + _staticUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, &status); + if(U_SUCCESS(status)){ + // Initalize variables for implicit generation + uprv_uca_initImplicitConstants(&status); + UCA_DATA_MEM = result; + + }else{ + ucol_close(_staticUCA); + _staticUCA = NULL; + udata_close(result); + } +} + + /* do not close UCA returned by ucol_initUCA! */ UCollator * ucol_initUCA(UErrorCode *status) { - if(U_FAILURE(*status)) { - return NULL; - } - UBool needsInit; - UMTX_CHECK(NULL, (_staticUCA == NULL), needsInit); - - if(needsInit) { - UDataMemory *result = udata_openChoice(U_ICUDATA_COLL, UCA_DATA_TYPE, UCA_DATA_NAME, isAcceptableUCA, NULL, status); - - if(U_SUCCESS(*status)){ - UCollator *newUCA = ucol_initCollator((const UCATableHeader *)udata_getMemory(result), NULL, NULL, status); - if(U_SUCCESS(*status)){ - // Initalize variables for implicit generation - uprv_uca_initImplicitConstants(status); - - umtx_lock(NULL); - if(_staticUCA == NULL) { - UCA_DATA_MEM = result; - _staticUCA = newUCA; - newUCA = NULL; - result = NULL; - } - umtx_unlock(NULL); - - ucln_i18n_registerCleanup(UCLN_I18N_UCOL_RES, ucol_res_cleanup); - if(newUCA != NULL) { - ucol_close(newUCA); - udata_close(result); - } - }else{ - ucol_close(newUCA); - udata_close(result); - } - } - else { - udata_close(result); - } - } + umtx_initOnce(gStaticUCAInitOnce, &ucol_initStaticUCA, *status); return _staticUCA; } @@ -155,6 +146,7 @@ ucol_forgetUCA(void) { _staticUCA = NULL; UCA_DATA_MEM = NULL; + gStaticUCAInitOnce.reset(); } /****************************************************************************/ diff --git a/icu4c/source/i18n/ucurr.cpp b/icu4c/source/i18n/ucurr.cpp index 2bd08026215..5e5c4e892d8 100644 --- a/icu4c/source/i18n/ucurr.cpp +++ b/icu4c/source/i18n/ucurr.cpp @@ -99,10 +99,8 @@ static const UChar CHOICE_FORMAT_MARK = 0x003D; // Equals sign static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0}; // ISO codes mapping table -static UHashtable* gIsoCodes = NULL; -static UBool gIsoCodesInitialized = FALSE; - -static UMutex gIsoCodesLock = U_MUTEX_INITIALIZER; +static const UHashtable* gIsoCodes = NULL; +static UInitOnce gIsoCodesInitOnce = U_INITONCE_INITIALIZER; //------------------------------------------------------------ // Code @@ -114,11 +112,10 @@ static UBool U_CALLCONV isoCodes_cleanup(void) { if (gIsoCodes != NULL) { - uhash_close(gIsoCodes); + uhash_close(const_cast(gIsoCodes)); gIsoCodes = NULL; } - gIsoCodesInitialized = FALSE; - + gIsoCodesInitOnce.reset(); return TRUE; } @@ -1227,6 +1224,8 @@ static CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL}; // It is a simple round-robin replacement strategy. static int8_t currentCacheEntryIndex = 0; +static UMutex gCurrencyCacheMutex = U_MUTEX_INITIALIZER; + // Cache deletion static void deleteCurrencyNames(CurrencyNameStruct* currencyNames, int32_t count) { @@ -1280,9 +1279,9 @@ uprv_parseCurrency(const char* locale, CurrencyNameStruct* currencySymbols = NULL; CurrencyNameCacheEntry* cacheEntry = NULL; - umtx_lock(NULL); + umtx_lock(&gCurrencyCacheMutex); // in order to handle racing correctly, - // not putting 'search' in a separate function and using UMTX. + // not putting 'search' in a separate function. int8_t found = -1; for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) { if (currCache[i]!= NULL && @@ -1299,13 +1298,13 @@ uprv_parseCurrency(const char* locale, total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; ++(cacheEntry->refCount); } - umtx_unlock(NULL); + umtx_unlock(&gCurrencyCacheMutex); if (found == -1) { collectCurrencyNames(locale, ¤cyNames, &total_currency_name_count, ¤cySymbols, &total_currency_symbol_count, ec); if (U_FAILURE(ec)) { return; } - umtx_lock(NULL); + umtx_lock(&gCurrencyCacheMutex); // check again. int8_t found = -1; for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) { @@ -1350,7 +1349,7 @@ uprv_parseCurrency(const char* locale, total_currency_symbol_count = cacheEntry->totalCurrencySymbolCount; ++(cacheEntry->refCount); } - umtx_unlock(NULL); + umtx_unlock(&gCurrencyCacheMutex); } int32_t start = pos.getIndex(); @@ -1394,12 +1393,12 @@ uprv_parseCurrency(const char* locale, } // decrease reference count - umtx_lock(NULL); + umtx_lock(&gCurrencyCacheMutex); --(cacheEntry->refCount); if (cacheEntry->refCount == 0) { // remove deleteCacheEntry(cacheEntry); } - umtx_unlock(NULL); + umtx_unlock(&gCurrencyCacheMutex); } @@ -1842,7 +1841,7 @@ ucurr_closeCurrencyList(UEnumeration *enumerator) { } static void U_CALLCONV -ucurr_createCurrencyList(UErrorCode* status){ +ucurr_createCurrencyList(UHashtable *isoCodes, UErrorCode* status){ UErrorCode localStatus = U_ZERO_ERROR; // Look up the CurrencyMap element in the root bundle. @@ -1908,7 +1907,7 @@ ucurr_createCurrencyList(UErrorCode* status){ entry->to = toDate; localStatus = U_ZERO_ERROR; - uhash_put(gIsoCodes, (UChar *)isoCode, entry, &localStatus); + uhash_put(isoCodes, (UChar *)isoCode, entry, &localStatus); } } else { *status = localStatus; @@ -1933,36 +1932,35 @@ static const UEnumeration gEnumCurrencyList = { }; U_CDECL_END + +static void U_CALLCONV initIsoCodes(UErrorCode &status) { + U_ASSERT(gIsoCodes == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); + + UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); + if (U_FAILURE(status)) { + return; + } + uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry); + + ucurr_createCurrencyList(isoCodes, &status); + if (U_FAILURE(status)) { + uhash_close(isoCodes); + return; + } + gIsoCodes = isoCodes; // Note: gIsoCodes is const. Once set up here it is never altered, + // and read only access is safe without synchronization. +} + + U_CAPI UBool U_EXPORT2 ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eErrorCode) { - UErrorCode status = U_ZERO_ERROR; - UBool initialized; - UMTX_CHECK(&gIsoCodesLock, gIsoCodesInitialized, initialized); - - if (!initialized) { - umtx_lock(&gIsoCodesLock); - gIsoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); - if (U_FAILURE(status)) { - umtx_unlock(&gIsoCodesLock); - return FALSE; - } - uhash_setValueDeleter(gIsoCodes, deleteIsoCodeEntry); - - ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup); - ucurr_createCurrencyList(&status); - if (U_FAILURE(status)) { - umtx_unlock(&gIsoCodesLock); - return FALSE; - } - - gIsoCodesInitialized = TRUE; - umtx_unlock(&gIsoCodesLock); + umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode); + if (U_FAILURE(*eErrorCode)) { + return FALSE; } - umtx_lock(&gIsoCodesLock); IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode); - umtx_unlock(&gIsoCodesLock); - if (result == NULL) { return FALSE; } else if (from > to) { @@ -1971,7 +1969,6 @@ ucurr_isAvailable(const UChar* isoCode, UDate from, UDate to, UErrorCode* eError } else if ((from > result->to) || (to < result->from)) { return FALSE; } - return TRUE; } diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index cbe559a7fd0..bcdff2d4834 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -59,6 +59,7 @@ class CurrencyPluralInfo; class Hashtable; class UnicodeSet; class FieldPositionHandler; +class DecimalFormatStaticSets; // explicit template instantiation. see digitlst.h #if defined (_MSC_VER) @@ -1882,15 +1883,15 @@ private: int32_t precision() const; /** - * Initialize all fields of a new DecimalFormatter. + * Initialize all fields of a new DecimalFormatter to a safe default value. * Common code for use by constructors. */ - void init(UErrorCode& status); + void init(); /** * Do real work of constructing a new DecimalFormat. */ - void construct(UErrorCode& status, + void construct(UErrorCode& status, UParseError& parseErr, const UnicodeString* pattern = 0, DecimalFormatSymbols* symbolsToAdopt = 0 @@ -2295,6 +2296,9 @@ private: UNumberFormatAttributeValue fParseAllInput; #endif + // Decimal Format Static Sets singleton. + const DecimalFormatStaticSets *fStaticSets; + protected: diff --git a/icu4c/source/i18n/unicode/gender.h b/icu4c/source/i18n/unicode/gender.h index 4b52ffdbafa..780c772c610 100644 --- a/icu4c/source/i18n/unicode/gender.h +++ b/icu4c/source/i18n/unicode/gender.h @@ -29,6 +29,9 @@ class GenderInfoTest; U_NAMESPACE_BEGIN +// Forward Declaration +void GenderInfo_initCache(UErrorCode &status); + /** * GenderInfo computes the gender of a list as a whole given the gender of * each element. @@ -96,7 +99,9 @@ private: static const GenderInfo* getMaleTaintsInstance(); static const GenderInfo* loadInstance(const Locale& locale, UErrorCode& status); + friend class ::GenderInfoTest; + friend void GenderInfo_initCache(UErrorCode &status); }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/unicode/gregocal.h b/icu4c/source/i18n/unicode/gregocal.h index f50cc82d54d..b92376aea03 100644 --- a/icu4c/source/i18n/unicode/gregocal.h +++ b/icu4c/source/i18n/unicode/gregocal.h @@ -767,53 +767,6 @@ public: * @return the beginning year of the default century */ virtual int32_t defaultCenturyStartYear() const; - - private: - /** - * The system maintains a static default century start date. This is initialized - * the first time it is used. Before then, it is set to SYSTEM_DEFAULT_CENTURY to - * indicate an uninitialized state. Once the system default century date and year - * are set, they do not change. - */ - static UDate fgSystemDefaultCenturyStart; - - /** - * See documentation for systemDefaultCenturyStart. - */ - static int32_t fgSystemDefaultCenturyStartYear; - - /** - * Default value that indicates the defaultCenturyStartYear is unitialized - */ - static const int32_t fgSystemDefaultCenturyYear; - - /** - * Default value that indicates the UDate of the beginning of the system default century - */ - static const UDate fgSystemDefaultCentury; - - /** - * Returns the beginning date of the 100-year window that dates with 2-digit years - * are considered to fall within. - * @return the beginning date of the 100-year window that dates with 2-digit years - * are considered to fall within. - */ - UDate internalGetDefaultCenturyStart(void) const; - - /** - * Returns the first year of the 100-year window that dates with 2-digit years - * are considered to fall within. - * @return the first year of the 100-year window that dates with 2-digit years - * are considered to fall within. - */ - int32_t internalGetDefaultCenturyStartYear(void) const; - - /** - * Initializes the 100-year window that dates with 2-digit years are considered - * to fall within so that its start date is 80 years before the current time. - */ - static void initializeSystemDefaultCentury(void); - }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/unicode/timezone.h b/icu4c/source/i18n/unicode/timezone.h index 6255c53c2d9..e0547566320 100644 --- a/icu4c/source/i18n/unicode/timezone.h +++ b/icu4c/source/i18n/unicode/timezone.h @@ -291,7 +291,11 @@ public: * Sets the default time zone (i.e., what's returned by createDefault()) to be the * specified time zone. If NULL is specified for the time zone, the default time * zone is set to the default host time zone. This call adopts the TimeZone object - * passed in; the clent is no longer responsible for deleting it. + * passed in; the client is no longer responsible for deleting it. + * + *

This function is not thread safe. It is an error for multiple threads + * to concurrently attempt to set the default time zone, or for any thread + * to attempt to reference the default zone while another thread is setting it. * * @param zone A pointer to the new TimeZone object to use as the default. * @stable ICU 2.0 @@ -303,6 +307,8 @@ public: * Same as adoptDefault(), except that the TimeZone object passed in is NOT adopted; * the caller remains responsible for deleting it. * + *

See the thread safety note under adoptDefault(). + * * @param zone The given timezone. * @system * @stable ICU 2.0 @@ -863,15 +869,18 @@ private: */ static const UChar* getRegion(const UnicodeString& id); + public: /** * Returns the region code associated with the given zone, * or NULL if the zone is not known. * @param id zone id string * @param status Status parameter * @return the region associated with the given zone + * @internal */ static const UChar* getRegion(const UnicodeString& id, UErrorCode& status); + private: /** * Parses the given custom time zone identifier * @param id id A string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or @@ -910,24 +919,6 @@ private: static UnicodeString& formatCustomID(int32_t hour, int32_t min, int32_t sec, UBool negative, UnicodeString& id); - /** - * Responsible for setting up DEFAULT_ZONE. Uses routines in TPlatformUtilities - * (i.e., platform-specific calls) to get the current system time zone. Failing - * that, uses the platform-specific default time zone. Failing that, uses GMT. - */ - static void initDefault(void); - - // See source file for documentation - /** - * Lookup the given name in our system zone table. If found, - * instantiate a new zone of that name and return it. If not - * found, return 0. - * @param name tthe given name of a system time zone. - * @return the TimeZone indicated by the 'name'. - */ - static TimeZone* createSystemTimeZone(const UnicodeString& name); - static TimeZone* createSystemTimeZone(const UnicodeString& name, UErrorCode& ec); - UnicodeString fID; // this time zone's ID friend class TZEnumeration; diff --git a/icu4c/source/i18n/uregex.cpp b/icu4c/source/i18n/uregex.cpp index 6c4ee7c5589..9763aac1e95 100644 --- a/icu4c/source/i18n/uregex.cpp +++ b/icu4c/source/i18n/uregex.cpp @@ -1,9 +1,9 @@ /* ******************************************************************************* -* Copyright (C) 2004-2012, International Business Machines +* Copyright (C) 2004-2013, International Business Machines * Corporation and others. All Rights Reserved. ******************************************************************************* -* file name: regex.cpp +* file name: uregex.cpp */ #include "unicode/utypes.h" @@ -35,7 +35,7 @@ public: ~RegularExpression(); int32_t fMagic; RegexPattern *fPat; - int32_t *fPatRefCount; + atomic_int32_t *fPatRefCount; UChar *fPatString; int32_t fPatStringLen; RegexMatcher *fMatcher; @@ -65,7 +65,7 @@ RegularExpression::~RegularExpression() { if (fPatRefCount!=NULL && umtx_atomic_dec(fPatRefCount)==0) { delete fPat; uprv_free(fPatString); - uprv_free(fPatRefCount); + uprv_free((void *)fPatRefCount); } if (fOwnsText && fText!=NULL) { uprv_free((void *)fText); @@ -122,13 +122,13 @@ uregex_open( const UChar *pattern, actualPatLen = u_strlen(pattern); } - RegularExpression *re = new RegularExpression; - int32_t *refC = (int32_t *)uprv_malloc(sizeof(int32_t)); + RegularExpression *re = new RegularExpression; + atomic_int32_t *refC = (atomic_int32_t *)uprv_malloc(sizeof(int32_t)); UChar *patBuf = (UChar *)uprv_malloc(sizeof(UChar)*(actualPatLen+1)); if (re == NULL || refC == NULL || patBuf == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; delete re; - uprv_free(refC); + uprv_free((void *)refC); uprv_free(patBuf); return NULL; } @@ -207,12 +207,12 @@ uregex_openUText(UText *pattern, UErrorCode lengthStatus = U_ZERO_ERROR; int32_t pattern16Length = utext_extract(pattern, 0, patternNativeLength, NULL, 0, &lengthStatus); - int32_t *refC = (int32_t *)uprv_malloc(sizeof(int32_t)); + atomic_int32_t *refC = (atomic_int32_t *)uprv_malloc(sizeof(int32_t)); UChar *patBuf = (UChar *)uprv_malloc(sizeof(UChar)*(pattern16Length+1)); if (re == NULL || refC == NULL || patBuf == NULL) { *status = U_MEMORY_ALLOCATION_ERROR; delete re; - uprv_free(refC); + uprv_free((void *)refC); uprv_free(patBuf); return NULL; } diff --git a/icu4c/source/i18n/uspoof_impl.h b/icu4c/source/i18n/uspoof_impl.h index dc9dda9da0f..0621bd00791 100644 --- a/icu4c/source/i18n/uspoof_impl.h +++ b/icu4c/source/i18n/uspoof_impl.h @@ -242,7 +242,7 @@ class SpoofData: public UMemory { // we are done. uint32_t fMemLimit; // Limit of available raw data space - int32_t fRefCount; + atomic_int32_t fRefCount; // Confusable data int32_t *fCFUKeys; diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp index 522c3f04990..3851ff17588 100644 --- a/icu4c/source/i18n/zonemeta.cpp +++ b/icu4c/source/i18n/zonemeta.cpp @@ -31,21 +31,21 @@ static UMutex gZoneMetaLock = U_MUTEX_INITIALIZER; // CLDR Canonical ID mapping table static UHashtable *gCanonicalIDCache = NULL; -static UBool gCanonicalIDCacheInitialized = FALSE; +static UInitOnce gCanonicalIDCacheInitOnce = U_INITONCE_INITIALIZER; // Metazone mapping table static UHashtable *gOlsonToMeta = NULL; -static UBool gOlsonToMetaInitialized = FALSE; +static UInitOnce gOlsonToMetaInitOnce = U_INITONCE_INITIALIZER; // Available metazone IDs vector and table static icu::UVector *gMetaZoneIDs = NULL; static UHashtable *gMetaZoneIDTable = NULL; -static UBool gMetaZoneIDsInitialized = FALSE; +static UInitOnce gMetaZoneIDsInitOnce = U_INITONCE_INITIALIZER; // Country info vectors static icu::UVector *gSingleZoneCountries = NULL; static icu::UVector *gMultiZonesCountries = NULL; -static UBool gCountryInfoVectorsInitialized = FALSE; +static UInitOnce gCountryInfoVectorsInitOnce = U_INITONCE_INITIALIZER; U_CDECL_BEGIN @@ -58,25 +58,29 @@ static UBool U_CALLCONV zoneMeta_cleanup(void) uhash_close(gCanonicalIDCache); gCanonicalIDCache = NULL; } - gCanonicalIDCacheInitialized = FALSE; + gCanonicalIDCacheInitOnce.reset(); if (gOlsonToMeta != NULL) { uhash_close(gOlsonToMeta); gOlsonToMeta = NULL; } - gOlsonToMetaInitialized = FALSE; + gOlsonToMetaInitOnce.reset(); if (gMetaZoneIDTable != NULL) { uhash_close(gMetaZoneIDTable); + gMetaZoneIDTable = NULL; } // delete after closing gMetaZoneIDTable, because it holds // value objects held by the hashtable delete gMetaZoneIDs; - gMetaZoneIDsInitialized = FALSE; + gMetaZoneIDs = NULL; + gMetaZoneIDsInitOnce.reset(); delete gSingleZoneCountries; + gSingleZoneCountries = NULL; delete gMultiZonesCountries; - gCountryInfoVectorsInitialized = FALSE; + gMultiZonesCountries = NULL; + gCountryInfoVectorsInitOnce.reset(); return TRUE; } @@ -212,6 +216,19 @@ parseDate (const UChar *text, UErrorCode &status) { return 0; } +static void U_CALLCONV initCanonicalIDCache(UErrorCode &status) { + gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); + if (gCanonicalIDCache == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } + if (U_FAILURE(status)) { + gCanonicalIDCache = NULL; + } + // No key/value deleters - keys/values are from a resource bundle + ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); +} + + const UChar* U_EXPORT2 ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { if (U_FAILURE(status)) { @@ -225,27 +242,9 @@ ZoneMeta::getCanonicalCLDRID(const UnicodeString &tzid, UErrorCode& status) { } // Checking the cached results - UBool initialized; - UMTX_CHECK(&gZoneMetaLock, gCanonicalIDCacheInitialized, initialized); - if (!initialized) { - // Create empty hashtable - umtx_lock(&gZoneMetaLock); - { - if (!gCanonicalIDCacheInitialized) { - gCanonicalIDCache = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); - if (gCanonicalIDCache == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } - if (U_FAILURE(status)) { - gCanonicalIDCache = NULL; - return NULL; - } - // No key/value deleters - keys/values are from a resource bundle - gCanonicalIDCacheInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); - } - } - umtx_unlock(&gZoneMetaLock); + umtx_initOnce(gCanonicalIDCacheInitOnce, &initCanonicalIDCache, status); + if (U_FAILURE(status)) { + return NULL; } const UChar *canonicalID = NULL; @@ -393,6 +392,28 @@ ZoneMeta::getCanonicalCLDRID(const TimeZone& tz) { return getCanonicalCLDRID(tz.getID(tzID), status); } +static void U_CALLCONV countryInfoVectorsInit(UErrorCode &status) { + // Create empty vectors + // No deleters for these UVectors, it's a reference to a resource bundle string. + gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status); + if (gSingleZoneCountries == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } + gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status); + if (gMultiZonesCountries == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + } + + if (U_FAILURE(status)) { + delete gSingleZoneCountries; + delete gMultiZonesCountries; + gSingleZoneCountries = NULL; + gMultiZonesCountries = NULL; + } + ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); +} + + UnicodeString& U_EXPORT2 ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &country, UBool *isPrimary /* = NULL */) { if (isPrimary != NULL) { @@ -412,39 +433,9 @@ ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &country, // Checking the cached results UErrorCode status = U_ZERO_ERROR; - UBool initialized; - UMTX_CHECK(&gZoneMetaLock, gCountryInfoVectorsInitialized, initialized); - if (!initialized) { - // Create empty vectors - umtx_lock(&gZoneMetaLock); - { - if (!gCountryInfoVectorsInitialized) { - // No deleters for these UVectors, it's a reference to a resource bundle string. - gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status); - if (gSingleZoneCountries == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } - gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status); - if (gMultiZonesCountries == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } - - if (U_SUCCESS(status)) { - gCountryInfoVectorsInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); - } else { - delete gSingleZoneCountries; - delete gMultiZonesCountries; - } - } - } - umtx_unlock(&gZoneMetaLock); - - if (U_FAILURE(status)) { - return country; - } - U_ASSERT(gSingleZoneCountries != NULL); - U_ASSERT(gMultiZonesCountries != NULL); + umtx_initOnce(gCountryInfoVectorsInitOnce, &countryInfoVectorsInit, status); + if (U_FAILURE(status)) { + return country; } // Check if it was already cached @@ -546,6 +537,19 @@ ZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &re return result; } +static void U_CALLCONV olsonToMetaInit(UErrorCode &status) { + U_ASSERT(gOlsonToMeta == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); + gOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); + if (U_FAILURE(status)) { + gOlsonToMeta = NULL; + } else { + uhash_setKeyDeleter(gOlsonToMeta, deleteUCharString); + uhash_setValueDeleter(gOlsonToMeta, deleteUVector); + } +} + + const UVector* U_EXPORT2 ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) { UErrorCode status = U_ZERO_ERROR; @@ -555,31 +559,9 @@ ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) { return NULL; } - UBool initialized; - UMTX_CHECK(&gZoneMetaLock, gOlsonToMetaInitialized, initialized); - if (!initialized) { - UHashtable *tmpOlsonToMeta = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status); - if (U_FAILURE(status)) { - return NULL; - } - uhash_setKeyDeleter(tmpOlsonToMeta, deleteUCharString); - uhash_setValueDeleter(tmpOlsonToMeta, deleteUVector); - - umtx_lock(&gZoneMetaLock); - { - if (!gOlsonToMetaInitialized) { - gOlsonToMeta = tmpOlsonToMeta; - tmpOlsonToMeta = NULL; - gOlsonToMetaInitialized = TRUE; - } - } - umtx_unlock(&gZoneMetaLock); - - // OK to call the following multiple times with the same function - ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); - if (tmpOlsonToMeta != NULL) { - uhash_close(tmpOlsonToMeta); - } + umtx_initOnce(gOlsonToMetaInitOnce, &olsonToMetaInit, status); + if (U_FAILURE(status)) { + return NULL; } // get the mapping from cache @@ -773,86 +755,79 @@ ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &re return result; } -void -ZoneMeta::initAvailableMetaZoneIDs () { - UBool initialized; - UMTX_CHECK(&gZoneMetaLock, gMetaZoneIDsInitialized, initialized); - if (!initialized) { - umtx_lock(&gZoneMetaLock); - { - if (!gMetaZoneIDsInitialized) { - UErrorCode status = U_ZERO_ERROR; - UHashtable *metaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status); - uhash_setKeyDeleter(metaZoneIDTable, uprv_deleteUObject); - // No valueDeleter, because the vector maintain the value objects - UVector *metaZoneIDs = NULL; - if (U_SUCCESS(status)) { - metaZoneIDs = new UVector(NULL, uhash_compareUChars, status); - if (metaZoneIDs == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - } - } else { - uhash_close(metaZoneIDTable); - } - if (U_SUCCESS(status)) { - U_ASSERT(metaZoneIDs != NULL); - metaZoneIDs->setDeleter(uprv_free); +static void U_CALLCONV initAvailableMetaZoneIDs () { + U_ASSERT(gMetaZoneIDs == NULL); + U_ASSERT(gMetaZoneIDTable == NULL); + ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); - UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status); - UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status); - UResourceBundle res; - ures_initStackObject(&res); - while (U_SUCCESS(status) && ures_hasNext(bundle)) { - ures_getNextResource(bundle, &res, &status); - if (U_FAILURE(status)) { - break; - } - const char *mzID = ures_getKey(&res); - int32_t len = uprv_strlen(mzID); - UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1)); - if (uMzID == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - break; - } - u_charsToUChars(mzID, uMzID, len); - uMzID[len] = 0; - UnicodeString *usMzID = new UnicodeString(uMzID); - if (uhash_get(metaZoneIDTable, usMzID) == NULL) { - metaZoneIDs->addElement((void *)uMzID, status); - uhash_put(metaZoneIDTable, (void *)usMzID, (void *)uMzID, &status); - } else { - uprv_free(uMzID); - delete usMzID; - } - } - if (U_SUCCESS(status)) { - gMetaZoneIDs = metaZoneIDs; - gMetaZoneIDTable = metaZoneIDTable; - gMetaZoneIDsInitialized = TRUE; - ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); - } else { - uhash_close(metaZoneIDTable); - delete metaZoneIDs; - } - ures_close(&res); - ures_close(bundle); - ures_close(rb); - } - } + UErrorCode status = U_ZERO_ERROR; + gMetaZoneIDTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status); + if (U_FAILURE(status) || gMetaZoneIDTable == NULL) { + gMetaZoneIDTable = NULL; + return; + } + uhash_setKeyDeleter(gMetaZoneIDTable, uprv_deleteUObject); + // No valueDeleter, because the vector maintain the value objects + gMetaZoneIDs = new UVector(NULL, uhash_compareUChars, status); + if (U_FAILURE(status) || gMetaZoneIDs == NULL) { + gMetaZoneIDs = NULL; + uhash_close(gMetaZoneIDTable); + gMetaZoneIDTable = NULL; + return; + } + gMetaZoneIDs->setDeleter(uprv_free); + + UResourceBundle *rb = ures_openDirect(NULL, gMetaZones, &status); + UResourceBundle *bundle = ures_getByKey(rb, gMapTimezonesTag, NULL, &status); + UResourceBundle res; + ures_initStackObject(&res); + while (U_SUCCESS(status) && ures_hasNext(bundle)) { + ures_getNextResource(bundle, &res, &status); + if (U_FAILURE(status)) { + break; } - umtx_unlock(&gZoneMetaLock); + const char *mzID = ures_getKey(&res); + int32_t len = uprv_strlen(mzID); + UChar *uMzID = (UChar*)uprv_malloc(sizeof(UChar) * (len + 1)); + if (uMzID == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } + u_charsToUChars(mzID, uMzID, len); + uMzID[len] = 0; + UnicodeString *usMzID = new UnicodeString(uMzID); + if (uhash_get(gMetaZoneIDTable, usMzID) == NULL) { + gMetaZoneIDs->addElement((void *)uMzID, status); + uhash_put(gMetaZoneIDTable, (void *)usMzID, (void *)uMzID, &status); + } else { + uprv_free(uMzID); + delete usMzID; + } + } + ures_close(&res); + ures_close(bundle); + ures_close(rb); + + if (U_FAILURE(status)) { + uhash_close(gMetaZoneIDTable); + delete gMetaZoneIDs; + gMetaZoneIDTable = NULL; + gMetaZoneIDs = NULL; } } const UVector* ZoneMeta::getAvailableMetazoneIDs() { - initAvailableMetaZoneIDs(); + umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs); return gMetaZoneIDs; } const UChar* ZoneMeta::findMetaZoneID(const UnicodeString& mzid) { - initAvailableMetaZoneIDs(); + umtx_initOnce(gMetaZoneIDsInitOnce, &initAvailableMetaZoneIDs); + if (gMetaZoneIDTable == NULL) { + return NULL; + } return (const UChar*)uhash_get(gMetaZoneIDTable, &mzid); } diff --git a/icu4c/source/i18n/zonemeta.h b/icu4c/source/i18n/zonemeta.h index 3c4218276ac..ac65e82acbc 100644 --- a/icu4c/source/i18n/zonemeta.h +++ b/icu4c/source/i18n/zonemeta.h @@ -109,7 +109,6 @@ public: private: ZoneMeta(); // Prevent construction. static UVector* createMetazoneMappings(const UnicodeString &tzid); - static void initAvailableMetaZoneIDs(); static UnicodeString& formatCustomID(uint8_t hour, uint8_t min, uint8_t sec, UBool negative, UnicodeString& id); static const UChar* getShortIDFromCanonical(const UChar* canonicalID); };