]> granicus.if.org Git - icu/commitdiff
ICU-10051 Mutexes: introduce UInitOnce; remove UMTX_CHECK; replace all uses of UMTX_C...
authorAndy Heninger <andy.heninger@gmail.com>
Fri, 31 May 2013 23:50:15 +0000 (23:50 +0000)
committerAndy Heninger <andy.heninger@gmail.com>
Fri, 31 May 2013 23:50:15 +0000 (23:50 +0000)
X-SVN-Rev: 33787

51 files changed:
icu4c/source/i18n/buddhcal.cpp
icu4c/source/i18n/buddhcal.h
icu4c/source/i18n/calendar.cpp
icu4c/source/i18n/chnsecal.cpp
icu4c/source/i18n/chnsecal.h
icu4c/source/i18n/coll.cpp
icu4c/source/i18n/coptccal.cpp
icu4c/source/i18n/coptccal.h
icu4c/source/i18n/csdetect.cpp
icu4c/source/i18n/dangical.cpp
icu4c/source/i18n/decfmtst.cpp
icu4c/source/i18n/decfmtst.h
icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/ethpccal.cpp
icu4c/source/i18n/ethpccal.h
icu4c/source/i18n/gender.cpp
icu4c/source/i18n/gregocal.cpp
icu4c/source/i18n/hebrwcal.cpp
icu4c/source/i18n/hebrwcal.h
icu4c/source/i18n/i18n.vcxproj
icu4c/source/i18n/islamcal.cpp
icu4c/source/i18n/islamcal.h
icu4c/source/i18n/numfmt.cpp
icu4c/source/i18n/olsontz.cpp
icu4c/source/i18n/olsontz.h
icu4c/source/i18n/persncal.cpp
icu4c/source/i18n/persncal.h
icu4c/source/i18n/rbt.cpp
icu4c/source/i18n/rbtz.cpp
icu4c/source/i18n/regexst.cpp
icu4c/source/i18n/simpletz.cpp
icu4c/source/i18n/smpdtfst.cpp
icu4c/source/i18n/smpdtfst.h
icu4c/source/i18n/taiwncal.cpp
icu4c/source/i18n/taiwncal.h
icu4c/source/i18n/timezone.cpp
icu4c/source/i18n/tzfmt.cpp
icu4c/source/i18n/tzgnames.cpp
icu4c/source/i18n/tznames.cpp
icu4c/source/i18n/tznames_impl.cpp
icu4c/source/i18n/ucol_bld.cpp
icu4c/source/i18n/ucol_res.cpp
icu4c/source/i18n/ucurr.cpp
icu4c/source/i18n/unicode/decimfmt.h
icu4c/source/i18n/unicode/gender.h
icu4c/source/i18n/unicode/gregocal.h
icu4c/source/i18n/unicode/timezone.h
icu4c/source/i18n/uregex.cpp
icu4c/source/i18n/uspoof_impl.h
icu4c/source/i18n/zonemeta.cpp
icu4c/source/i18n/zonemeta.h

index d61f68810dad55d26661db0b3b323c823a1b2027..a4fa7b66f1d0fbd856ff104ec94967c49a4b0c16 100644 (file)
@@ -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
 
