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 |