Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / icu / source / common / udata.cpp
index 42ed3d3..2bcc187 100644 (file)
@@ -1,7 +1,7 @@
 /*
 ******************************************************************************
 *
-*   Copyright (C) 1999-2010, International Business Machines
+*   Copyright (C) 1999-2013, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 ******************************************************************************
@@ -14,9 +14,9 @@
 *   created by: Markus W. Scherer
 */
 
-#include "unicode/utypes.h"  /* U_LINUX */
+#include "unicode/utypes.h"  /* U_PLATFORM etc. */
 
-#ifdef U_LINUX
+#ifdef __GNUC__
 /* if gcc
 #define ATTRIBUTE_WEAK __attribute__ ((weak))
 might have to #include some other header
@@ -30,6 +30,7 @@ might have to #include some other header
 #include "cmemory.h"
 #include "cstring.h"
 #include "putilimp.h"
+#include "uassert.h"
 #include "ucln_cmn.h"
 #include "ucmndata.h"
 #include "udatamem.h"
@@ -74,6 +75,11 @@ might have to #include some other header
 
 U_NAMESPACE_USE
 
+/*
+ *  Forward declarations
+ */
+static UDataMemory *udata_findCachedData(const char *path);
+
 /***********************************************************************
 *
 *    static (Global) data
@@ -101,6 +107,7 @@ static UDataMemory *gCommonICUDataArray[10] = { NULL };
 static UBool gHaveTriedToLoadCommonData = FALSE;  /* See extendICUData(). */
 
 static UHashtable  *gCommonDataCache = NULL;  /* Global hash table of opened ICU data files.  */
+static icu::UInitOnce gCommonDataCacheInitOnce = U_INITONCE_INITIALIZER;
 
 static UDataFileAccess  gDataFileAccess = UDATA_DEFAULT_ACCESS;
 
@@ -113,6 +120,7 @@ udata_cleanup(void)
         uhash_close(gCommonDataCache);  /*   Table owns the contents, and will delete them. */
         gCommonDataCache = NULL;        /*   Cleanup is not thread safe.                */
     }
+    gCommonDataCacheInitOnce.reset();
 
     for (i = 0; i < LENGTHOF(gCommonICUDataArray) && gCommonICUDataArray[i] != NULL; ++i) {
         udata_close(gCommonICUDataArray[i]);
@@ -123,7 +131,26 @@ udata_cleanup(void)
     return TRUE;                   /* Everything was cleaned up */
 }
 
+static UBool U_CALLCONV
+findCommonICUDataByName(const char *inBasename)
+{
+    UBool found = FALSE;
+    int32_t i;
 
+    UDataMemory  *pData = udata_findCachedData(inBasename);
+    if (pData == NULL)
+        return FALSE;
+
+    for (i = 0; i < LENGTHOF(gCommonICUDataArray); ++i) {
+        if ((gCommonICUDataArray[i] != NULL) && (gCommonICUDataArray[i]->pHeader == pData->pHeader)) {
+            /* The data pointer is already in the array. */
+            found = TRUE;
+            break;
+        }
+    }
+
+    return found;
+}
 
 
 /*
@@ -174,7 +201,7 @@ static UBool
 setCommonICUDataPointer(const void *pData, UBool /*warn*/, UErrorCode *pErrorCode) {
     UDataMemory tData;
     UDataMemory_init(&tData);
-    tData.pHeader = (const DataHeader *)pData;
+    UDataMemory_setData(&tData, pData);
     udata_checkCommonData(&tData, pErrorCode);
     return setCommonICUData(&tData, FALSE, pErrorCode);
 }
@@ -238,42 +265,26 @@ static void U_CALLCONV DataCacheElement_deleter(void *pDCEl) {
     uprv_free(pDCEl);                  /* delete 'this'          */
 }
 
