Use TLS and converter manager in locale backend.

This commit is contained in:
Oliver Tappe
2011-11-22 17:17:18 +01:00
parent bcadc4ca66
commit bf5ff48092
18 changed files with 145 additions and 48 deletions
@@ -5,6 +5,7 @@
#ifndef _ICU_CATEGORY_DATA_H #ifndef _ICU_CATEGORY_DATA_H
#define _ICU_CATEGORY_DATA_H #define _ICU_CATEGORY_DATA_H
#include <pthread.h>
#include <unicode/locid.h> #include <unicode/locid.h>
#include <unicode/ucnv.h> #include <unicode/ucnv.h>
@@ -12,6 +13,8 @@
#include <SupportDefs.h> #include <SupportDefs.h>
#include "ICUConverterManager.h"
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
@@ -19,14 +22,14 @@ namespace Libroot {
class ICUCategoryData { class ICUCategoryData {
public: public:
ICUCategoryData(); ICUCategoryData(pthread_key_t tlsKey);
virtual ~ICUCategoryData(); virtual ~ICUCategoryData();
virtual status_t SetTo(const Locale& locale, virtual status_t SetTo(const Locale& locale,
const char* posixLocaleName); const char* posixLocaleName);
virtual status_t SetToPosix(); virtual status_t SetToPosix();
const char * PosixLocaleName() const char* PosixLocaleName()
{ return fPosixLocaleName; } { return fPosixLocaleName; }
protected: protected:
@@ -35,16 +38,18 @@ protected:
char* destination, int destinationSize, char* destination, int destinationSize,
const char* defaultValue = ""); const char* defaultValue = "");
status_t _GetConverter(ICUConverterRef& converterRefOut);
static const uint16 skMaxPosixLocaleNameLen = 128; static const uint16 skMaxPosixLocaleNameLen = 128;
static const size_t skLCBufSize = 16; static const size_t skLCBufSize = 16;
pthread_key_t fThreadLocalStorageKey;
Locale fLocale; Locale fLocale;
UConverter* fConverter;
char fPosixLocaleName[skMaxPosixLocaleNameLen]; char fPosixLocaleName[skMaxPosixLocaleNameLen];
char fGivenCharset[UCNV_MAX_CONVERTER_NAME_LENGTH]; char fGivenCharset[UCNV_MAX_CONVERTER_NAME_LENGTH];
private: private:
status_t _SetupConverter(); status_t _SetupConverter();
}; };
@@ -19,7 +19,7 @@ class ICUCollateData : public ICUCategoryData {
typedef ICUCategoryData inherited; typedef ICUCategoryData inherited;
public: public:
ICUCollateData(); ICUCollateData(pthread_key_t tlsKey);
virtual ~ICUCollateData(); virtual ~ICUCollateData();
virtual status_t SetTo(const Locale& locale, virtual status_t SetTo(const Locale& locale,
@@ -17,7 +17,7 @@ namespace Libroot {
class ICUCtypeData : public ICUCategoryData { class ICUCtypeData : public ICUCategoryData {
typedef ICUCategoryData inherited; typedef ICUCategoryData inherited;
public: public:
ICUCtypeData(); ICUCtypeData(pthread_key_t tlsKey);
virtual ~ICUCtypeData(); virtual ~ICUCtypeData();
void Initialize(LocaleCtypeDataBridge* dataBridge); void Initialize(LocaleCtypeDataBridge* dataBridge);
@@ -9,6 +9,7 @@
#include "LocaleBackend.h" #include "LocaleBackend.h"
#include <locale.h> #include <locale.h>
#include <pthread.h>
#include <timelocal.h> #include <timelocal.h>
#include "ICUCollateData.h" #include "ICUCollateData.h"
@@ -57,6 +58,9 @@ private:
const char* _QueryLocale(int category); const char* _QueryLocale(int category);
const char* _SetPosixLocale(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) // buffer for locale names (up to one per category)
char fLocaleDescription[512]; char fLocaleDescription[512];
@@ -64,6 +68,9 @@ private:
struct lconv fLocaleConv; struct lconv fLocaleConv;
struct lc_time_t fLCTimeInfo; struct lc_time_t fLCTimeInfo;
//
pthread_key_t fThreadLocalStorageKey;
// these work on the data containers above // these work on the data containers above
ICUCollateData fCollateData; ICUCollateData fCollateData;
ICUCtypeData fCtypeData; ICUCtypeData fCtypeData;
@@ -21,6 +21,8 @@ class ICULocaleconvData : public ICUCategoryData {
typedef ICUCategoryData inherited; typedef ICUCategoryData inherited;
protected: protected:
ICULocaleconvData(pthread_key_t tlsKey);
status_t _SetLocaleconvEntry( status_t _SetLocaleconvEntry(
const DecimalFormatSymbols* formatSymbols, const DecimalFormatSymbols* formatSymbols,
char* destination, FormatSymbol symbol, char* destination, FormatSymbol symbol,
@@ -16,7 +16,10 @@ namespace Libroot {
class ICUMessagesData : public ICUCategoryData { class ICUMessagesData : public ICUCategoryData {
typedef ICUCategoryData inherited; typedef ICUCategoryData inherited;
public: public:
ICUMessagesData(pthread_key_t tlsKey);
virtual status_t SetTo(const Locale& locale, virtual status_t SetTo(const Locale& locale,
const char* posixLocaleName); const char* posixLocaleName);
virtual status_t SetToPosix(); virtual status_t SetToPosix();
@@ -18,6 +18,7 @@ namespace Libroot {
class ICUMonetaryData : public ICULocaleconvData { class ICUMonetaryData : public ICULocaleconvData {
typedef ICULocaleconvData inherited; typedef ICULocaleconvData inherited;
public: public:
static const int32 kParenthesesAroundCurrencyAndValue = 0; static const int32 kParenthesesAroundCurrencyAndValue = 0;
static const int32 kSignPrecedesCurrencyAndValue = 1; static const int32 kSignPrecedesCurrencyAndValue = 1;
@@ -25,7 +26,8 @@ public:
static const int32 kSignImmediatelyPrecedesCurrency = 3; static const int32 kSignImmediatelyPrecedesCurrency = 3;
static const int32 kSignImmediatelySucceedsCurrency = 4; static const int32 kSignImmediatelySucceedsCurrency = 4;
ICUMonetaryData(struct lconv& localeConv); ICUMonetaryData(pthread_key_t tlsKey,
struct lconv& localeConv);
void Initialize( void Initialize(
LocaleMonetaryDataBridge* dataBridge); LocaleMonetaryDataBridge* dataBridge);
@@ -18,7 +18,8 @@ class ICUNumericData : public ICULocaleconvData {
typedef ICULocaleconvData inherited; typedef ICULocaleconvData inherited;
public: public:
ICUNumericData(struct lconv& localeConv); ICUNumericData(pthread_key_t tlsKey,
struct lconv& localeConv);
void Initialize(LocaleNumericDataBridge* dataBridge); void Initialize(LocaleNumericDataBridge* dataBridge);
+2 -1
View File
@@ -21,7 +21,8 @@ namespace Libroot {
class ICUTimeData : public ICUCategoryData { class ICUTimeData : public ICUCategoryData {
typedef ICUCategoryData inherited; typedef ICUCategoryData inherited;
public: public:
ICUTimeData(struct lc_time_t& lcTimeInfo); ICUTimeData(pthread_key_t tlsKey,
struct lc_time_t& lcTimeInfo);
~ICUTimeData(); ~ICUTimeData();
void Initialize(LocaleTimeDataBridge* dataBridge); void Initialize(LocaleTimeDataBridge* dataBridge);
@@ -15,9 +15,7 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUCategoryData::ICUCategoryData() ICUCategoryData::ICUCategoryData(pthread_key_t tlsKey)
:
fConverter(NULL)
{ {
*fPosixLocaleName = '\0'; *fPosixLocaleName = '\0';
*fGivenCharset = '\0'; *fGivenCharset = '\0';
@@ -26,32 +24,42 @@ ICUCategoryData::ICUCategoryData()
ICUCategoryData::~ICUCategoryData() ICUCategoryData::~ICUCategoryData()
{ {
if (fConverter)
ucnv_close(fConverter);
} }
status_t status_t
ICUCategoryData::_SetupConverter() ICUCategoryData::_GetConverter(ICUConverterRef& converterRefOut)
{ {
if (fConverter != NULL) { // we use different converter-IDs per thread in order to avoid converters
ucnv_close(fConverter); // being used by more than one thread
fConverter = NULL; 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; // create a new converter for the current charset
fConverter = ucnv_open(fGivenCharset, &icuStatus); result = ICUConverterManager::Instance()->CreateConverter(fGivenCharset,
if (fConverter == NULL) converterRef, tlsValue->converterID);
return B_NAME_NOT_FOUND; if (result != B_OK)
return result;
icuStatus = U_ZERO_ERROR; converterRefOut = converterRef;
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;
return B_OK; return B_OK;
} }
@@ -105,10 +113,13 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
const UnicodeString& string, char* destination, int destinationSize, const UnicodeString& string, char* destination, int destinationSize,
const char* defaultValue) const char* defaultValue)
{ {
status_t result = B_OK; ICUConverterRef converterRef;
UErrorCode icuStatus = U_ZERO_ERROR; 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); string.getBuffer(), string.length(), &icuStatus);
if (!U_SUCCESS(icuStatus)) { if (!U_SUCCESS(icuStatus)) {
switch (icuStatus) { switch (icuStatus) {
@@ -131,5 +142,13 @@ ICUCategoryData::_ConvertUnicodeStringToLocaleconvEntry(
} }
status_t
ICUCategoryData::_SetupConverter()
{
ICUConverterRef converterRef;
return _GetConverter(converterRef);
}
} // namespace Libroot } // namespace Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -10,13 +10,16 @@
#include <unicode/unistr.h> #include <unicode/unistr.h>
#include "ICUConverterManager.h"
namespace BPrivate { namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUCollateData::ICUCollateData() ICUCollateData::ICUCollateData(pthread_key_t tlsKey)
: :
inherited(tlsKey),
fCollator(NULL) fCollator(NULL)
{ {
} }
@@ -150,8 +153,14 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out)
if (inLen == 0) if (inLen == 0)
return B_OK; return B_OK;
ICUConverterRef converterRef;
status_t result = _GetConverter(converterRef);
if (result != B_OK)
return result;
UErrorCode icuStatus = U_ZERO_ERROR; 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) if (icuStatus != U_BUFFER_OVERFLOW_ERROR)
return B_BAD_VALUE; return B_BAD_VALUE;
if (outLen < 0) if (outLen < 0)
@@ -161,8 +170,8 @@ ICUCollateData::_ToUnicodeString(const char* in, UnicodeString& out)
UChar* outBuf = out.getBuffer(outLen + 1); UChar* outBuf = out.getBuffer(outLen + 1);
icuStatus = U_ZERO_ERROR; icuStatus = U_ZERO_ERROR;
outLen outLen = ucnv_toUChars(converterRef->Converter(), outBuf, outLen + 1, in,
= ucnv_toUChars(fConverter, outBuf, outLen + 1, in, inLen, &icuStatus); inLen, &icuStatus);
if (!U_SUCCESS(icuStatus)) { if (!U_SUCCESS(icuStatus)) {
out.releaseBuffer(0); out.releaseBuffer(0);
return B_BAD_VALUE; return B_BAD_VALUE;
@@ -16,8 +16,9 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUCtypeData::ICUCtypeData() ICUCtypeData::ICUCtypeData(pthread_key_t tlsKey)
: :
inherited(tlsKey),
fDataBridge(NULL) fDataBridge(NULL)
{ {
} }
@@ -47,7 +48,14 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
UErrorCode icuStatus = U_ZERO_ERROR; 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 }; char buffer[] = { 0, 0 };
for (int i = 0; i < 256; ++i) { for (int i = 0; i < 256; ++i) {
const char* source = buffer; const char* source = buffer;
@@ -55,7 +63,7 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
buffer[1] = '\0'; buffer[1] = '\0';
icuStatus = U_ZERO_ERROR; icuStatus = U_ZERO_ERROR;
UChar32 unicodeChar UChar32 unicodeChar
= ucnv_getNextUChar(fConverter, &source, source + 1, &icuStatus); = ucnv_getNextUChar(converter, &source, source + 1, &icuStatus);
unsigned short classInfo = 0; unsigned short classInfo = 0;
unsigned int toLower = i; unsigned int toLower = i;
@@ -88,13 +96,13 @@ ICUCtypeData::SetTo(const Locale& locale, const char* posixLocaleName)
UChar lowerChar = u_tolower(unicodeChar); UChar lowerChar = u_tolower(unicodeChar);
icuStatus = U_ZERO_ERROR; icuStatus = U_ZERO_ERROR;
ucnv_fromUChars(fConverter, buffer, 1, &lowerChar, 1, &icuStatus); ucnv_fromUChars(converter, buffer, 1, &lowerChar, 1, &icuStatus);
if (U_SUCCESS(icuStatus)) if (U_SUCCESS(icuStatus))
toLower = (unsigned char)buffer[0]; toLower = (unsigned char)buffer[0];
UChar upperChar = u_toupper(unicodeChar); UChar upperChar = u_toupper(unicodeChar);
icuStatus = U_ZERO_ERROR; icuStatus = U_ZERO_ERROR;
ucnv_fromUChars(fConverter, buffer, 1, &upperChar, 1, &icuStatus); ucnv_fromUChars(converter, buffer, 1, &upperChar, 1, &icuStatus);
if (U_SUCCESS(icuStatus)) if (U_SUCCESS(icuStatus))
toUpper = (unsigned char)buffer[0]; toUpper = (unsigned char)buffer[0];
} }
@@ -28,9 +28,13 @@ CreateInstance()
ICULocaleBackend::ICULocaleBackend() ICULocaleBackend::ICULocaleBackend()
: :
fMonetaryData(fLocaleConv), fThreadLocalStorageKey(_CreateThreadLocalStorageKey()),
fNumericData(fLocaleConv), fCollateData(fThreadLocalStorageKey),
fTimeData(fLCTimeInfo), fCtypeData(fThreadLocalStorageKey),
fMessagesData(fThreadLocalStorageKey),
fMonetaryData(fThreadLocalStorageKey, fLocaleConv),
fNumericData(fThreadLocalStorageKey, fLocaleConv),
fTimeData(fThreadLocalStorageKey, fLCTimeInfo),
fTimeConversion(fTimeData) fTimeConversion(fTimeData)
{ {
} }
@@ -38,6 +42,7 @@ ICULocaleBackend::ICULocaleBackend()
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<ICUThreadLocalStorageValue*>(value);
delete tlsValue;
}
} // namespace Libroot } // namespace Libroot
} // namespace BPrivate } // namespace BPrivate
@@ -13,6 +13,12 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICULocaleconvData::ICULocaleconvData(pthread_key_t tlsKey)
: inherited(tlsKey)
{
}
status_t status_t
ICULocaleconvData::_SetLocaleconvEntry(const DecimalFormatSymbols* formatSymbols, ICULocaleconvData::_SetLocaleconvEntry(const DecimalFormatSymbols* formatSymbols,
char* destination, FormatSymbol symbol, const char* defaultValue) char* destination, FormatSymbol symbol, const char* defaultValue)
@@ -14,6 +14,12 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUMessagesData::ICUMessagesData(pthread_key_t tlsKey)
: inherited(tlsKey)
{
}
void void
ICUMessagesData::Initialize(LocaleMessagesDataBridge* dataBridge) ICUMessagesData::Initialize(LocaleMessagesDataBridge* dataBridge)
{ {
@@ -15,8 +15,9 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUMonetaryData::ICUMonetaryData(struct lconv& localeConv) ICUMonetaryData::ICUMonetaryData(pthread_key_t tlsKey, struct lconv& localeConv)
: :
inherited(tlsKey),
fLocaleConv(localeConv), fLocaleConv(localeConv),
fPosixLocaleConv(NULL) fPosixLocaleConv(NULL)
{ {
@@ -15,8 +15,9 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUNumericData::ICUNumericData(struct lconv& localeConv) ICUNumericData::ICUNumericData(pthread_key_t tlsKey, struct lconv& localeConv)
: :
inherited(tlsKey),
fLocaleConv(localeConv), fLocaleConv(localeConv),
fDataBridge(NULL) fDataBridge(NULL)
{ {
@@ -20,8 +20,9 @@ namespace BPrivate {
namespace Libroot { namespace Libroot {
ICUTimeData::ICUTimeData(struct lc_time_t& lcTimeInfo) ICUTimeData::ICUTimeData(pthread_key_t tlsKey, struct lc_time_t& lcTimeInfo)
: :
inherited(tlsKey),
fLCTimeInfo(lcTimeInfo), fLCTimeInfo(lcTimeInfo),
fDataBridge(NULL) fDataBridge(NULL)
{ {