diff --git a/headers/private/libroot/locale/ICUCategoryData.h b/headers/private/libroot/locale/ICUCategoryData.h index 78515117a6..7da090482d 100644 --- a/headers/private/libroot/locale/ICUCategoryData.h +++ b/headers/private/libroot/locale/ICUCategoryData.h @@ -5,6 +5,7 @@ #ifndef _ICU_CATEGORY_DATA_H #define _ICU_CATEGORY_DATA_H +#include #include #include @@ -12,6 +13,8 @@ #include +#include "ICUConverterManager.h" + namespace BPrivate { namespace Libroot { @@ -19,14 +22,14 @@ namespace Libroot { class ICUCategoryData { public: - ICUCategoryData(); + ICUCategoryData(pthread_key_t tlsKey); virtual ~ICUCategoryData(); virtual status_t SetTo(const Locale& locale, const char* posixLocaleName); virtual status_t SetToPosix(); - const char * PosixLocaleName() + const char* PosixLocaleName() { return fPosixLocaleName; } protected: @@ -35,16 +38,18 @@ protected: char* destination, int destinationSize, const char* defaultValue = ""); + status_t _GetConverter(ICUConverterRef& converterRefOut); + static const uint16 skMaxPosixLocaleNameLen = 128; static const size_t skLCBufSize = 16; + pthread_key_t fThreadLocalStorageKey; Locale fLocale; - UConverter* fConverter; char fPosixLocaleName[skMaxPosixLocaleNameLen]; char fGivenCharset[UCNV_MAX_CONVERTER_NAME_LENGTH]; private: - status_t _SetupConverter(); + status_t _SetupConverter(); }; diff --git a/headers/private/libroot/locale/ICUCollateData.h b/headers/private/libroot/locale/ICUCollateData.h index c22daf6297..4d30cc7663 100644 --- a/headers/private/libroot/locale/ICUCollateData.h +++ b/headers/private/libroot/locale/ICUCollateData.h @@ -19,7 +19,7 @@ class ICUCollateData : public ICUCategoryData { typedef ICUCategoryData inherited; public: - ICUCollateData(); + ICUCollateData(pthread_key_t tlsKey); virtual ~ICUCollateData(); virtual status_t SetTo(const Locale& locale, diff --git a/headers/private/libroot/locale/ICUCtypeData.h b/headers/private/libroot/locale/ICUCtypeData.h index e6a74bfefa..e62db41550 100644 --- a/headers/private/libroot/locale/ICUCtypeData.h +++ b/headers/private/libroot/locale/ICUCtypeData.h @@ -17,7 +17,7 @@ namespace Libroot { class ICUCtypeData : public ICUCategoryData { typedef ICUCategoryData inherited; public: - ICUCtypeData(); + ICUCtypeData(pthread_key_t tlsKey); virtual ~ICUCtypeData(); void Initialize(LocaleCtypeDataBridge* dataBridge); diff --git a/headers/private/libroot/locale/ICULocaleBackend.h b/headers/private/libroot/locale/ICULocaleBackend.h index a4292ec902..de3c1afb4f 100644 --- a/headers/private/libroot/locale/ICULocaleBackend.h +++ b/headers/private/libroot/locale/ICULocaleBackend.h @@ -9,6 +9,7 @@ #include "LocaleBackend.h" #include +#include #include #include "ICUCollateData.h" @@ -57,6 +58,9 @@ private: const char* _QueryLocale(int category); const char* _SetPosixLocale(int category); + static pthread_key_t _CreateThreadLocalStorageKey(); + static void _DestroyThreadLocalStorageValue(void* value); + // buffer for locale names (up to one per category) char fLocaleDescription[512]; @@ -64,6 +68,9 @@ private: struct lconv fLocaleConv; struct lc_time_t fLCTimeInfo; + // + pthread_key_t fThreadLocalStorageKey; + // these work on the data containers above ICUCollateData fCollateData; ICUCtypeData fCtypeData; diff --git a/headers/private/libroot/locale/ICULocaleconvData.h b/headers/private/libroot/locale/ICULocaleconvData.h index 7e86e2143e..96823a7ca1 100644 --- a/headers/private/libroot/locale/ICULocaleconvData.h +++ b/headers/private/libroot/locale/ICULocaleconvData.h @@ -21,6 +21,8 @@ class ICULocaleconvData : public ICUCategoryData { typedef ICUCategoryData inherited; protected: + ICULocaleconvData(pthread_key_t tlsKey); + status_t _SetLocaleconvEntry( const DecimalFormatSymbols* formatSymbols, char* destination, FormatSymbol symbol, diff --git a/headers/private/libroot/locale/ICUMessagesData.h b/headers/private/libroot/locale/ICUMessagesData.h index fe94ded256..7790da78d9 100644 --- a/headers/private/libroot/locale/ICUMessagesData.h +++ b/headers/private/libroot/locale/ICUMessagesData.h @@ -16,7 +16,10 @@ namespace Libroot { class ICUMessagesData : public ICUCategoryData { typedef ICUCategoryData inherited; + public: + ICUMessagesData(pthread_key_t tlsKey); + virtual status_t SetTo(const Locale& locale, const char* posixLocaleName); virtual status_t SetToPosix(); diff --git a/headers/private/libroot/locale/ICUMonetaryData.h b/headers/private/libroot/locale/ICUMonetaryData.h index 5d3571ed5a..ca62f54199 100644 --- a/headers/private/libroot/locale/ICUMonetaryData.h +++ b/headers/private/libroot/locale/ICUMonetaryData.h @@ -18,6 +18,7 @@ namespace Libroot { class ICUMonetaryData : public ICULocaleconvData { typedef ICULocaleconvData inherited; + public: static const int32 kParenthesesAroundCurrencyAndValue = 0; static const int32 kSignPrecedesCurrencyAndValue = 1; @@ -25,7 +26,8 @@ public: static const int32 kSignImmediatelyPrecedesCurrency = 3; static const int32 kSignImmediatelySucceedsCurrency = 4; - ICUMonetaryData(struct lconv& localeConv); + ICUMonetaryData(pthread_key_t tlsKey, + struct lconv& localeConv); void Initialize( LocaleMonetaryDataBridge* dataBridge); diff --git a/headers/private/libroot/locale/ICUNumericData.h b/headers/private/libroot/locale/ICUNumericData.h index c95ad4d5ed..b41d4271ee 100644 --- a/headers/private/libroot/locale/ICUNumericData.h +++ b/headers/private/libroot/locale/ICUNumericData.h @@ -18,7 +18,8 @@ class ICUNumericData : public ICULocaleconvData { typedef ICULocaleconvData inherited; public: - ICUNumericData(struct lconv& localeConv); + ICUNumericData(pthread_key_t tlsKey, + struct lconv& localeConv); void Initialize(LocaleNumericDataBridge* dataBridge); diff --git a/headers/private/libroot/locale/ICUTimeData.h b/headers/private/libroot/locale/ICUTimeData.h index d3a8384df7..10b37b95d1 100644 --- a/headers/private/libroot/locale/ICUTimeData.h +++ b/headers/private/libroot/locale/ICUTimeData.h @@ -21,7 +21,8 @@ namespace Libroot { class ICUTimeData : public ICUCategoryData { typedef ICUCategoryData inherited; public: - ICUTimeData(struct lc_time_t& lcTimeInfo); + ICUTimeData(pthread_key_t tlsKey, + struct lc_time_t& lcTimeInfo); ~ICUTimeData(); void Initialize(LocaleTimeDataBridge* dataBridge); diff --git a/src/system/libroot/add-ons/icu/ICUCategoryData.cpp b/src/system/libroot/add-ons/icu/ICUCategoryData.cpp index 0f7e2acf90..17730f83a7 100644 --- a/src/system/libroot/add-ons/icu/ICUCategoryData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCategoryData.cpp @@ -15,9 +15,7 @@ namespace BPrivate { namespace Libroot { -ICUCategoryData::ICUCategoryData() - : - fConverter(NULL) +ICUCategoryData::ICUCategoryData(pthread_key_t tlsKey) { *fPosixLocaleName = '\0'; *fGivenCharset = '\0'; @@ -26,32 +24,42 @@ ICUCategoryData::ICUCategoryData() ICUCategoryData::~ICUCategoryData() { - if (fConverter) - ucnv_close(fConverter); } status_t -ICUCategoryData::_SetupConverter() +ICUCategoryData::_GetConverter(ICUConverterRef& converterRefOut) { - if (fConverter != NULL) { - ucnv_close(fConverter); - fConverter = NULL; + // we use different converter-IDs per thread in order to avoid converters + // being used by more than one thread + ICUThreadLocalStorageValue* tlsValue = NULL; + status_t result = ICUThreadLocalStorageValue::GetInstanceForKey( + fThreadLocalStorageKey, tlsValue); + if (result != B_OK) + return result; + + ICUConverterRef converterRef; + result = ICUConverterManager::Instance()->GetConverter( + tlsValue->converterID, converterRef); + if (result == B_OK) { + if (strcmp(converterRef->Charset(), fGivenCharset) == 0) { + converterRefOut = converterRef; + return B_OK; + } + + // charset no longer matches the converter, we need to dump it and + // create a new one + ICUConverterManager::Instance()->DropConverter(tlsValue->converterID); + tlsValue->converterID = 0; } - UErrorCode icuStatus = U_ZERO_ERROR; - fConverter = ucnv_open(fGivenCharset, &icuStatus); - if (fConverter == NULL) - return B_NAME_NOT_FOUND; + // create a new converter for the current charset + result = ICUConverterManager::Instance()->CreateConverter(fGivenCharset, + converterRef, tlsValue->converterID); + if (result != B_OK) + return result; - icuStatus = U_ZERO_ERROR; - ucnv_setToUCallBack(fConverter, UCNV_TO_U_CALLBACK_STOP, NULL, NULL, - NULL, &icuStatus); - icuStatus = U_ZERO_ERROR; - ucnv_setFromUCallBack(fConverter, UCNV_FROM_U_CALLBACK_STOP, NULL, NULL, - NULL, &icuStatus); - if (!U_SUCCESS(icuStatus)) - return B_ERROR; + converterRefOut = converterRef; return B_OK; } @@ -105,10 +113,13 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry( const UnicodeString& string, char* destination, int destinationSize, const char* defaultValue) { - status_t result = B_OK; - UErrorCode icuStatus = U_ZERO_ERROR; + ICUConverterRef converterRef; + status_t result = _GetConverter(converterRef); + if (result != B_OK) + return result; - ucnv_fromUChars(fConverter, destination, destinationSize, + UErrorCode icuStatus = U_ZERO_ERROR; + ucnv_fromUChars(converterRef->Converter(), destination, destinationSize, string.getBuffer(), string.length(), &icuStatus); if (!U_SUCCESS(icuStatus)) { switch (icuStatus) { @@ -131,5 +142,13 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry( } +status_t +ICUCategoryData::_SetupConverter() +{ + ICUConverterRef converterRef; + return _GetConverter(converterRef); +} + + } // namespace Libroot } // namespace BPrivate diff --git a/src/system/libroot/add-ons/icu/ICUCollateData.cpp b/src/system/libroot/add-ons/icu/ICUCollateData.cpp index c394886309..75f7c41c41 100644 --- a/src/system/libroot/add-ons/icu/ICUCollateData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCollateData.cpp @@ -10,13 +10,16 @@ #include +#include "ICUConverterManager.h" + namespace BPrivate { namespace Libroot { -ICUCollateData::ICUCollateData() +ICUCollateData::ICUCollateData(pthread_key_t tlsKey) : + inherited(tlsKey), fCollator(NULL) { } @@ -150,8 +153,14 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) if (inLen == 0) return B_OK; + ICUConverterRef converterRef; + status_t result = _GetConverter(converterRef); + if (result != B_OK) + return result; + UErrorCode icuStatus = U_ZERO_ERROR; - int32_t outLen = ucnv_toUChars(fConverter, NULL, 0, in, inLen, &icuStatus); + int32_t outLen = ucnv_toUChars(converterRef->Converter(), NULL, 0, in, + inLen, &icuStatus); if (icuStatus != U_BUFFER_OVERFLOW_ERROR) return B_BAD_VALUE; if (outLen < 0) @@ -161,8 +170,8 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out) UChar* outBuf = out.getBuffer(outLen + 1); icuStatus = U_ZERO_ERROR; - outLen - = ucnv_toUChars(fConverter, outBuf, outLen + 1, in, inLen, &icuStatus); + outLen = ucnv_toUChars(converterRef->Converter(), outBuf, outLen + 1, in, + inLen, &icuStatus); if (!U_SUCCESS(icuStatus)) { out.releaseBuffer(0); return B_BAD_VALUE; diff --git a/src/system/libroot/add-ons/icu/ICUCtypeData.cpp b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp index 4e6860532e..3a4d64cd87 100644 --- a/src/system/libroot/add-ons/icu/ICUCtypeData.cpp +++ b/src/system/libroot/add-ons/icu/ICUCtypeData.cpp @@ -16,8 +16,9 @@ namespace BPrivate { namespace Libroot { -ICUCtypeData::ICUCtypeData() +ICUCtypeData::ICUCtypeData(pthread_key_t tlsKey) : + inherited(tlsKey), fDataBridge(NULL) { } @@ -47,7 +48,14 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName) UErrorCode icuStatus = U_ZERO_ERROR; - ucnv_reset(fConverter); + ICUConverterRef converterRef; + result = _GetConverter(converterRef); + if (result != B_OK) + return result; + + UConverter* converter = converterRef->Converter(); + + ucnv_reset(converter); char buffer[] = { 0, 0 }; for (int i = 0; i < 256; ++i) { const char* source = buffer; @@ -55,7 +63,7 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName) buffer[1] = '\0'; icuStatus = U_ZERO_ERROR; UChar32 unicodeChar - = ucnv_getNextUChar(fConverter, &source, source + 1, &icuStatus); + = ucnv_getNextUChar(converter, &source, source + 1, &icuStatus); unsigned short classInfo = 0; unsigned int toLower = i; @@ -88,13 +96,13 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName) UChar lowerChar = u_tolower(unicodeChar); icuStatus = U_ZERO_ERROR; - ucnv_fromUChars(fConverter, buffer, 1, &lowerChar, 1, &icuStatus); + ucnv_fromUChars(converter, buffer, 1, &lowerChar, 1, &icuStatus); if (U_SUCCESS(icuStatus)) toLower = (unsigned char)buffer[0]; UChar upperChar = u_toupper(unicodeChar); icuStatus = U_ZERO_ERROR; - ucnv_fromUChars(fConverter, buffer, 1, &upperChar, 1, &icuStatus); + ucnv_fromUChars(converter, buffer, 1, &upperChar, 1, &icuStatus); if (U_SUCCESS(icuStatus)) toUpper = (unsigned char)buffer[0]; } diff --git a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp index 52bff29e62..8733b0fe80 100644 --- a/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp +++ b/src/system/libroot/add-ons/icu/ICULocaleBackend.cpp @@ -28,9 +28,13 @@ CreateInstance() ICULocaleBackend::ICULocaleBackend() : - fMonetaryData(fLocaleConv), - fNumericData(fLocaleConv), - fTimeData(fLCTimeInfo), + fThreadLocalStorageKey(_CreateThreadLocalStorageKey()), + fCollateData(fThreadLocalStorageKey), + fCtypeData(fThreadLocalStorageKey), + fMessagesData(fThreadLocalStorageKey), + fMonetaryData(fThreadLocalStorageKey, fLocaleConv), + fNumericData(fThreadLocalStorageKey, fLocaleConv), + fTimeData(fThreadLocalStorageKey, fLCTimeInfo), fTimeConversion(fTimeData) { } @@ -38,6 +42,7 @@ ICULocaleBackend::ICULocaleBackend() ICULocaleBackend::~ICULocaleBackend() { + pthread_key_delete(fThreadLocalStorageKey); } @@ -371,5 +376,25 @@ ICULocaleBackend::_SetPosixLocale(int category) } +pthread_key_t +ICULocaleBackend::_CreateThreadLocalStorageKey() +{ + pthread_key_t key; + + pthread_key_create(&key, ICULocaleBackend::_DestroyThreadLocalStorageValue); + + return key; +} + + +void ICULocaleBackend::_DestroyThreadLocalStorageValue(void* value) +{ + ICUThreadLocalStorageValue* tlsValue + = static_cast(value); + + delete tlsValue; +} + + } // namespace Libroot } // namespace BPrivate diff --git a/src/system/libroot/add-ons/icu/ICULocaleconvData.cpp b/src/system/libroot/add-ons/icu/ICULocaleconvData.cpp index f59272ea55..1b64b158e4 100644 --- a/src/system/libroot/add-ons/icu/ICULocaleconvData.cpp +++ b/src/system/libroot/add-ons/icu/ICULocaleconvData.cpp @@ -13,6 +13,12 @@ namespace BPrivate { namespace Libroot { +ICULocaleconvData::ICULocaleconvData(pthread_key_t tlsKey) + : inherited(tlsKey) +{ +} + + status_t ICULocaleconvData::_SetLocaleconvEntry(const DecimalFormatSymbols* formatSymbols, char* destination, FormatSymbol symbol, const char* defaultValue) diff --git a/src/system/libroot/add-ons/icu/ICUMessagesData.cpp b/src/system/libroot/add-ons/icu/ICUMessagesData.cpp index dafcfe4abf..c2e0fba316 100644 --- a/src/system/libroot/add-ons/icu/ICUMessagesData.cpp +++ b/src/system/libroot/add-ons/icu/ICUMessagesData.cpp @@ -14,6 +14,12 @@ namespace BPrivate { namespace Libroot { +ICUMessagesData::ICUMessagesData(pthread_key_t tlsKey) + : inherited(tlsKey) +{ +} + + void ICUMessagesData::Initialize(LocaleMessagesDataBridge* dataBridge) { diff --git a/src/system/libroot/add-ons/icu/ICUMonetaryData.cpp b/src/system/libroot/add-ons/icu/ICUMonetaryData.cpp index a7d470fdb0..597a7f1f82 100644 --- a/src/system/libroot/add-ons/icu/ICUMonetaryData.cpp +++ b/src/system/libroot/add-ons/icu/ICUMonetaryData.cpp @@ -15,8 +15,9 @@ namespace BPrivate { namespace Libroot { -ICUMonetaryData::ICUMonetaryData(struct lconv& localeConv) +ICUMonetaryData::ICUMonetaryData(pthread_key_t tlsKey, struct lconv& localeConv) : + inherited(tlsKey), fLocaleConv(localeConv), fPosixLocaleConv(NULL) { diff --git a/src/system/libroot/add-ons/icu/ICUNumericData.cpp b/src/system/libroot/add-ons/icu/ICUNumericData.cpp index 85bec2d9b2..c21cae0170 100644 --- a/src/system/libroot/add-ons/icu/ICUNumericData.cpp +++ b/src/system/libroot/add-ons/icu/ICUNumericData.cpp @@ -15,8 +15,9 @@ namespace BPrivate { namespace Libroot { -ICUNumericData::ICUNumericData(struct lconv& localeConv) +ICUNumericData::ICUNumericData(pthread_key_t tlsKey, struct lconv& localeConv) : + inherited(tlsKey), fLocaleConv(localeConv), fDataBridge(NULL) { diff --git a/src/system/libroot/add-ons/icu/ICUTimeData.cpp b/src/system/libroot/add-ons/icu/ICUTimeData.cpp index 4354150f55..aeeeca586e 100644 --- a/src/system/libroot/add-ons/icu/ICUTimeData.cpp +++ b/src/system/libroot/add-ons/icu/ICUTimeData.cpp @@ -20,8 +20,9 @@ namespace BPrivate { namespace Libroot { -ICUTimeData::ICUTimeData(struct lc_time_t& lcTimeInfo) +ICUTimeData::ICUTimeData(pthread_key_t tlsKey, struct lc_time_t& lcTimeInfo) : + inherited(tlsKey), fLCTimeInfo(lcTimeInfo), fDataBridge(NULL) {