index 735f61890a7b617f8cb33b8d56cc07fdfbab8b50..6b6befd39a51d06c74804eb838bee1476d036e12 100644 (file)
@@ -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
index 8cf95671e7797d413e672b15377fed875264cc54..238b4d6c67ac8269c8266ad041702f6b709fe109 100644 (file)
@@ -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 ICULocaleService* 
-getCalendarService(UErrorCode &status)
+static void U_CALLCONV
+initCalendarService(UErrorCode &status)
 {
-    UBool needInit;
-    UMTX_CHECK(NULL, (UBool)(gService == NULL), needInit);
-    if (needInit) {
 #ifdef U_DEBUG_CALSVC
-        fprintf(stderr, "Spinning up Calendar Service\n");
+    fprintf(stderr, "Spinning up Calendar Service\n");
 #endif
-        ICULocaleService * newservice = new CalendarService();
-        if (newservice == NULL) {
-            status = U_MEMORY_ALLOCATION_ERROR;
-            return newservice;
-        }
+    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");
+    fprintf(stderr, "Registering classes..\n");
 #endif
 
-        // Register all basic instances. 
-        newservice->registerFactory(new BasicCalendarFactory(),status);
+    // Register all basic instances. 
+    gService->registerFactory(new BasicCalendarFactory(),status);
 
 #ifdef U_DEBUG_CALSVC
-        fprintf(stderr, "Done..\n");
+    fprintf(stderr, "Done..\n");
 #endif
 
-        if(U_FAILURE(status)) {
+    if(U_FAILURE(status)) {
 #ifdef U_DEBUG_CALSVC
-            fprintf(stderr, "err (%s) registering classes, deleting service.....\n", u_errorName(status));
+        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);
-        }
+        delete gService;
+        gService = NULL;
     }
+}
+
+static ICULocaleService* 
+getCalendarService(UErrorCode &status)
+{
+    umtx_initOnce(gServiceInitOnce, &initCalendarService, status);
     return gService;
 }
 
+
 URegistryKey Calendar::registerFactory(ICUServiceFactory* toAdopt, UErrorCode& status)
 {
     return getCalendarService(status)->registerFactory(toAdopt, status);
index 16a3c9a061bd4490136a2d4699705dbfb71fd00b..c32b0611c67e962cdf58173c7bfef564db35168c 100644 (file)
@@ -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
index 7d0e2a1fc8a7688da0cf593845f34ed2487c11d7..ac14a679eee2132957785d5866665d51b019a4b1 100644 (file)
@@ -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
 };
 
index 9e9ca0239d0a269641120420a7f0e68512b793e1..c12f9d4e2cfb3a3f11e515efe8b3319cecb022cb 100644 (file)
@@ -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;
-        
-        ures_initStackObject(&installed);
-        index = ures_openDirect(U_ICUDATA_COLL, "res_index", &status);
-        ures_getByKey(index, "InstalledLocales", &installed, &status);
+    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];
         
-        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) 
index 84bbad797eae597a4cfcd69e994a8d84da383081..9b19e8adbf7ad6c9f7e17f0b8b7b84a8663c73b9 100644 (file)
@@ -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
 {
index f42230dff4cdfdafec9daa4582edb3a08987dde4..5d2e306c632e4df6d9a1448492a49df3680c55ef 100644 (file)
@@ -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:
     /**
index 3ad7136f87854f7ea788fd4d0981923ce73ce00c..415c85421dbd2b82cb8c3575715c7d3a5fd1d00f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  **********************************************************************
- *   Copyright (C) 2005-2012, International Business Machines
+ *   Copyright (C) 2005-2013, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  **********************************************************************
  */
 #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)
index 489821baf604a29635172975e1b953f0b89be686..94e1458b8d00464d0dca25f9530a8acb7073fb0d 100644 (file)
 
 #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
index c991c0098e0f75e9d2da1d3d171e21b0f8058b6f..c9df897e1a465d1454dad8b0d052d607edbd95bd 100644 (file)
@@ -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;
 }
-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);
+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
+
+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;
     }
index 16c5b7c950ed610c85e4a10190ed4a44f64e98fd..e3208421d6199310a6eaa35e2353dd7daebf3cf7 100644 (file)
@@ -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);
 
index e1499478bef0d85e950f64b20d6efade6ef85584..cf8f2a8ed5bc8f9e912274ddce39ee4d3dd418ae 100644 (file)
@@ -269,7 +269,7 @@ inline int32_t _max(int32_t a, int32_t b) { return (a<b) ? b : a; }
 // Constructs a DecimalFormat instance in the default locale.
 
 DecimalFormat::DecimalFormat(UErrorCode& status) {
-    init(status);
+    init();
     UParseError parseError;
     construct(status, parseError);
 }
@@ -280,7 +280,7 @@ DecimalFormat::DecimalFormat(UErrorCode& status) {
 
 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
                              UErrorCode& status) {
-    init(status);
+    init();
     UParseError parseError;
     construct(status, parseError, &pattern);
 }