- /*   udata_getCacheHashTable()
- *     Get the hash table used to store the data cache entries.
- *     Lazy create it if it doesn't yet exist.
- */
-static UHashtable *udata_getHashTable() {
-    UErrorCode   err = U_ZERO_ERROR;
-    UBool        cacheIsInitialized;
-    UHashtable  *tHT = NULL;
-
-    UMTX_CHECK(NULL, (gCommonDataCache != NULL), cacheIsInitialized);
-
-    if (cacheIsInitialized) {
-        return gCommonDataCache;
-    }
-
-    tHT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &err);
-    /* Check for null pointer. */
-    if (tHT == NULL) {
-       return NULL; /* TODO:  Handle this error better. */
+static void udata_initHashTable() {
+    UErrorCode err = U_ZERO_ERROR;
+    U_ASSERT(gCommonDataCache == NULL);
+    gCommonDataCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &err);
+    if (U_FAILURE(err)) {
+        // TODO: handle errors better.
+        gCommonDataCache = NULL;
     }
-    uhash_setValueDeleter(tHT, DataCacheElement_deleter);
-
-    umtx_lock(NULL);
-    if (gCommonDataCache == NULL) {
-        gCommonDataCache = tHT;
-        tHT = NULL;
+    if (gCommonDataCache != NULL) {
+        uhash_setValueDeleter(gCommonDataCache, DataCacheElement_deleter);
         ucln_common_registerCleanup(UCLN_COMMON_UDATA, udata_cleanup);
     }
-    umtx_unlock(NULL);
-    if (tHT != NULL) {
-        uhash_close(tHT);
-    }
+}
 
-    if (U_FAILURE(err)) {
-        return NULL;      /* TODO:  handle this error better.  */
-    }
+ /*   udata_getCacheHashTable()
+  *     Get the hash table used to store the data cache entries.
+  *     Lazy create it if it doesn't yet exist.
+  */
+static UHashtable *udata_getHashTable() {
+    umtx_initOnce(gCommonDataCacheInitOnce, &udata_initHashTable);
     return gCommonDataCache;
 }
 
@@ -782,12 +793,10 @@ static UBool extendICUData(UErrorCode *pErr)
      * Use a specific mutex to avoid nested locks of the global mutex.
      */
 #if MAP_IMPLEMENTATION==MAP_STDIO
-    static UMTX extendICUDataMutex = NULL;
+    static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER;
     umtx_lock(&extendICUDataMutex);
 #endif
     if(!gHaveTriedToLoadCommonData) {
-        gHaveTriedToLoadCommonData = TRUE;
-
         /* See if we can explicitly open a .dat file for the ICUData. */
         pData = openCommonData(
                    U_ICUDATA_NAME,            /*  "icudt20l" , for example.          */
@@ -806,12 +815,20 @@ static UBool extendICUData(UErrorCode *pErr)
                                           /*   fields in the UDataMemory that we're assigning     */
                                           /*   to CommonICUData.                                  */
 
-          didUpdate =
+          didUpdate = /* no longer using this result */
               setCommonICUData(&copyPData,/*  The new common data.                                */
                        FALSE,             /*  No warnings if write didn't happen                  */
                        pErr);             /*  setCommonICUData honors errors; NOP if error set    */
         }
+
+        gHaveTriedToLoadCommonData = TRUE;
     }
+
+    didUpdate = findCommonICUDataByName(U_ICUDATA_NAME);  /* Return 'true' when a racing writes out the extended                        */
+                                                          /* data after another thread has failed to see it (in openCommonData), so     */
+                                                          /* extended data can be examined.                                             */
+                                                          /* Also handles a race through here before gHaveTriedToLoadCommonData is set. */
+
 #if MAP_IMPLEMENTATION==MAP_STDIO
     umtx_unlock(&extendICUDataMutex);
 #endif
@@ -996,6 +1013,7 @@ static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName
     const DataHeader   *pHeader;
     UDataMemory        *pCommonData;
     int32_t            commonDataIndex;
+    UBool              checkedExtendedICUData = FALSE;
     /* try to get common data.  The loop is for platforms such as the 390 that do
      *  not initially load the full set of ICU data.  If the lookup of an ICU data item
      *  fails, the full (but slower to load) set is loaded, the and the loop repeats,
@@ -1038,7 +1056,8 @@ static UDataMemory *doLoadFromCommonData(UBool isICUData, const char * /*pkgName
             return NULL;
         } else if (pCommonData != NULL) {
             ++commonDataIndex;  /* try the next data package */
-        } else if (extendICUData(subErrorCode)) {
+        } else if ((!checkedExtendedICUData) && extendICUData(subErrorCode)) {
+            checkedExtendedICUData = TRUE;
             /* try this data package slot again: it changed from NULL to non-NULL */
         } else {
             return NULL;