| OLD | NEW |
| 1 /* | 1 /* |
| 2 ****************************************************************************** | 2 ****************************************************************************** |
| 3 * | 3 * |
| 4 * Copyright (C) 1999-2014, International Business Machines | 4 * Copyright (C) 1999-2015, International Business Machines |
| 5 * Corporation and others. All Rights Reserved. | 5 * Corporation and others. All Rights Reserved. |
| 6 * | 6 * |
| 7 ****************************************************************************** | 7 ****************************************************************************** |
| 8 * file name: udata.cpp | 8 * file name: udata.cpp |
| 9 * encoding: US-ASCII | 9 * encoding: US-ASCII |
| 10 * tab size: 8 (not used) | 10 * tab size: 8 (not used) |
| 11 * indentation:4 | 11 * indentation:4 |
| 12 * | 12 * |
| 13 * created on: 1999oct25 | 13 * created on: 1999oct25 |
| 14 * created by: Markus W. Scherer | 14 * created by: Markus W. Scherer |
| 15 */ | 15 */ |
| 16 | 16 |
| 17 #include "unicode/utypes.h" /* U_PLATFORM etc. */ | 17 #include "unicode/utypes.h" /* U_PLATFORM etc. */ |
| 18 | 18 |
| 19 #ifdef __GNUC__ | 19 #ifdef __GNUC__ |
| 20 /* if gcc | 20 /* if gcc |
| 21 #define ATTRIBUTE_WEAK __attribute__ ((weak)) | 21 #define ATTRIBUTE_WEAK __attribute__ ((weak)) |
| 22 might have to #include some other header | 22 might have to #include some other header |
| 23 */ | 23 */ |
| 24 #endif | 24 #endif |
| 25 | 25 |
| 26 #include "unicode/putil.h" | 26 #include "unicode/putil.h" |
| 27 #include "unicode/udata.h" | 27 #include "unicode/udata.h" |
| 28 #include "unicode/uversion.h" | 28 #include "unicode/uversion.h" |
| 29 #include "charstr.h" | 29 #include "charstr.h" |
| 30 #include "cmemory.h" | 30 #include "cmemory.h" |
| 31 #include "cstring.h" | 31 #include "cstring.h" |
| 32 #include "mutex.h" |
| 32 #include "putilimp.h" | 33 #include "putilimp.h" |
| 33 #include "uassert.h" | 34 #include "uassert.h" |
| 34 #include "ucln_cmn.h" | 35 #include "ucln_cmn.h" |
| 35 #include "ucmndata.h" | 36 #include "ucmndata.h" |
| 36 #include "udatamem.h" | 37 #include "udatamem.h" |
| 37 #include "uhash.h" | 38 #include "uhash.h" |
| 38 #include "umapfile.h" | 39 #include "umapfile.h" |
| 39 #include "umutex.h" | 40 #include "umutex.h" |
| 40 | 41 |
| 41 /*********************************************************************** | 42 /*********************************************************************** |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 * It is possible to combine this with dependency inversion: | 94 * It is possible to combine this with dependency inversion: |
| 94 * One or more data package libraries may export | 95 * One or more data package libraries may export |
| 95 * functions that each return a pointer to their piece of the ICU data, | 96 * functions that each return a pointer to their piece of the ICU data, |
| 96 * and this file would import them as weak functions, without a | 97 * and this file would import them as weak functions, without a |
| 97 * strong linker dependency from the common library on the data library. | 98 * strong linker dependency from the common library on the data library. |
| 98 * | 99 * |
| 99 * Then we can have applications depend on only that part of ICU's data | 100 * Then we can have applications depend on only that part of ICU's data |
| 100 * that they really need, reducing the size of binaries that take advantage | 101 * that they really need, reducing the size of binaries that take advantage |
| 101 * of this. | 102 * of this. |
| 102 */ | 103 */ |
| 103 static UDataMemory *gCommonICUDataArray[10] = { NULL }; | 104 static UDataMemory *gCommonICUDataArray[10] = { NULL }; // Access protected by
icu global mutex. |
| 104 | 105 |
| 105 static UBool gHaveTriedToLoadCommonData = FALSE; /* See extendICUData(). */ | 106 static u_atomic_int32_t gHaveTriedToLoadCommonData = ATOMIC_INT32_T_INITIALIZER(
0); // See extendICUData(). |
| 106 | 107 |
| 107 static UHashtable *gCommonDataCache = NULL; /* Global hash table of opened ICU
data files. */ | 108 static UHashtable *gCommonDataCache = NULL; /* Global hash table of opened ICU
data files. */ |
| 108 static icu::UInitOnce gCommonDataCacheInitOnce = U_INITONCE_INITIALIZER; | 109 static icu::UInitOnce gCommonDataCacheInitOnce = U_INITONCE_INITIALIZER; |
| 109 | 110 |
| 110 static UDataFileAccess gDataFileAccess = UDATA_DEFAULT_ACCESS; | 111 static UDataFileAccess gDataFileAccess = UDATA_DEFAULT_ACCESS; // Access not s
ynchronized. |
| 112 // Modifying is
documented as thread-unsafe. |
| 111 | 113 |
| 112 static UBool U_CALLCONV | 114 static UBool U_CALLCONV |
| 113 udata_cleanup(void) | 115 udata_cleanup(void) |
| 114 { | 116 { |
| 115 int32_t i; | 117 int32_t i; |
| 116 | 118 |
| 117 if (gCommonDataCache) { /* Delete the cache of user data mapping
s. */ | 119 if (gCommonDataCache) { /* Delete the cache of user data mapping
s. */ |
| 118 uhash_close(gCommonDataCache); /* Table owns the contents, and will d
elete them. */ | 120 uhash_close(gCommonDataCache); /* Table owns the contents, and will d
elete them. */ |
| 119 gCommonDataCache = NULL; /* Cleanup is not thread safe.
*/ | 121 gCommonDataCache = NULL; /* Cleanup is not thread safe.
*/ |
| 120 } | 122 } |
| 121 gCommonDataCacheInitOnce.reset(); | 123 gCommonDataCacheInitOnce.reset(); |
| 122 | 124 |
| 123 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray) && gCommonICUDataArray[i]
!= NULL; ++i) { | 125 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray) && gCommonICUDataArray[i]
!= NULL; ++i) { |
| 124 udata_close(gCommonICUDataArray[i]); | 126 udata_close(gCommonICUDataArray[i]); |
| 125 gCommonICUDataArray[i] = NULL; | 127 gCommonICUDataArray[i] = NULL; |
| 126 } | 128 } |
| 127 gHaveTriedToLoadCommonData = FALSE; | 129 gHaveTriedToLoadCommonData = 0; |
| 128 | 130 |
| 129 return TRUE; /* Everything was cleaned up */ | 131 return TRUE; /* Everything was cleaned up */ |
| 130 } | 132 } |
| 131 | 133 |
| 132 static UBool U_CALLCONV | 134 static UBool U_CALLCONV |
| 133 findCommonICUDataByName(const char *inBasename) | 135 findCommonICUDataByName(const char *inBasename) |
| 134 { | 136 { |
| 135 UBool found = FALSE; | 137 UBool found = FALSE; |
| 136 int32_t i; | 138 int32_t i; |
| 137 | 139 |
| 138 UDataMemory *pData = udata_findCachedData(inBasename); | 140 UDataMemory *pData = udata_findCachedData(inBasename); |
| 139 if (pData == NULL) | 141 if (pData == NULL) |
| 140 return FALSE; | 142 return FALSE; |
| 141 | 143 |
| 142 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) { | 144 { |
| 143 if ((gCommonICUDataArray[i] != NULL) && (gCommonICUDataArray[i]->pHeader
== pData->pHeader)) { | 145 Mutex lock; |
| 144 /* The data pointer is already in the array. */ | 146 for (i = 0; i < UPRV_LENGTHOF(gCommonICUDataArray); ++i) { |
| 145 found = TRUE; | 147 if ((gCommonICUDataArray[i] != NULL) && (gCommonICUDataArray[i]->pHe
ader == pData->pHeader)) { |
| 146 break; | 148 /* The data pointer is already in the array. */ |
| 149 found = TRUE; |
| 150 break; |
| 151 } |
| 147 } | 152 } |
| 148 } | 153 } |
| 149 | |
| 150 return found; | 154 return found; |
| 151 } | 155 } |
| 152 | 156 |
| 153 | 157 |
| 154 /* | 158 /* |
| 155 * setCommonICUData. Set a UDataMemory to be the global ICU Data | 159 * setCommonICUData. Set a UDataMemory to be the global ICU Data |
| 156 */ | 160 */ |
| 157 static UBool | 161 static UBool |
| 158 setCommonICUData(UDataMemory *pData, /* The new common data. Belongs to ca
ller, we copy it. */ | 162 setCommonICUData(UDataMemory *pData, /* The new common data. Belongs to ca
ller, we copy it. */ |
| 159 UBool warn, /* If true, set USING_DEFAULT warning
if ICUData was */ | 163 UBool warn, /* If true, set USING_DEFAULT warning
if ICUData was */ |
| (...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 656 } | 660 } |
| 657 | 661 |
| 658 UDataMemory_init(&tData); | 662 UDataMemory_init(&tData); |
| 659 | 663 |
| 660 /* ??????? TODO revisit this */ | 664 /* ??????? TODO revisit this */ |
| 661 if (commonDataIndex >= 0) { | 665 if (commonDataIndex >= 0) { |
| 662 /* "mini-cache" for common ICU data */ | 666 /* "mini-cache" for common ICU data */ |
| 663 if(commonDataIndex >= UPRV_LENGTHOF(gCommonICUDataArray)) { | 667 if(commonDataIndex >= UPRV_LENGTHOF(gCommonICUDataArray)) { |
| 664 return NULL; | 668 return NULL; |
| 665 } | 669 } |
| 666 if(gCommonICUDataArray[commonDataIndex] == NULL) { | 670 { |
| 671 Mutex lock; |
| 672 if(gCommonICUDataArray[commonDataIndex] != NULL) { |
| 673 return gCommonICUDataArray[commonDataIndex]; |
| 674 } |
| 667 int32_t i; | 675 int32_t i; |
| 668 for(i = 0; i < commonDataIndex; ++i) { | 676 for(i = 0; i < commonDataIndex; ++i) { |
| 669 if(gCommonICUDataArray[i]->pHeader == &U_ICUDATA_ENTRY_POINT.hdr
) { | 677 if(gCommonICUDataArray[i]->pHeader == &U_ICUDATA_ENTRY_POINT.hdr
) { |
| 670 /* The linked-in data is already in the list. */ | 678 /* The linked-in data is already in the list. */ |
| 671 return NULL; | 679 return NULL; |
| 672 } | 680 } |
| 673 } | 681 } |
| 682 } |
| 674 | 683 |
| 675 /* Add the linked-in data to the list. */ | 684 /* Add the linked-in data to the list. */ |
| 676 /* | 685 /* |
| 677 * This is where we would check and call weakly linked partial-data-
library | 686 * This is where we would check and call weakly linked partial-data-libr
ary |
| 678 * access functions. | 687 * access functions. |
| 679 */ | 688 */ |
| 680 /* | 689 /* |
| 681 if (uprv_getICUData_collation) { | 690 if (uprv_getICUData_collation) { |
| 682 setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErr
orCode); | 691 setCommonICUDataPointer(uprv_getICUData_collation(), FALSE, pErrorCo
de); |
| 683 } | |
| 684 if (uprv_getICUData_conversion) { | |
| 685 setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pEr
rorCode); | |
| 686 } | |
| 687 */ | |
| 688 setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT.hdr, FALSE, pErrorCod
e); | |
| 689 } | 692 } |
| 690 return gCommonICUDataArray[commonDataIndex]; | 693 if (uprv_getICUData_conversion) { |
| 694 setCommonICUDataPointer(uprv_getICUData_conversion(), FALSE, pErrorC
ode); |
| 695 } |
| 696 */ |
| 697 setCommonICUDataPointer(&U_ICUDATA_ENTRY_POINT.hdr, FALSE, pErrorCode); |
| 698 { |
| 699 Mutex lock; |
| 700 return gCommonICUDataArray[commonDataIndex]; |
| 701 } |
| 691 } | 702 } |
| 692 | 703 |
| 693 | 704 |
| 694 /* request is NOT for ICU Data. */ | 705 /* request is NOT for ICU Data. */ |
| 695 | 706 |
| 696 /* Find the base name portion of the supplied path. */ | 707 /* Find the base name portion of the supplied path. */ |
| 697 /* inBasename will be left pointing somewhere within the original path str
ing. */ | 708 /* inBasename will be left pointing somewhere within the original path str
ing. */ |
| 698 inBasename = findBasename(path); | 709 inBasename = findBasename(path); |
| 699 #ifdef UDATA_DEBUG | 710 #ifdef UDATA_DEBUG |
| 700 fprintf(stderr, "inBasename = %s\n", inBasename); | 711 fprintf(stderr, "inBasename = %s\n", inBasename); |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 788 * If ICU is built with data loading via fread() then the address will | 799 * If ICU is built with data loading via fread() then the address will |
| 789 * be different each time the common data is loaded and we may add | 800 * be different each time the common data is loaded and we may add |
| 790 * multiple copies of the data. | 801 * multiple copies of the data. |
| 791 * In this case, use a mutex to prevent the race. | 802 * In this case, use a mutex to prevent the race. |
| 792 * Use a specific mutex to avoid nested locks of the global mutex. | 803 * Use a specific mutex to avoid nested locks of the global mutex. |
| 793 */ | 804 */ |
| 794 #if MAP_IMPLEMENTATION==MAP_STDIO | 805 #if MAP_IMPLEMENTATION==MAP_STDIO |
| 795 static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER; | 806 static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER; |
| 796 umtx_lock(&extendICUDataMutex); | 807 umtx_lock(&extendICUDataMutex); |
| 797 #endif | 808 #endif |
| 798 if(!gHaveTriedToLoadCommonData) { | 809 if(!umtx_loadAcquire(gHaveTriedToLoadCommonData)) { |
| 799 /* See if we can explicitly open a .dat file for the ICUData. */ | 810 /* See if we can explicitly open a .dat file for the ICUData. */ |
| 800 pData = openCommonData( | 811 pData = openCommonData( |
| 801 U_ICUDATA_NAME, /* "icudt20l" , for example.
*/ | 812 U_ICUDATA_NAME, /* "icudt20l" , for example.
*/ |
| 802 -1, /* Pretend we're not opening ICUD
ata */ | 813 -1, /* Pretend we're not opening ICUD
ata */ |
| 803 pErr); | 814 pErr); |
| 804 | 815 |
| 805 /* How about if there is no pData, eh... */ | 816 /* How about if there is no pData, eh... */ |
| 806 | 817 |
| 807 UDataMemory_init(©PData); | 818 UDataMemory_init(©PData); |
| 808 if(pData != NULL) { | 819 if(pData != NULL) { |
| 809 UDatamemory_assign(©PData, pData); | 820 UDatamemory_assign(©PData, pData); |
| 810 copyPData.map = 0; /* The mapping for this data is owned
by the hash table */ | 821 copyPData.map = 0; /* The mapping for this data is owned
by the hash table */ |
| 811 copyPData.mapAddr = 0; /* which will unmap it when ICU is s
hut down. */ | 822 copyPData.mapAddr = 0; /* which will unmap it when ICU is s
hut down. */ |
| 812 /* CommonICUData is also unmapped when
ICU is shut down.*/ | 823 /* CommonICUData is also unmapped when
ICU is shut down.*/ |
| 813 /* To avoid unmapping the data twice,
zero out the map */ | 824 /* To avoid unmapping the data twice,
zero out the map */ |
| 814 /* fields in the UDataMemory that we
're assigning */ | 825 /* fields in the UDataMemory that we
're assigning */ |
| 815 /* to CommonICUData.
*/ | 826 /* to CommonICUData.
*/ |
| 816 | 827 |
| 817 didUpdate = /* no longer using this result */ | 828 didUpdate = /* no longer using this result */ |
| 818 setCommonICUData(©PData,/* The new common data.
*/ | 829 setCommonICUData(©PData,/* The new common data.
*/ |
| 819 FALSE, /* No warnings if write didn't happen
*/ | 830 FALSE, /* No warnings if write didn't happen
*/ |
| 820 pErr); /* setCommonICUData honors errors; NO
P if error set */ | 831 pErr); /* setCommonICUData honors errors; NO
P if error set */ |
| 821 } | 832 } |
| 822 | 833 |
| 823 gHaveTriedToLoadCommonData = TRUE; | 834 umtx_storeRelease(gHaveTriedToLoadCommonData, 1); |
| 824 } | 835 } |
| 825 | 836 |
| 826 didUpdate = findCommonICUDataByName(U_ICUDATA_NAME); /* Return 'true' when
a racing writes out the extended */ | 837 didUpdate = findCommonICUDataByName(U_ICUDATA_NAME); /* Return 'true' when
a racing writes out the extended */ |
| 827 /* data after another
thread has failed to see it (in openCommonData), so */ | 838 /* data after another
thread has failed to see it (in openCommonData), so */ |
| 828 /* extended data can b
e examined. */ | 839 /* extended data can b
e examined. */ |
| 829 /* Also handles a race
through here before gHaveTriedToLoadCommonData is set. */ | 840 /* Also handles a race
through here before gHaveTriedToLoadCommonData is set. */ |
| 830 | 841 |
| 831 #if MAP_IMPLEMENTATION==MAP_STDIO | 842 #if MAP_IMPLEMENTATION==MAP_STDIO |
| 832 umtx_unlock(&extendICUDataMutex); | 843 umtx_unlock(&extendICUDataMutex); |
| 833 #endif | 844 #endif |
| (...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1391 } | 1402 } |
| 1392 } else { | 1403 } else { |
| 1393 pInfo->size=0; | 1404 pInfo->size=0; |
| 1394 } | 1405 } |
| 1395 } | 1406 } |
| 1396 } | 1407 } |
| 1397 | 1408 |
| 1398 | 1409 |
| 1399 U_CAPI void U_EXPORT2 udata_setFileAccess(UDataFileAccess access, UErrorCode * /
*status*/) | 1410 U_CAPI void U_EXPORT2 udata_setFileAccess(UDataFileAccess access, UErrorCode * /
*status*/) |
| 1400 { | 1411 { |
| 1412 // Note: this function is documented as not thread safe. |
| 1401 gDataFileAccess = access; | 1413 gDataFileAccess = access; |
| 1402 } | 1414 } |
| OLD | NEW |