ICU-2787 revise double-check code to improve thread safety
X-SVN-Rev: 11818
This commit is contained in:
parent
5219cb8a3b
commit
232bc47257
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (C) 1999-2001, International Business Machines
|
||||
* Copyright (C) 1999-2001, ternational Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Date Name Description
|
||||
@ -43,7 +43,7 @@
|
||||
#include "hash.h"
|
||||
#include "mutex.h"
|
||||
#include "ucln_in.h"
|
||||
|
||||
#include "uassert.h"
|
||||
#include "cmemory.h"
|
||||
#include "cstring.h"
|
||||
|
||||
@ -712,10 +712,6 @@ UnicodeString& Transliterator::getDisplayName(const UnicodeString& ID,
|
||||
UnicodeString& Transliterator::getDisplayName(const UnicodeString& id,
|
||||
const Locale& inLocale,
|
||||
UnicodeString& result) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
ResourceBundle bundle(u_getDataDirectory(), inLocale, status);
|
||||
@ -890,9 +886,6 @@ Transliterator* Transliterator::createInstance(const UnicodeString& ID,
|
||||
if (U_FAILURE(status)) {
|
||||
return 0;
|
||||
}
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
|
||||
UnicodeString canonID;
|
||||
UVector list(status);
|
||||
@ -949,17 +942,17 @@ Transliterator* Transliterator::createInstance(const UnicodeString& ID,
|
||||
*/
|
||||
Transliterator* Transliterator::createBasicInstance(const UnicodeString& id,
|
||||
const UnicodeString* canon) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
UParseError pe;
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
TransliteratorAlias* alias = 0;
|
||||
Transliterator* t = 0;
|
||||
{
|
||||
Mutex lock(®istryMutex);
|
||||
|
||||
umtx_lock(®istryMutex);
|
||||
if (initializeRegistry()) {
|
||||
t = registry->get(id, alias, pe, ec);
|
||||
}
|
||||
umtx_unlock(®istryMutex);
|
||||
|
||||
if (U_FAILURE(ec)) {
|
||||
delete t;
|
||||
delete alias;
|
||||
@ -967,8 +960,8 @@ Transliterator* Transliterator::createBasicInstance(const UnicodeString& id,
|
||||
}
|
||||
|
||||
if (alias != 0) {
|
||||
// assert(t==0);
|
||||
// Instantiate an alias
|
||||
U_ASSERT(t==0);
|
||||
t = alias->create(pe, ec);
|
||||
delete alias;
|
||||
if (U_FAILURE(ec)) {
|
||||
@ -1120,11 +1113,10 @@ UnicodeSet& Transliterator::getTargetSet(UnicodeSet& result) const {
|
||||
void Transliterator::registerFactory(const UnicodeString& id,
|
||||
Transliterator::Factory factory,
|
||||
Transliterator::Token context) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
_registerFactory(id, factory, context);
|
||||
if (initializeRegistry()) {
|
||||
_registerFactory(id, factory, context);
|
||||
}
|
||||
}
|
||||
|
||||
// To be called only by Transliterator subclasses that are called
|
||||
@ -1157,11 +1149,10 @@ void Transliterator::_registerSpecialInverse(const UnicodeString& target,
|
||||
* @see #unregister
|
||||
*/
|
||||
void Transliterator::registerInstance(Transliterator* adoptedPrototype) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
_registerInstance(adoptedPrototype);
|
||||
if (initializeRegistry()) {
|
||||
_registerInstance(adoptedPrototype);
|
||||
}
|
||||
}
|
||||
|
||||
void Transliterator::_registerInstance(Transliterator* adoptedPrototype) {
|
||||
@ -1177,11 +1168,10 @@ void Transliterator::_registerInstance(Transliterator* adoptedPrototype) {
|
||||
|
||||
*/
|
||||
void Transliterator::unregister(const UnicodeString& ID) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
registry->remove(ID);
|
||||
if (initializeRegistry()) {
|
||||
registry->remove(ID);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1190,11 +1180,8 @@ void Transliterator::unregister(const UnicodeString& ID) {
|
||||
* i from 0 to countAvailableIDs() - 1.
|
||||
*/
|
||||
int32_t Transliterator::countAvailableIDs(void) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return registry->countAvailableIDs();
|
||||
return initializeRegistry() ? registry->countAvailableIDs() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1203,66 +1190,60 @@ int32_t Transliterator::countAvailableIDs(void) {
|
||||
* range, the result of getAvailableID(0) is returned.
|
||||
*/
|
||||
const UnicodeString& Transliterator::getAvailableID(int32_t index) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
const UnicodeString* result = NULL;
|
||||
umtx_lock(®istryMutex);
|
||||
if (initializeRegistry()) {
|
||||
result = ®istry->getAvailableID(index);
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return registry->getAvailableID(index);
|
||||
umtx_unlock(®istryMutex);
|
||||
U_ASSERT(result != NULL); // fail if no registry
|
||||
return *result;
|
||||
}
|
||||
|
||||
int32_t Transliterator::countAvailableSources(void) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return _countAvailableSources();
|
||||
return initializeRegistry() ? _countAvailableSources() : 0;
|
||||
}
|
||||
|
||||
UnicodeString& Transliterator::getAvailableSource(int32_t index,
|
||||
UnicodeString& result) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return _getAvailableSource(index, result);
|
||||
if (initializeRegistry()) {
|
||||
_getAvailableSource(index, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t Transliterator::countAvailableTargets(const UnicodeString& source) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return _countAvailableTargets(source);
|
||||
return initializeRegistry() ? _countAvailableTargets(source) : 0;
|
||||
}
|
||||
|
||||
UnicodeString& Transliterator::getAvailableTarget(int32_t index,
|
||||
const UnicodeString& source,
|
||||
UnicodeString& result) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return _getAvailableTarget(index, source, result);
|
||||
if (initializeRegistry()) {
|
||||
_getAvailableTarget(index, source, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t Transliterator::countAvailableVariants(const UnicodeString& source,
|
||||
const UnicodeString& target) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return _countAvailableVariants(source, target);
|
||||
return initializeRegistry() ? _countAvailableVariants(source, target) : 0;
|
||||
}
|
||||
|
||||
UnicodeString& Transliterator::getAvailableVariant(int32_t index,
|
||||
const UnicodeString& source,
|
||||
const UnicodeString& target,
|
||||
UnicodeString& result) {
|
||||
if (registry == 0) {
|
||||
initializeRegistry();
|
||||
}
|
||||
Mutex lock(®istryMutex);
|
||||
return _getAvailableVariant(index, source, target, result);
|
||||
if (initializeRegistry()) {
|
||||
_getAvailableVariant(index, source, target, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t Transliterator::_countAvailableSources(void) {
|
||||
@ -1313,16 +1294,28 @@ UChar Transliterator::filteredCharAt(const Replaceable& text, int32_t i) const {
|
||||
|
||||
#endif
|
||||
|
||||
void Transliterator::initializeRegistry(void) {
|
||||
/**
|
||||
* If the registry is initialized, return TRUE. If not, initialize it
|
||||
* and return TRUE. If the registry cannot be initialized, return
|
||||
* FALSE (rare).
|
||||
*
|
||||
* IMPORTANT: Upon entry, registryMutex must be LOCKED. The entirely
|
||||
* initialization is done with the lock held. There is NO REASON to
|
||||
* unlock, since no other thread that is waiting on the registryMutex
|
||||
* can itself proceed until the registry is initialized.
|
||||
*/
|
||||
UBool Transliterator::initializeRegistry() {
|
||||
if (registry != 0) {
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
TransliteratorRegistry* _registry = new TransliteratorRegistry(status);
|
||||
if (_registry == 0 || U_FAILURE(status)) {
|
||||
return; // out of memory, no recovery
|
||||
registry = new TransliteratorRegistry(status);
|
||||
if (registry == 0 || U_FAILURE(status)) {
|
||||
delete registry;
|
||||
registry = 0;
|
||||
return FALSE; // can't create registry, no recovery
|
||||
}
|
||||
|
||||
/* The following code parses the index table located in
|
||||
@ -1378,12 +1371,12 @@ void Transliterator::initializeRegistry(void) {
|
||||
(ures_getUnicodeStringByIndex(colBund, 3, &status).charAt(0) ==
|
||||
0x0046 /*F*/) ?
|
||||
UTRANS_FORWARD : UTRANS_REVERSE;
|
||||
_registry->put(id, resString, dir, visible);
|
||||
registry->put(id, resString, dir, visible);
|
||||
}
|
||||
break;
|
||||
case 0x61: // 'a'
|
||||
// 'alias'; row[2]=createInstance argument
|
||||
_registry->put(id, resString, TRUE);
|
||||
registry->put(id, resString, TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1400,28 +1393,18 @@ void Transliterator::initializeRegistry(void) {
|
||||
// cache. This is how new non-rule-based transliterators are
|
||||
// added to the system.
|
||||
|
||||
_registry->put(new NullTransliterator(), TRUE);
|
||||
_registry->put(new LowercaseTransliterator(), TRUE);
|
||||
_registry->put(new UppercaseTransliterator(), TRUE);
|
||||
_registry->put(new TitlecaseTransliterator(), TRUE);
|
||||
_registry->put(new UnicodeNameTransliterator(), TRUE);
|
||||
_registry->put(new NameUnicodeTransliterator(), TRUE);
|
||||
registry->put(new NullTransliterator(), TRUE);
|
||||
registry->put(new LowercaseTransliterator(), TRUE);
|
||||
registry->put(new UppercaseTransliterator(), TRUE);
|
||||
registry->put(new TitlecaseTransliterator(), TRUE);
|
||||
registry->put(new UnicodeNameTransliterator(), TRUE);
|
||||
registry->put(new NameUnicodeTransliterator(), TRUE);
|
||||
|
||||
// Keep the number of operations within the mutex to a minimum.
|
||||
// The SUBCLASS::registerIDs() calls must occur within the mutex.
|
||||
umtx_lock(®istryMutex);
|
||||
if (registry == NULL) {
|
||||
registry = _registry;
|
||||
_registry = NULL;
|
||||
|
||||
RemoveTransliterator::registerIDs(); // Must be within mutex
|
||||
EscapeTransliterator::registerIDs();
|
||||
UnescapeTransliterator::registerIDs();
|
||||
NormalizationTransliterator::registerIDs();
|
||||
AnyTransliterator::registerIDs();
|
||||
}
|
||||
umtx_unlock(®istryMutex);
|
||||
delete _registry;
|
||||
RemoveTransliterator::registerIDs(); // Must be within mutex
|
||||
EscapeTransliterator::registerIDs();
|
||||
UnescapeTransliterator::registerIDs();
|
||||
NormalizationTransliterator::registerIDs();
|
||||
AnyTransliterator::registerIDs();
|
||||
|
||||
_registerSpecialInverse(NullTransliterator::SHORT_ID,
|
||||
NullTransliterator::SHORT_ID, FALSE);
|
||||
@ -1429,6 +1412,8 @@ void Transliterator::initializeRegistry(void) {
|
||||
_registerSpecialInverse("Title", "Lower", FALSE);
|
||||
|
||||
ucln_i18n_registerCleanup();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
@ -1228,7 +1228,7 @@ private:
|
||||
static const char fgClassID;
|
||||
|
||||
private:
|
||||
static void initializeRegistry(void);
|
||||
static UBool initializeRegistry(void);
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user