X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/51004dcb01e06fef634b61be77ed73dd61cb6db9..f3c0d7a59d99c2a94c6b8822291f0e42be3773c9:/icuSources/common/ucnv_bld.cpp diff --git a/icuSources/common/ucnv_bld.cpp b/icuSources/common/ucnv_bld.cpp index 45c56c17..14de21bd 100644 --- a/icuSources/common/ucnv_bld.cpp +++ b/icuSources/common/ucnv_bld.cpp @@ -1,11 +1,13 @@ +// © 2016 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html /* ******************************************************************** * COPYRIGHT: - * Copyright (c) 1996-2012, International Business Machines Corporation and + * Copyright (c) 1996-2016, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************** * - * uconv_bld.cpp: + * ucnv_bld.cpp: * * Defines functions that are used in the creation/initialization/deletion * of converters and related structures. @@ -27,7 +29,9 @@ #include "unicode/udata.h" #include "unicode/ucnv.h" #include "unicode/uloc.h" +#include "mutex.h" #include "putilimp.h" +#include "uassert.h" #include "utracimp.h" #include "ucnv_io.h" #include "ucnv_bld.h" @@ -43,7 +47,6 @@ #include "ustr_cnv.h" - #if 0 #include <stdio.h> extern void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l); @@ -63,33 +66,51 @@ converterData[UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES]={ #endif &_Latin1Data, - &_UTF8Data, &_UTF16BEData, &_UTF16LEData, &_UTF32BEData, &_UTF32LEData, + &_UTF8Data, &_UTF16BEData, &_UTF16LEData, +#if UCONFIG_ONLY_HTML_CONVERSION + NULL, NULL, +#else + &_UTF32BEData, &_UTF32LEData, +#endif NULL, #if UCONFIG_NO_LEGACY_CONVERSION NULL, +#else + &_ISO2022Data, +#endif + +#if UCONFIG_NO_LEGACY_CONVERSION || UCONFIG_ONLY_HTML_CONVERSION NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, #else - &_ISO2022Data, &_LMBCSData1,&_LMBCSData2, &_LMBCSData3, &_LMBCSData4, &_LMBCSData5, &_LMBCSData6, &_LMBCSData8,&_LMBCSData11,&_LMBCSData16,&_LMBCSData17,&_LMBCSData18,&_LMBCSData19, &_HZData, #endif +#if UCONFIG_ONLY_HTML_CONVERSION + NULL, +#else &_SCSUData, +#endif -#if UCONFIG_NO_LEGACY_CONVERSION + +#if UCONFIG_NO_LEGACY_CONVERSION || UCONFIG_ONLY_HTML_CONVERSION NULL, #else &_ISCIIData, #endif &_ASCIIData, +#if UCONFIG_ONLY_HTML_CONVERSION + NULL, NULL, &_UTF16Data, NULL, NULL, NULL, +#else &_UTF7Data, &_Bocu1Data, &_UTF16Data, &_UTF32Data, &_CESU8Data, &_IMAPData, +#endif -#if UCONFIG_NO_LEGACY_CONVERSION +#if UCONFIG_NO_LEGACY_CONVERSION || UCONFIG_ONLY_HTML_CONVERSION NULL, #else &_CompoundTextData @@ -104,18 +125,24 @@ static struct { const char *name; const UConverterType type; } const cnvNameType[] = { +#if !UCONFIG_ONLY_HTML_CONVERSION { "bocu1", UCNV_BOCU1 }, { "cesu8", UCNV_CESU8 }, -#if !UCONFIG_NO_LEGACY_CONVERSION +#endif +#if !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION { "hz",UCNV_HZ }, #endif +#if !UCONFIG_ONLY_HTML_CONVERSION { "imapmailboxname", UCNV_IMAP_MAILBOX }, -#if !UCONFIG_NO_LEGACY_CONVERSION +#endif +#if !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION { "iscii", UCNV_ISCII }, +#endif +#if !UCONFIG_NO_LEGACY_CONVERSION { "iso2022", UCNV_ISO_2022 }, #endif { "iso88591", UCNV_LATIN_1 }, -#if !UCONFIG_NO_LEGACY_CONVERSION +#if !UCONFIG_NO_LEGACY_CONVERSION && !UCONFIG_ONLY_HTML_CONVERSION { "lmbcs1", UCNV_LMBCS_1 }, { "lmbcs11",UCNV_LMBCS_11 }, { "lmbcs16",UCNV_LMBCS_16 }, @@ -129,7 +156,9 @@ static struct { { "lmbcs6", UCNV_LMBCS_6 }, { "lmbcs8", UCNV_LMBCS_8 }, #endif +#if !UCONFIG_ONLY_HTML_CONVERSION { "scsu", UCNV_SCSU }, +#endif { "usascii", UCNV_US_ASCII }, { "utf16", UCNV_UTF16 }, { "utf16be", UCNV_UTF16_BigEndian }, @@ -141,6 +170,7 @@ static struct { { "utf16oppositeendian", UCNV_UTF16_BigEndian}, { "utf16platformendian", UCNV_UTF16_LittleEndian }, #endif +#if !UCONFIG_ONLY_HTML_CONVERSION { "utf32", UCNV_UTF32 }, { "utf32be", UCNV_UTF32_BigEndian }, { "utf32le", UCNV_UTF32_LittleEndian }, @@ -151,9 +181,14 @@ static struct { { "utf32oppositeendian", UCNV_UTF32_BigEndian }, { "utf32platformendian", UCNV_UTF32_LittleEndian }, #endif +#endif +#if !UCONFIG_ONLY_HTML_CONVERSION { "utf7", UCNV_UTF7 }, +#endif { "utf8", UCNV_UTF8 }, +#if !UCONFIG_ONLY_HTML_CONVERSION { "x11compoundtext", UCNV_COMPOUND_TEXT} +#endif }; @@ -165,6 +200,7 @@ static UMutex cnvCacheMutex = U_MUTEX_INITIALIZER; /* Mutex for synchronizing c static const char **gAvailableConverters = NULL; static uint16_t gAvailableConverterCount = 0; +static icu::UInitOnce gAvailableConvertersInitOnce = U_INITONCE_INITIALIZER; #if !U_CHARSET_IS_UTF8 @@ -187,15 +223,18 @@ static UBool gDefaultConverterContainsOption; static const char DATA_TYPE[] = "cnv"; +/* ucnv_flushAvailableConverterCache. This is only called from ucnv_cleanup(). + * If it is ever to be called from elsewhere, synchronization + * will need to be considered. + */ static void ucnv_flushAvailableConverterCache() { + gAvailableConverterCount = 0; if (gAvailableConverters) { - umtx_lock(&cnvCacheMutex); - gAvailableConverterCount = 0; uprv_free((char **)gAvailableConverters); gAvailableConverters = NULL; - umtx_unlock(&cnvCacheMutex); } + gAvailableConvertersInitOnce.reset(); } /* ucnv_cleanup - delete all storage held by the converter cache, except any */ @@ -255,6 +294,7 @@ ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCo if( (uint16_t)type >= UCNV_NUMBER_OF_SUPPORTED_CONVERTER_TYPES || converterData[type] == NULL || + !converterData[type]->isReferenceCounted || converterData[type]->referenceCounter != 1 || source->structSize != sizeof(UConverterStaticData)) { @@ -271,26 +311,6 @@ ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCo /* copy initial values from the static structure for this type */ uprv_memcpy(data, converterData[type], sizeof(UConverterSharedData)); -#if 0 /* made UConverterMBCSTable part of UConverterSharedData -- markus 20031107 */ - /* - * It would be much more efficient if the table were a direct member, not a pointer. - * However, that would add to the size of all UConverterSharedData objects - * even if they do not use this table (especially algorithmic ones). - * If this changes, then the static templates from converterData[type] - * need more entries. - * - * In principle, it would be cleaner if the load() function below - * allocated the table. - */ - data->table = (UConverterTable *)uprv_malloc(sizeof(UConverterTable)); - if(data->table == NULL) { - uprv_free(data); - *status = U_MEMORY_ALLOCATION_ERROR; - return NULL; - } - uprv_memset(data->table, 0, sizeof(UConverterTable)); -#endif - data->staticData = source; data->sharedDataCached = FALSE; @@ -301,7 +321,6 @@ ucnv_data_unFlattenClone(UConverterLoadArgs *pArgs, UDataMemory *pData, UErrorCo if(data->impl->load != NULL) { data->impl->load(data, pArgs, raw + source->structSize, status); if(U_FAILURE(*status)) { - uprv_free(data->table); uprv_free(data); return NULL; } @@ -368,7 +387,7 @@ getAlgorithmicTypeFromName(const char *realName) /* do a binary search for the alias */ start = 0; - limit = sizeof(cnvNameType)/sizeof(cnvNameType[0]); + limit = UPRV_LENGTHOF(cnvNameType); mid = limit; lastMid = UINT32_MAX; @@ -505,25 +524,6 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData) udata_close(data); } - if(deadSharedData->table != NULL) - { - uprv_free(deadSharedData->table); - } - -#if 0 - /* if the static data is actually owned by the shared data */ - /* enable if we ever have this situation. */ - if(deadSharedData->staticDataOwned == TRUE) /* see ucnv_bld.h */ - { - uprv_free((void*)deadSharedData->staticData); - } -#endif - -#if 0 - /* Zap it ! */ - uprv_memset(deadSharedData->0, sizeof(*deadSharedData)); -#endif - uprv_free(deadSharedData); UTRACE_EXIT_VALUE((int32_t)TRUE); @@ -574,7 +574,7 @@ ucnv_load(UConverterLoadArgs *pArgs, UErrorCode *err) { /** * Unload a non-algorithmic converter. - * It must be sharedData->referenceCounter != ~0 + * It must be sharedData->isReferenceCounted * and this function must be called inside umtx_lock(&cnvCacheMutex). */ U_CAPI void @@ -593,12 +593,7 @@ ucnv_unload(UConverterSharedData *sharedData) { U_CFUNC void ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData) { - /* - Checking whether it's an algorithic converter is okay - in multithreaded applications because the value never changes. - Don't check referenceCounter for any other value. - */ - if(sharedData != NULL && sharedData->referenceCounter != (uint32_t)~0) { + if(sharedData != NULL && sharedData->isReferenceCounted) { umtx_lock(&cnvCacheMutex); ucnv_unload(sharedData); umtx_unlock(&cnvCacheMutex); @@ -608,12 +603,7 @@ ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData) U_CFUNC void ucnv_incrementRefCount(UConverterSharedData *sharedData) { - /* - Checking whether it's an algorithic converter is okay - in multithreaded applications because the value never changes. - Don't check referenceCounter for any other value. - */ - if(sharedData != NULL && sharedData->referenceCounter != (uint32_t)~0) { + if(sharedData != NULL && sharedData->isReferenceCounted) { umtx_lock(&cnvCacheMutex); sharedData->referenceCounter++; umtx_unlock(&cnvCacheMutex); @@ -903,12 +893,7 @@ ucnv_createAlgorithmicConverter(UConverter *myUConverter, } sharedData = converterData[type]; - /* - Checking whether it's an algorithic converter is okay - in multithreaded applications because the value never changes. - Don't check referenceCounter for any other value. - */ - if(sharedData == NULL || sharedData->referenceCounter != (uint32_t)~0) { + if(sharedData == NULL || sharedData->isReferenceCounted) { /* not a valid type, or not an algorithmic converter */ *err = U_ILLEGAL_ARGUMENT_ERROR; UTRACE_EXIT_STATUS(U_ILLEGAL_ARGUMENT_ERROR); @@ -1081,7 +1066,7 @@ ucnv_flushCache () i = 0; do { remaining = 0; - pos = -1; + pos = UHASH_FIRST; while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL) { mySharedData = (UConverterSharedData *) e->value.pointer; @@ -1110,59 +1095,46 @@ ucnv_flushCache () /* available converters list --------------------------------------------------- */ -static UBool haveAvailableConverterList(UErrorCode *pErrorCode) { - int needInit; - UMTX_CHECK(&cnvCacheMutex, (gAvailableConverters == NULL), needInit); - if (needInit) { - UConverter tempConverter; - UEnumeration *allConvEnum = NULL; - uint16_t idx; - uint16_t localConverterCount; - uint16_t allConverterCount; - UErrorCode localStatus; - const char *converterName; - const char **localConverterList; - - allConvEnum = ucnv_openAllNames(pErrorCode); - allConverterCount = uenum_count(allConvEnum, pErrorCode); - if (U_FAILURE(*pErrorCode)) { - return FALSE; - } +static void U_CALLCONV initAvailableConvertersList(UErrorCode &errCode) { + U_ASSERT(gAvailableConverterCount == 0); + U_ASSERT(gAvailableConverters == NULL); - /* We can't have more than "*converterTable" converters to open */ - localConverterList = (const char **) uprv_malloc(allConverterCount * sizeof(char*)); - if (!localConverterList) { - *pErrorCode = U_MEMORY_ALLOCATION_ERROR; - return FALSE; - } + ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); + UEnumeration *allConvEnum = ucnv_openAllNames(&errCode); + int32_t allConverterCount = uenum_count(allConvEnum, &errCode); + if (U_FAILURE(errCode)) { + return; + } - /* Open the default converter to make sure that it has first dibs in the hash table. */ - localStatus = U_ZERO_ERROR; - ucnv_close(ucnv_createConverter(&tempConverter, NULL, &localStatus)); + /* We can't have more than "*converterTable" converters to open */ + gAvailableConverters = (const char **) uprv_malloc(allConverterCount * sizeof(char*)); + if (!gAvailableConverters) { + errCode = U_MEMORY_ALLOCATION_ERROR; + return; + } - localConverterCount = 0; + /* Open the default converter to make sure that it has first dibs in the hash table. */ + UErrorCode localStatus = U_ZERO_ERROR; + UConverter tempConverter; + ucnv_close(ucnv_createConverter(&tempConverter, NULL, &localStatus)); - for (idx = 0; idx < allConverterCount; idx++) { - localStatus = U_ZERO_ERROR; - converterName = uenum_next(allConvEnum, NULL, &localStatus); - if (ucnv_canCreateConverter(converterName, &localStatus)) { - localConverterList[localConverterCount++] = converterName; - } - } - uenum_close(allConvEnum); + gAvailableConverterCount = 0; - umtx_lock(&cnvCacheMutex); - if (gAvailableConverters == NULL) { - gAvailableConverterCount = localConverterCount; - gAvailableConverters = localConverterList; - ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); - } - else { - uprv_free((char **)localConverterList); + for (int32_t idx = 0; idx < allConverterCount; idx++) { + localStatus = U_ZERO_ERROR; + const char *converterName = uenum_next(allConvEnum, NULL, &localStatus); + if (ucnv_canCreateConverter(converterName, &localStatus)) { + gAvailableConverters[gAvailableConverterCount++] = converterName; } - umtx_unlock(&cnvCacheMutex); } - return TRUE; + + uenum_close(allConvEnum); +} + + +static UBool haveAvailableConverterList(UErrorCode *pErrorCode) { + umtx_initOnce(gAvailableConvertersInitOnce, &initAvailableConvertersList, *pErrorCode); + return U_SUCCESS(*pErrorCode); } U_CFUNC uint16_t @@ -1228,6 +1200,9 @@ internalSetName(const char *name, UErrorCode *status) { /* gDefaultConverterName MUST be the last global var set by this function. */ /* It is the variable checked in ucnv_getDefaultName() to see if initialization is required. */ + // But there is nothing here preventing that from being reordered, either by the compiler + // or hardware. I'm adding the mutex to ucnv_getDefaultName for now. UMTX_CHECK is not enough. + // -- Andy gDefaultConverterName = gDefaultConverterNameBuffer; ucln_common_registerCleanup(UCLN_COMMON_UCNV, ucnv_cleanup); @@ -1253,10 +1228,13 @@ ucnv_getDefaultName() { const char *name; /* - Multiple calls to ucnv_getDefaultName must be thread safe, + Concurrent calls to ucnv_getDefaultName must be thread safe, but ucnv_setDefaultName is not thread safe. */ - UMTX_CHECK(&cnvCacheMutex, gDefaultConverterName, name); + { + icu::Mutex lock(&cnvCacheMutex); + name = gDefaultConverterName; + } if(name==NULL) { UErrorCode errorCode = U_ZERO_ERROR; UConverter *cnv = NULL;