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:
George Rhoten 2003-05-07 00:53:32 +00:00
parent 231176f7de
commit 33568a2ee4
5 changed files with 127 additions and 70 deletions

View File

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

View File

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

View File

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

View File

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

View File

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