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

View File

@ -5,6 +5,7 @@
#ifndef _ICU_CATEGORY_DATA_H
#define _ICU_CATEGORY_DATA_H
#include <pthread.h>
#include <unicode/locid.h>
#include <unicode/ucnv.h>
@ -12,6 +13,8 @@
#include <SupportDefs.h>
#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();
};

View File

@ -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,

View File

@ -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);

View File

@ -9,6 +9,7 @@
#include "LocaleBackend.h"
#include <locale.h>
#include <pthread.h>
#include <timelocal.h>
#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;

View File

@ -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,

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -10,13 +10,16 @@
#include <unicode/unistr.h>
#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;

View File

@ -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];
}

View File

@ -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<ICUThreadLocalStorageValue*>(value);
delete tlsValue;
}
} // namespace Libroot
} // namespace BPrivate

View File

@ -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)

View File

@ -14,6 +14,12 @@ namespace BPrivate {
namespace Libroot {
ICUMessagesData::ICUMessagesData(pthread_key_t tlsKey)
: inherited(tlsKey)
{
}
void
ICUMessagesData::Initialize(LocaleMessagesDataBridge* dataBridge)
{

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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)
{