@@ -293,7 +293,7 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern,
 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
                              DecimalFormatSymbols* symbolsToAdopt,
                              UErrorCode& status) {
-    init(status);
+    init();
     UParseError parseError;
     if (symbolsToAdopt == NULL)
         status = U_ILLEGAL_ARGUMENT_ERROR;
@@ -304,7 +304,7 @@ DecimalFormat::DecimalFormat(  const UnicodeString& pattern,
                     DecimalFormatSymbols* symbolsToAdopt,
                     UParseError& parseErr,
                     UErrorCode& status) {
-    init(status);
+    init();
     if (symbolsToAdopt == NULL)
         status = U_ILLEGAL_ARGUMENT_ERROR;
     construct(status,parseErr, &pattern, symbolsToAdopt);
@@ -318,7 +318,7 @@ DecimalFormat::DecimalFormat(  const UnicodeString& pattern,
 DecimalFormat::DecimalFormat(const UnicodeString& pattern,
                              const DecimalFormatSymbols& symbols,
                              UErrorCode& status) {
-    init(status);
+    init();
     UParseError parseError;
     construct(status, parseError, &pattern, new DecimalFormatSymbols(symbols));
 }
@@ -332,7 +332,7 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern,
                              DecimalFormatSymbols* symbolsToAdopt,
                              UNumberFormatStyle style,
                              UErrorCode& status) {
-    init(status);
+    init();
     fStyle = style;
     UParseError parseError;
     construct(status, parseError, &pattern, symbolsToAdopt);
@@ -342,8 +342,10 @@ DecimalFormat::DecimalFormat(const UnicodeString& pattern,
 // Common DecimalFormat initialization.
 //    Put all fields of an uninitialized object into a known state.
 //    Common code, shared by all constructors.
+//    Can not fail. Leave the object in good enough shape that the destructor
+//    or assignment operator can run successfully.
 void
-DecimalFormat::init(UErrorCode &status) {
+DecimalFormat::init() {
     fPosPrefixPattern = 0;
     fPosSuffixPattern = 0;
     fNegPrefixPattern = 0;
@@ -382,8 +384,7 @@ DecimalFormat::init(UErrorCode &status) {
     data.fFastFormatStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
     data.fFastParseStatus=kFastpathUNKNOWN; // don't try to calculate the fastpath until later.
 #endif
-    // only do this once per obj.
-    DecimalFormatStaticSets::initSets(&status);
+    fStaticSets = NULL;
 }
 
 //------------------------------------------------------------------------------
@@ -392,7 +393,7 @@ DecimalFormat::init(UErrorCode &status) {
 // created instance owns the symbols.
 
 void
-DecimalFormat::construct(UErrorCode&             status,
+DecimalFormat::construct(UErrorCode&            status,
                          UParseError&           parseErr,
                          const UnicodeString*   pattern,
                          DecimalFormatSymbols*  symbolsToAdopt)
@@ -417,12 +418,15 @@ DecimalFormat::construct(UErrorCode&             status,
     if (fSymbols == NULL)
     {
         fSymbols = new DecimalFormatSymbols(Locale::getDefault(), status);
-        /* test for NULL */
         if (fSymbols == 0) {
             status = U_MEMORY_ALLOCATION_ERROR;
             return;
         }
     }
+    fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
+    if (U_FAILURE(status)) {
+        return;
+    }
     UErrorCode nsStatus = U_ZERO_ERROR;
     NumberingSystem *ns = NumberingSystem::createInstance(nsStatus);
     if (U_FAILURE(nsStatus)) {
@@ -695,8 +699,7 @@ DecimalFormat::~DecimalFormat()
 
 DecimalFormat::DecimalFormat(const DecimalFormat &source) :
     NumberFormat(source) {
-    UErrorCode status = U_ZERO_ERROR;
-    init(status); // if this fails, 'source' isn't initialized properly either.
+    init();
     *this = source;
 }
 
@@ -729,7 +732,9 @@ DecimalFormat&
 DecimalFormat::operator=(const DecimalFormat& rhs)
 {
     if(this != &rhs) {
+        UErrorCode status = U_ZERO_ERROR;
         NumberFormat::operator=(rhs);
+        fStaticSets     = DecimalFormatStaticSets::getStaticSets(status);
         fPositivePrefix = rhs.fPositivePrefix;
         fPositiveSuffix = rhs.fPositiveSuffix;
         fNegativePrefix = rhs.fNegativePrefix;
@@ -2432,9 +2437,9 @@ UBool DecimalFormat::subparse(const UnicodeString& text,
 
         if (groupingCharLength == groupingStringLength) {
             if (strictParse) {
-                groupingSet = DecimalFormatStaticSets::gStaticSets->fStrictDefaultGroupingSeparators;
+                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);
index 9317dead0ae6ef28fe41f9e7f5ee3af41b59411e..dd386025c644ae1759f348ed128931de33130d6b 100644 (file)
@@ -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
index 01db826a79fe694de5544ecbbe9e44d249068209..6aba6828f20c2df400ecd77a703ddfdca5809ba9 100644 (file)
@@ -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
index 4eac9e17740ed542d95ce5b71ddfdb17a5e4ca61..8e6e0d15bfd4505fbfc4495481e8a4d01bc49b62 100644 (file)
@@ -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();
   {
index c2a635a87d1faed6148c35a7864528cfd28697dc..9e00b4266b94044dec1b7ba49fed81b1886d9879 100644 (file)
@@ -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
 
index 12e850a593b5be69e77e55d09bff98aa27443bea..cdd76953830520b103e9e2011b52738003fd2f42 100644 (file)
@@ -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
index 76f100fea951b52aa27c0a11492f883d06904376..50c86364634d0ab6878c4fd3fee2d33332ce9dc9 100644 (file)
@@ -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.
index 020fcf962186ddb6c2646a7f4a7d651fb4f5c19f..0b3598e8f2175aec6a7645bf197e43a4015cc8c9 100644 (file)
@@ -91,7 +91,7 @@
       <StringPooling>true</StringPooling>\r
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
       <FunctionLevelLinking>true</FunctionLevelLinking>\r
-      <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+      <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
       <PrecompiledHeaderOutputFile>.\x86\Release/i18n.pch</PrecompiledHeaderOutputFile>\r
       <AssemblerListingLocation>.\x86\Release/</AssemblerListingLocation>\r
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
       <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+      <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
       <PrecompiledHeaderOutputFile>.\x86\Debug/i18n.pch</PrecompiledHeaderOutputFile>\r
       <AssemblerListingLocation>.\x86\Debug/</AssemblerListingLocation>\r
       <StringPooling>true</StringPooling>\r
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\r
       <FunctionLevelLinking>true</FunctionLevelLinking>\r
-      <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+      <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
       <PrecompiledHeaderOutputFile>.\x64\Release/i18n.pch</PrecompiledHeaderOutputFile>\r
       <AssemblerListingLocation>.\x64\Release/</AssemblerListingLocation>\r
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
       <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\r
       <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <DisableLanguageExtensions>true</DisableLanguageExtensions>\r
+      <DisableLanguageExtensions>false</DisableLanguageExtensions>\r
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
       <PrecompiledHeaderOutputFile>.\x64\Debug/i18n.pch</PrecompiledHeaderOutputFile>\r
       <AssemblerListingLocation>.\x64\Debug/</AssemblerListingLocation>\r
index 6d553787da3b188f97681b6c1a247c55b5a57ff0..ea8e1013a212b0433deebf024bb8d4268e9b0955 100644 (file)
@@ -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
index e3647bc0ffd5442ecbd5f9abf65d9be33776e4a3..b9c964cfadf0808f1886f0976257c2a5163b81a6 100644 (file)
@@ -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
index 8c08c1742e532741c44bae42791ab3705e80b8e3..922bc2fffa67d21cf81cca39ae58ca38e18b3172 100644 (file)
@@ -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);
-        }
+    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<NumberingSystem> 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));
index a39a4e6cf1da6ce27058872bdbd5fa7db2b86eed..244876b065b2409d25946ed83023667788fe8eae 100644 (file)
@@ -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<OlsonTimeZone*>(this);
-            ncThis->initTransitionRules(status);
-        }
-        umtx_unlock(&gLock);
-    }
+    OlsonTimeZone *ncThis = const_cast<OlsonTimeZone *>(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
index a263ec05aa4f799bc6387ce173b81f943f4c59d0..17409abf20cae51d4b6df2108257077f1119590c 100644 (file)
@@ -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
index 957db9c08a7cf82401f1cdc07ade1e3d47b0f70f..60afeb4eb9ee44d68157293536844f2f82c463e9 100644 (file)
@@ -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
index b926da5ef25fe78df9aa71506c784c8883686992..e6be055e68a8bc7b444c60853d105453f7e0c290 100644 (file)
@@ -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
index b987ade2c7257b0af0b7839ae8e93a29b24345da..beb6067b943f196fa04bba555cbb53b45b9a610f 100644 (file)
@@ -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;
index 6abc6d1e6516e9af0cf21422787e25dd7e2c0fde..5f3addce313101a20e5f298a42b5489203cbd2e3 100644 (file)
@@ -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<RuleBasedTimeZone*>(this);
-            ncThis->complete(status);
-        }
-        umtx_unlock(&gLock);
+    umtx_lock(&gLock);
+    if (!fUpToDate) {
+        RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
+        ncThis->complete(status);
     }
+    umtx_unlock(&gLock);
 }
 
 void
index d86524990916dbc769d7ba1d06e1b02148f07a33..fa61c3de401ead00bc3992f4435057cebdd6e0c2 100644 (file)
@@ -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();
 }
-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);
+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) {
+    umtx_initOnce(gStaticSetsInitOnce, &initStaticSets, *status);
+}
 
 U_NAMESPACE_END
 #endif  // !UCONFIG_NO_REGULAR_EXPRESSIONS
index 2faa55893b93c3bd945d8228b08c7bd3891c2c4d..dc8defabcecd663d42604a7cc4269cb0977f498f 100644 (file)
@@ -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<SimpleTimeZone*>(this);
-            ncThis->initTransitionRules(status);
-        }
-        umtx_unlock(&gLock);
+    umtx_lock(&gLock);
+    if (!transitionRulesInitialized) {
+        SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
+        ncThis->initTransitionRules(status);
     }
+    umtx_unlock(&gLock);
 }
 
 void
index 2e138b84fb8a6be6fb3b1c23a31163bf52af27ad..8bbcea199ab0496c10ad1d13a0b16f3432294fac 100644 (file)
@@ -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"
 
 
 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
index 48a2c6cdc26945be0a5c441993a2ee538ac9087d..153e007f1577a6389d8e3d93103c2369db3a8e6b 100644 (file)
@@ -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);
index 4a895251df7b6dc98d2071836469d96f350b10b2..0b244fe3b366251d6b12031b6f79cafb0f567c89 100644 (file)
@@ -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
 
index fe6f89b1902ac2cbf0e58b3015957d01ec4fe702..8bd0b5ce2d652ebc9869909b180fe56e5e752069 100644 (file)
@@ -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
index 34e03a9d8b7590d18ceda9ed0137b6830d9b503e..aaecff7b27e3c66fb72db4c9d6407354c5d9cb4e 100644 (file)
@@ -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.
- */
-TimeZone*
-TimeZone::createSystemTimeZone(const UnicodeString& id) {
-    UErrorCode ec = U_ZERO_ERROR;
-    return createSystemTimeZone(id, ec);
-}
-
+namespace {
 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());
 }
 
-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);
+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;
-            }
-            umtx_lock(&LOCK);
-            if (!TZDataVersionInitialized) {
-                u_UCharsToChars(tzver, TZDATA_VERSION, len);
-                TZDataVersionInitialized = TRUE;
-            }
-            umtx_unlock(&LOCK);
-            ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
+    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;
         }
