ICU-2787 The shared converter cache should consistently use one non-global mutex,
and fix the double check in ucnv_io. X-SVN-Rev: 11826
This commit is contained in:
parent
231176f7de
commit
33568a2ee4
@ -27,8 +27,6 @@
|
||||
#include "unicode/uset.h"
|
||||
#include "cmemory.h"
|
||||
#include "cstring.h"
|
||||
#include "umutex.h"
|
||||
#include "uhash.h"
|
||||
#include "ustr_imp.h"
|
||||
#include "ucnv_imp.h"
|
||||
#include "ucnv_io.h"
|
||||
@ -40,18 +38,27 @@
|
||||
# include <stdio.h>
|
||||
void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l)
|
||||
{
|
||||
static FILE *f = NULL;
|
||||
if(f==NULL)
|
||||
{
|
||||
/* stderr, or open another file */
|
||||
f = stderr;
|
||||
/* f = fopen("c:\\UCNV_DEBUG_LOG.txt", "w"); */
|
||||
}
|
||||
static FILE *f = NULL;
|
||||
if(f==NULL)
|
||||
{
|
||||
/* stderr, or open another file */
|
||||
f = stderr;
|
||||
/* f = fopen("c:\\UCNV_DEBUG_LOG.txt", "w"); */
|
||||
}
|
||||
if (!what) {
|
||||
what = "(null)";
|
||||
}
|
||||
if (!who) {
|
||||
who = "(null)";
|
||||
}
|
||||
if (!p) {
|
||||
p = "(null)";
|
||||
}
|
||||
|
||||
fprintf(f, "%p\t:%d\t%-20s\t%-10s\n",
|
||||
p, l, who, what);
|
||||
fprintf(f, "%p\t:%d\t%-20s\t%-10s\n",
|
||||
p, l, who, what);
|
||||
|
||||
fflush(f);
|
||||
fflush(f);
|
||||
}
|
||||
|
||||
|
||||
@ -61,11 +68,15 @@ static void UCNV_DEBUG_CNV(UConverter *c, int line)
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
fprintf(stderr, "%p\t:%d\t", c, line);
|
||||
if(c!=NULL) {
|
||||
fprintf(stderr, "%s\t", ucnv_getName(c, &err));
|
||||
|
||||
const char *name = ucnv_getName(c, &err);
|
||||
if (!name) {
|
||||
name = "(null)";
|
||||
}
|
||||
fprintf(stderr, "%s\t", name);
|
||||
|
||||
fprintf(stderr, "shr=%p, ref=%x\n",
|
||||
c->sharedData,
|
||||
c->sharedData->referenceCounter);
|
||||
c->sharedData,
|
||||
c->sharedData->referenceCounter);
|
||||
} else {
|
||||
fprintf(stderr, "DEMISED\n");
|
||||
}
|
||||
@ -278,13 +289,7 @@ ucnv_safeClone(const UConverter* cnv, void *stackBuffer, int32_t *pBufferSize, U
|
||||
}
|
||||
|
||||
/* increment refcount of shared data if needed */
|
||||
if (cnv->sharedData->referenceCounter != ~0) {
|
||||
umtx_lock (NULL);
|
||||
if (cnv->sharedData->referenceCounter != ~0) {
|
||||
cnv->sharedData->referenceCounter++;
|
||||
}
|
||||
umtx_unlock (NULL);
|
||||
}
|
||||
ucnv_incrementRefCount(cnv->sharedData);
|
||||
|
||||
if(localConverter==NULL || U_FAILURE(*status)) {
|
||||
return NULL;
|
||||
@ -372,29 +377,20 @@ ucnv_close (UConverter * converter)
|
||||
converter->sharedData->impl->close(converter);
|
||||
}
|
||||
|
||||
if (converter->sharedData->referenceCounter != ~0) {
|
||||
umtx_lock (NULL);
|
||||
if (converter->sharedData->referenceCounter != 0) {
|
||||
converter->sharedData->referenceCounter--;
|
||||
}
|
||||
umtx_unlock (NULL);
|
||||
|
||||
#ifdef UCNV_DEBUG
|
||||
{
|
||||
char c[4];
|
||||
c[1]=0;
|
||||
c[0]='0'+converter->sharedData->referenceCounter;
|
||||
UCNV_DEBUG_LOG("close--", c, converter);
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
char c[4];
|
||||
c[0]='0'+converter->sharedData->referenceCounter;
|
||||
c[1]=0;
|
||||
UCNV_DEBUG_LOG("close--", c, converter);
|
||||
if((converter->sharedData->referenceCounter == 0)&&(converter->sharedData->sharedDataCached == FALSE)) {
|
||||
UCNV_DEBUG_CNV(converter);
|
||||
UCNV_DEBUG_LOG("close:delDead", "??", converter);
|
||||
ucnv_deleteSharedConverterData(converter->sharedData);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ucnv_unloadSharedDataIfReady(converter->sharedData);
|
||||
|
||||
if(!converter->isCopyLocal){
|
||||
UCNV_DEBUG_LOG("close:free", "", converter);
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "ustr_imp.h"
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
extern void UCNV_DEBUG_LOG(char *what, char *who, void *p, int l);
|
||||
@ -148,6 +149,27 @@ static UConverterSharedData *createConverterFromFile(const char *pkg, const char
|
||||
|
||||
static const UConverterSharedData *getAlgorithmicTypeFromName(const char *realName);
|
||||
|
||||
/* Stores the shared data in the SHARED_DATA_HASHTABLE
|
||||
* @param data The shared data
|
||||
*/
|
||||
static void ucnv_shareConverterData(UConverterSharedData * data);
|
||||
|
||||
/* gets the shared data from the SHARED_DATA_HASHTABLE (might return NULL if it isn't there)
|
||||
* @param name The name of the shared data
|
||||
* @return the shared data from the SHARED_DATA_HASHTABLE
|
||||
*/
|
||||
static UConverterSharedData *ucnv_getSharedConverterData(const char *name);
|
||||
|
||||
/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to
|
||||
* see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and
|
||||
* returns TRUE,
|
||||
* otherwise returns FALSE
|
||||
* @param sharedConverterData The shared data
|
||||
* @return if not it frees all the memory stemming from sharedConverterData and
|
||||
* returns TRUE, otherwise returns FALSE
|
||||
*/
|
||||
static UBool ucnv_deleteSharedConverterData(UConverterSharedData * sharedConverterData);
|
||||
|
||||
/**
|
||||
* Un flatten shared data from a UDATA..
|
||||
*/
|
||||
@ -281,7 +303,7 @@ getAlgorithmicTypeFromName(const char *realName)
|
||||
/* Puts the shared data in the static hashtable SHARED_DATA_HASHTABLE */
|
||||
/* Will always be called with the cnvCacheMutex alrady being held */
|
||||
/* by the calling function. */
|
||||
void
|
||||
static void
|
||||
ucnv_shareConverterData(UConverterSharedData * data)
|
||||
{
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
@ -322,7 +344,7 @@ ucnv_shareConverterData(UConverterSharedData * data)
|
||||
|
||||
/* Look up a converter name in the shared data cache. */
|
||||
/* cnvCacheMutex must be held by the caller to protect the hash table. */
|
||||
UConverterSharedData *
|
||||
static UConverterSharedData *
|
||||
ucnv_getSharedConverterData(const char *name)
|
||||
{
|
||||
/*special case when no Table has yet been created we return NULL */
|
||||
@ -343,7 +365,7 @@ ucnv_getSharedConverterData(const char *name)
|
||||
/*frees the string of memory blocks associates with a sharedConverter
|
||||
*if and only if the referenceCounter == 0
|
||||
*/
|
||||
UBool
|
||||
static UBool
|
||||
ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
|
||||
{
|
||||
if (deadSharedData->referenceCounter > 0)
|
||||
@ -383,6 +405,40 @@ ucnv_deleteSharedConverterData(UConverterSharedData * deadSharedData)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData)
|
||||
{
|
||||
umtx_lock(&cnvCacheMutex);
|
||||
/*
|
||||
Double checking doesn't work on some platforms.
|
||||
Don't check referenceCounter outside of a mutex block.
|
||||
*/
|
||||
if (sharedData->referenceCounter != ~0) {
|
||||
if (sharedData->referenceCounter > 0) {
|
||||
sharedData->referenceCounter--;
|
||||
}
|
||||
|
||||
if((sharedData->referenceCounter <= 0)&&(sharedData->sharedDataCached == FALSE)) {
|
||||
ucnv_deleteSharedConverterData(sharedData);
|
||||
}
|
||||
}
|
||||
umtx_unlock(&cnvCacheMutex);
|
||||
}
|
||||
|
||||
void
|
||||
ucnv_incrementRefCount(UConverterSharedData *sharedData)
|
||||
{
|
||||
umtx_lock(&cnvCacheMutex);
|
||||
/*
|
||||
Double checking doesn't work on some platforms.
|
||||
Don't check referenceCounter outside of a mutex block.
|
||||
*/
|
||||
if (sharedData->referenceCounter != ~0) {
|
||||
sharedData->referenceCounter++;
|
||||
}
|
||||
umtx_unlock(&cnvCacheMutex);
|
||||
}
|
||||
|
||||
static void
|
||||
parseConverterOptions(const char *inName,
|
||||
char *cnvName,
|
||||
@ -472,7 +528,8 @@ ucnv_createConverter(UConverter *myUConverter, const char *converterName, UError
|
||||
const char *realName;
|
||||
UConverterSharedData *mySharedConverterData = NULL;
|
||||
UErrorCode internalErrorCode = U_ZERO_ERROR;
|
||||
uint32_t options=0;
|
||||
uint32_t options = 0;
|
||||
int32_t cnvNumber = -1;
|
||||
if (U_FAILURE (*err))
|
||||
return NULL;
|
||||
|
||||
@ -495,7 +552,7 @@ ucnv_createConverter(UConverter *myUConverter, const char *converterName, UError
|
||||
}
|
||||
|
||||
/* get the canonical converter name */
|
||||
realName = ucnv_io_getConverterName(cnvName, &internalErrorCode);
|
||||
realName = ucnv_io_getConverterName(cnvName, &cnvNumber, &internalErrorCode);
|
||||
if (U_FAILURE(internalErrorCode) || realName == NULL) {
|
||||
/*
|
||||
* set the input name in case the converter was added
|
||||
@ -541,9 +598,7 @@ ucnv_createConverter(UConverter *myUConverter, const char *converterName, UError
|
||||
{
|
||||
/* The data for this converter was already in the cache. */
|
||||
/* Update the reference counter on the shared data: one more client */
|
||||
umtx_lock(NULL);
|
||||
mySharedConverterData->referenceCounter++;
|
||||
umtx_unlock(NULL);
|
||||
}
|
||||
umtx_unlock(&cnvCacheMutex);
|
||||
}
|
||||
@ -553,9 +608,9 @@ ucnv_createConverter(UConverter *myUConverter, const char *converterName, UError
|
||||
if (U_FAILURE(*err))
|
||||
{
|
||||
if (mySharedConverterData->referenceCounter != ~0) {
|
||||
umtx_lock (NULL);
|
||||
umtx_lock(&cnvCacheMutex);
|
||||
--mySharedConverterData->referenceCounter;
|
||||
umtx_unlock (NULL);
|
||||
umtx_unlock(&cnvCacheMutex);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@ -763,7 +818,7 @@ ucnv_flushCache ()
|
||||
* because the sequence of looking up in the cache + incrementing
|
||||
* is protected by cnvCacheMutex.
|
||||
*/
|
||||
umtx_lock (&cnvCacheMutex);
|
||||
umtx_lock(&cnvCacheMutex);
|
||||
while ((e = uhash_nextElement (SHARED_DATA_HASHTABLE, &pos)) != NULL)
|
||||
{
|
||||
mySharedData = (UConverterSharedData *) e->value.pointer;
|
||||
@ -779,7 +834,7 @@ ucnv_flushCache ()
|
||||
ucnv_deleteSharedConverterData (mySharedData);
|
||||
}
|
||||
}
|
||||
umtx_unlock (&cnvCacheMutex);
|
||||
umtx_unlock(&cnvCacheMutex);
|
||||
|
||||
ucnv_io_flushAvailableConverterCache();
|
||||
|
||||
|
@ -55,26 +55,19 @@ ucnv_createConverterFromSharedData(UConverter *myUConverter, UConverterSharedDat
|
||||
UConverter* ucnv_createConverterFromPackage(const char *packageName, const char *converterName,
|
||||
UErrorCode *err);
|
||||
|
||||
/* Stores the shared data in the SHARED_DATA_HASHTABLE
|
||||
* @param data The shared data
|
||||
/**
|
||||
* This may unload the shared data in a thread safe manner.
|
||||
* This will only unload the data if no other converters are sharing it.
|
||||
*/
|
||||
void ucnv_shareConverterData (UConverterSharedData * data);
|
||||
void
|
||||
ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData);
|
||||
|
||||
/* gets the shared data from the SHARED_DATA_HASHTABLE (might return NULL if it isn't there)
|
||||
* @param name The name of the shared data
|
||||
* @return the shared data from the SHARED_DATA_HASHTABLE
|
||||
/**
|
||||
* This is a thread safe way to increment the reference count.
|
||||
*/
|
||||
UConverterSharedData *ucnv_getSharedConverterData (const char *name);
|
||||
void
|
||||
ucnv_incrementRefCount(UConverterSharedData *sharedData);
|
||||
|
||||
/* Deletes (frees) the Shared data it's passed. first it checks the referenceCounter to
|
||||
* see if anyone is using it, if not it frees all the memory stemming from sharedConverterData and
|
||||
* returns TRUE,
|
||||
* otherwise returns FALSE
|
||||
* @param sharedConverterData The shared data
|
||||
* @return if not it frees all the memory stemming from sharedConverterData and
|
||||
* returns TRUE, otherwise returns FALSE
|
||||
*/
|
||||
UBool ucnv_deleteSharedConverterData (UConverterSharedData * sharedConverterData);
|
||||
|
||||
/* returns true if "name" is in algorithmicConverterNames
|
||||
* @param name The converter name.
|
||||
|
@ -198,12 +198,18 @@ isAcceptable(void *context,
|
||||
|
||||
static UBool
|
||||
haveAliasData(UErrorCode *pErrorCode) {
|
||||
int haveData;
|
||||
|
||||
if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
umtx_lock(NULL);
|
||||
haveData = (int)(gAliasData==NULL);
|
||||
umtx_unlock(NULL);
|
||||
|
||||
/* load converter alias data from file if necessary */
|
||||
if(gAliasData==NULL) {
|
||||
if (haveData) {
|
||||
UDataMemory *data = NULL;
|
||||
const uint16_t *table = NULL;
|
||||
uint32_t tableStart;
|
||||
@ -568,14 +574,20 @@ findTaggedConverterNum(const char *alias, const char *standard, UErrorCode *pErr
|
||||
|
||||
|
||||
U_CFUNC const char *
|
||||
ucnv_io_getConverterName(const char *alias, UErrorCode *pErrorCode) {
|
||||
ucnv_io_getConverterName(const char *alias, int32_t *convNumPtr, UErrorCode *pErrorCode) {
|
||||
if(haveAliasData(pErrorCode) && isAlias(alias, pErrorCode)) {
|
||||
uint32_t convNum = findConverter(alias, pErrorCode);
|
||||
if (convNum < gConverterListSize) {
|
||||
if (convNumPtr) {
|
||||
*convNumPtr = (int32_t)convNum;
|
||||
}
|
||||
return GET_STRING(gConverterList[convNum]);
|
||||
}
|
||||
/* else converter not found */
|
||||
}
|
||||
if (convNumPtr) {
|
||||
*convNumPtr = -1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1012,7 +1024,7 @@ ucnv_io_setDefaultConverterName(const char *converterName) {
|
||||
gDefaultConverterName=NULL;
|
||||
} else {
|
||||
UErrorCode errorCode=U_ZERO_ERROR;
|
||||
const char *name=ucnv_io_getConverterName(converterName, &errorCode);
|
||||
const char *name=ucnv_io_getConverterName(converterName, NULL, &errorCode);
|
||||
if(U_SUCCESS(errorCode) && name!=NULL) {
|
||||
gDefaultConverterName=name;
|
||||
} else {
|
||||
|
@ -36,11 +36,12 @@ ucnv_io_stripForCompare(char *dst, const char *name);
|
||||
* is returned in mixed-case.
|
||||
* Returns NULL if the alias is not found.
|
||||
* @param alias The alias name to be searched.
|
||||
* @param convNumPtr aAn out param for the index of the converter name in the alias table.
|
||||
* @param pErrorCode The error code
|
||||
* @return the converter name in mixed-case, return NULL if the alias is not found.
|
||||
*/
|
||||
U_CFUNC const char *
|
||||
ucnv_io_getConverterName(const char *alias, UErrorCode *pErrorCode);
|
||||
ucnv_io_getConverterName(const char *alias, int32_t *convNumPtr, UErrorCode *pErrorCode);
|
||||
|
||||
/**
|
||||
* The count for ucnv_io_getAliases and ucnv_io_getAlias
|
||||
|
Loading…
Reference in New Issue
Block a user