]> granicus.if.org Git - icu/commitdiff
ICU-11776 Thread safety fixes in data loading.
authorAndy Heninger <andy.heninger@gmail.com>
Wed, 15 Jul 2015 22:09:25 +0000 (22:09 +0000)
committerAndy Heninger <andy.heninger@gmail.com>
Wed, 15 Jul 2015 22:09:25 +0000 (22:09 +0000)
X-SVN-Rev: 37670

icu4c/source/common/udata.cpp

index 0d7df42568dcbe22a6d6577132092d764471a032..d32023b7f6d7565a50051bac44ee084abb4853d2 100644 (file)
@@ -1,7 +1,7 @@
 /*
 ******************************************************************************
 *
-*   Copyright (C) 1999-2014, International Business Machines
+*   Copyright (C) 1999-2015, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 ******************************************************************************
@@ -29,6 +29,7 @@ might have to #include some other header
 #include "charstr.h"
 #include "cmemory.h"
 #include "cstring.h"
+#include "mutex.h"
 #include "putilimp.h"
 #include "uassert.h"
 #include "ucln_cmn.h"
@@ -100,14 +101,15 @@ static UDataMemory *udata_findCachedData(const char *path);
  * that they really need, reducing the size of binaries that take advantage
  * of this.
  */
-static UDataMemory *gCommonICUDataArray[10] = { NULL };
+static UDataMemory *gCommonICUDataArray[10] = { NULL };   // Access protected by icu global mutex.
 
-static UBool gHaveTriedToLoadCommonData = FALSE;  /* See extendICUData(). */
+static u_atomic_int32_t gHaveTriedToLoadCommonData = ATOMIC_INT32_T_INITIALIZER(0);  //  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;
+static UDataFileAccess  gDataFileAccess = UDATA_DEFAULT_ACCESS;  // Access not synchronized.
+                                                                 // Modifying is documented as thread-unsafe.
 
 static UBool U_CALLCONV
 udata_cleanup(void)
@@ -124,7 +126,7 @@ udata_cleanup(void)
         udata_close(gCommonICUDataArray[i]);
         gCommonICUDataArray[i] = NULL;
     }
-    gHaveTriedToLoadCommonData = FALSE;
+    gHaveTriedToLoadCommonData = 0;
 
     return TRUE;                   /* Everything was cleaned up */
 }
@@ -139,14 +141,16 @@ findCommonICUDataByName(const char *inBasename)
     if (pData == NULL)
         return FALSE;
 
-    for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) {
-        if ((gCommonICUDataArray[i] != NULL) && (gCommonICUDataArray[i]->pHeader == pData->pHeader)) {
-            /* The data pointer is already in the array. */
-            found = TRUE;
-            break;
+    {
+        Mutex lock;
+        for (i = 0; i < UPRV_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;
 }
 
@@ -663,7 +667,11 @@ openCommonData(const char *path,          /*  Path from OpenChoice?          */
         if(commonDataIndex >= UPRV_LENGTHOF(gCommonICUDataArray)) {
             return NULL;
         }
-        if(gCommonICUDataArray[commonDataIndex] == NULL) {
+        {
+            Mutex lock;
+            if(gCommonICUDataArray[commonDataIndex] != NULL) {
+                return gCommonICUDataArray[commonDataIndex];
+            }
             int32_t i;
             for(i = 0; i < commonDataIndex; ++i) {
                 if(gCommonICUDataArray[i]->pHeader == &U_ICUDATA_ENTRY_POINT) {
@@ -671,23 +679,26 @@ openCommonData(const char *path,          /*  Path from OpenChoice?          */
                     return NULL;
                 }
             }
+        }
 
-            /* Add the linked-in data to the list. */
-            /*
-             * This is where we would check and call weakly linked partial-data-library
-             * access functions.
-             */
-            /*
-            if (uprv_getICUData_collation) {
-                setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErrorCode);
-            }
-            if (uprv_getICUData_conversion) {
-                setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pErrorCode);
-            }
-            */
-            setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, FALSE, pErrorCode);
+        /* Add the linked-in data to the list. */
+        /*
+         * This is where we would check and call weakly linked partial-data-library
+         * access functions.
+         */
+        /*
+        if (uprv_getICUData_collation) {
+            setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErrorCode);
+        }
+        if (uprv_getICUData_conversion) {
+            setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pErrorCode);
+        }
+        */
+        setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT, FALSE, pErrorCode);
+        {
+            Mutex lock;
+            return gCommonICUDataArray[commonDataIndex];
         }
-        return gCommonICUDataArray[commonDataIndex];
     }
 
 
@@ -795,7 +806,7 @@ static UBool extendICUData(UErrorCode *pErr)
     static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER;
     umtx_lock(&extendICUDataMutex);
 #endif
-    if(!gHaveTriedToLoadCommonData) {
+    if(!umtx_loadAcquire(gHaveTriedToLoadCommonData)) {
         /* See if we can explicitly open a .dat file for the ICUData. */
         pData = openCommonData(
                    U_ICUDATA_NAME,            /*  "icudt20l" , for example.          */
@@ -820,7 +831,7 @@ static UBool extendICUData(UErrorCode *pErr)
                        pErr);             /*  setCommonICUData honors errors; NOP if error set    */
         }
 
-        gHaveTriedToLoadCommonData = TRUE;
+        umtx_storeRelease(gHaveTriedToLoadCommonData, 1);
     }
 
     didUpdate = findCommonICUDataByName(U_ICUDATA_NAME);  /* Return 'true' when a racing writes out the extended                        */
@@ -1398,5 +1409,6 @@ udata_getInfo(UDataMemory *pData, UDataInfo *pInfo) {
 
 U_CAPI void U_EXPORT2 udata_setFileAccess(UDataFileAccess access, UErrorCode * /*status*/)
 {
+    // Note: this function is documented as not thread safe.
     gDataFileAccess = access;
 }