-
-        ures_close(bundle);
-    }
-    if (U_FAILURE(status)) {
-        return NULL;
+        u_UCharsToChars(tzver, TZDATA_VERSION, len);
     }
+    ures_close(bundle);
+
+}
+
+const char*
+TimeZone::getTZDataVersion(UErrorCode& status)
+{
+    umtx_initOnce(gTZDataVersionInitOnce, &initTZDataVersion, status);
     return (const char*)TZDATA_VERSION;
 }
 
index 95f0421e8f5b476d376d95991e974a6d45658183..ab5b451d359de6d66be07108130e540e5a68f00e 100644 (file)
@@ -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<TimeZoneFormat *>(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<UChar *>(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<UChar *>(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<ZoneIdMatchHandler> 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;
 }
 
-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<UChar *>(uID), status);
-                            }
-                        }
-                        if (U_SUCCESS(status)) {
-                            gShortZoneIdTrie = trie;
-                            gShortZoneIdTrieInitialized = initialized = TRUE;
-                            ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEFORMAT, tzfmt_cleanup);
-                        } else {
-                            delete trie;
-                        }
-                    }
+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<UChar *>(uID), status);
                 }
-                delete tzenum;
             }
         }
-        umtx_unlock(&gLock);
     }
+    delete tzenum;
+}
+
+
+UnicodeString&
+TimeZoneFormat::parseShortZoneID(const UnicodeString& text, ParsePosition& pos, UnicodeString& tzID) const {
+    UErrorCode status = U_ZERO_ERROR;
+    umtx_initOnce(gShortZoneIdTrieInitOnce, &initShortZoneIdTrie, status);
 
     int32_t start = pos.getIndex();
     int32_t len = 0;
     tzID.setToBogus();
 
-    if (initialized) {
+    if (U_SUCCESS(status)) {
         LocalPointer<ZoneIdMatchHandler> handler(new ZoneIdMatchHandler());
         gShortZoneIdTrie->search(text, start, handler.getAlias(), status); 
         len = handler->getMatchLen();
index 0666cfba29d24a7e849e1fa0df75d133e9932486..e6bd109b749bee9bfd6c9ea683f391c2000240ab 100644 (file)
@@ -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;
index c887997e82d4f5f395c57f2e7b26fcc6332efde6..bb1e863cd8bb849a34a3dc78e1a6bcb5a01c559b 100644 (file)
@@ -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)) {
+            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);
             }
-            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_FAILURE(status)) {
+            if (tznames != NULL) {
+                delete tznames;
             }
-            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);
-                }
+            if (newKey != NULL) {
+                uprv_free(newKey);
             }
-            if (U_FAILURE(status)) {
-                if (tznames != NULL) {
-                    delete tznames;
-                }
-                if (newKey != NULL) {
-                    uprv_free(newKey);
-                }
-                if (cacheEntry != NULL) {
-                    uprv_free(cacheEntry);
-                }
-                cacheEntry = NULL;
+            if (cacheEntry != NULL) {
+                uprv_free(cacheEntry);
             }
-        } else {
-            // Update the reference count
-            cacheEntry->refCount++;
-            cacheEntry->lastAccess = (double)uprv_getUTCtime();
-        }
-        gAccessCount++;
-        if (gAccessCount >= SWEEP_INTERVAL) {
-            // sweep
-            sweepCache();
-            gAccessCount = 0;
+            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;
 }
 
index e3b0c3c043192cf25a2e0e13f7fc2f2d95639684..d11d787cfc7758756d11fa20a7b76d207ba43980 100644 (file)
@@ -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; i<fLazyContents->size(); 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<TextTrieMap *>(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<TextTrieMap *>(this);
+            nonConstThis->buildTrie(status);
+        }
     }
     if (fNodes == NULL) {
         return;
index 15088310983f90203d2c6d4e6ff1e59332fcc2af..22ca64055e230e69b5e723e2777edad29fbfc642 100644 (file)
@@ -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
 
-U_CAPI const InverseUCATableHeader * U_EXPORT2
-ucol_initInverseUCA(UErrorCode *status)
-{
-    if(U_FAILURE(*status)) return NULL;
+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);
 
-    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);
+        return;
+    }
 
-        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;
         }
 
-        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;
-            }
+        invUCA_DATA_MEM = result;
+        _staticInvUCA = newInvUCA;
+    }
+}
 
-            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);
-            }
-        }
-    }
+U_CAPI const InverseUCATableHeader * U_EXPORT2
+ucol_initInverseUCA(UErrorCode *status)
+{
+    umtx_initOnce(gStaticInvUCAInitOnce, &initInverseUCA, *status);
     return _staticInvUCA;
 }
 
index 5ceb2c6cd332643fb966a38ae25b82671be17046..853de6e08aa177172692afa466e59c654bbbb8eb 100644 (file)
@@ -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
 
-/* do not close UCA returned by ucol_initUCA! */
-UCollator *
-ucol_initUCA(UErrorCode *status) {
-    if(U_FAILURE(*status)) {
-        return NULL;
+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;
     }
-    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);
+    _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;
 
-        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);
+    }else{
+        ucol_close(_staticUCA);
+        _staticUCA = NULL;
+        udata_close(result);
+    }
+}
 
-                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);
-        }
-    }
+/* do not close UCA returned by ucol_initUCA! */
+UCollator *
+ucol_initUCA(UErrorCode *status) {
+    umtx_initOnce(gStaticUCAInitOnce, &ucol_initStaticUCA, *status);
     return _staticUCA;
 }
 
@@ -155,6 +146,7 @@ ucol_forgetUCA(void)
 {
     _staticUCA = NULL;
     UCA_DATA_MEM = NULL;
+    gStaticUCAInitOnce.reset();
 }
 
 /****************************************************************************/
index 2bd08026215190f23428cd5741614439895a8a90..5e5c4e892d8256edf8f07efb0438516036686314 100644 (file)
@@ -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<UHashtable *>(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, &currencyNames, &total_currency_name_count, &currencySymbols, &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
 
-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;
-        }
+static void U_CALLCONV initIsoCodes(UErrorCode &status) {
+    U_ASSERT(gIsoCodes == NULL);
+    ucln_i18n_registerCleanup(UCLN_I18N_CURRENCY, currency_cleanup);
 
-        gIsoCodesInitialized = TRUE;
-        umtx_unlock(&gIsoCodesLock);
+    UHashtable *isoCodes = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+    if (U_FAILURE(status)) {
+        return;
     }
+    uhash_setValueDeleter(isoCodes, deleteIsoCodeEntry);
 
-    umtx_lock(&gIsoCodesLock);
-    IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
-    umtx_unlock(&gIsoCodesLock);
+    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) {
+    umtx_initOnce(gIsoCodesInitOnce, &initIsoCodes, *eErrorCode);
+    if (U_FAILURE(*eErrorCode)) {
+        return FALSE;
+    }
+
+    IsoCodeEntry* result = (IsoCodeEntry *) uhash_get(gIsoCodes, isoCode);
     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;
 }
 
index cbe559a7fd011911c57c51a9db8f0190866927cc..bcdff2d4834c70ddda05dccb897dc8556d05b2c8 100644 (file)
@@ -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:
 
index 4b52ffdbafa24e778d27df8087014ee1e0320185..780c772c61041409956ff8e60a6d88de5ad2a150 100644 (file)
@@ -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
index f50cc82d54dfb47628486a9a55ccdacf32f62f3c..b92376aea036a3400dce6c1ed40a56bcbfb2b7a8 100644 (file)
@@ -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
index 6255c53c2d9c398dc785ee05df30f55316a72bae..e054756632071dda2bb2098f58dcbe9fdf2a5f7a 100644 (file)
@@ -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.
+     *
+     * <p>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.
      *
+     * <p>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;
index 6c4ee7c55899fb0bbacca56a446dc457781358ba..9763aac1e95ba84b37c675e90b365d2644fb5a4d 100644 (file)
@@ -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;
     }
index dc9dda9da0f6aa04769931c061f0e1ddbc2fb6f2..0621bd007914173cff8771b63cd3c33d1c59977b 100644 (file)
@@ -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;
index 522c3f04990e3a07371f48de77bea442988db839..3851ff17588a3c329e013c26d4169f22d3465206 100644 (file)
@@ -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);
-
-                    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);
-                }
-            }
+static void U_CALLCONV initAvailableMetaZoneIDs () {
+    U_ASSERT(gMetaZoneIDs == NULL);
+    U_ASSERT(gMetaZoneIDTable == NULL);
+    ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
+
+    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);
 }
 
index 3c4218276ac18d043b3d5428e89a9d35df1abe5f..ac65e82acbc69c20fcf42aaeec28e5b7ec1a64c2 100644 (file)
@@ -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);
 };