ICU-20588 UMutex, add cleanup of underlying mutexes, and simplify usage model
diff --git a/icu4c/source/common/brkeng.cpp b/icu4c/source/common/brkeng.cpp
index 80e1158..78492db 100644
--- a/icu4c/source/common/brkeng.cpp
+++ b/icu4c/source/common/brkeng.cpp
@@ -129,8 +129,8 @@
const LanguageBreakEngine *lbe = NULL;
UErrorCode status = U_ZERO_ERROR;
- static UMutex *gBreakEngineMutex = STATIC_NEW(UMutex);
- Mutex m(gBreakEngineMutex);
+ static UMutex gBreakEngineMutex;
+ Mutex m(&gBreakEngineMutex);
if (fEngines == NULL) {
UStack *engines = new UStack(_deleteEngine, NULL, status);
diff --git a/icu4c/source/common/characterproperties.cpp b/icu4c/source/common/characterproperties.cpp
index 5ce8cac..7b50a4e 100644
--- a/icu4c/source/common/characterproperties.cpp
+++ b/icu4c/source/common/characterproperties.cpp
@@ -47,10 +47,7 @@
UCPMap *maps[UCHAR_INT_LIMIT - UCHAR_INT_START] = {};
-icu::UMutex *cpMutex() {
- static icu::UMutex *m = STATIC_NEW(icu::UMutex);
- return m;
-}
+icu::UMutex cpMutex;
//----------------------------------------------------------------
// Inclusions list
@@ -361,7 +358,7 @@
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
return nullptr;
}
- Mutex m(cpMutex());
+ Mutex m(&cpMutex);
UnicodeSet *set = sets[property];
if (set == nullptr) {
sets[property] = set = makeSet(property, *pErrorCode);
@@ -377,7 +374,7 @@
*pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
return nullptr;
}
- Mutex m(cpMutex());
+ Mutex m(&cpMutex);
UCPMap *map = maps[property - UCHAR_INT_START];
if (map == nullptr) {
maps[property - UCHAR_INT_START] = map = makeMap(property, *pErrorCode);
diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h
index 814e39d..274acc5 100644
--- a/icu4c/source/common/cmemory.h
+++ b/icu4c/source/common/cmemory.h
@@ -101,12 +101,18 @@
* Create & return an instance of "type" in statically allocated storage.
* e.g.
* static std::mutex *myMutex = STATIC_NEW(std::mutex);
- * This is intended for use when
+ * To destroy an object created in this way, invoke the destructor explicitly, e.g.
+ * myMutex->~mutex();
+ * DO NOT use delete.
+ * DO NOT use with class UMutex, which has specific support for static instances.
+ *
+ * STATIC_NEW is intended for use when
* - We want a static (or global) object.
- * - We don't want it to ever be destructed, to avoid order-of-destruction
- * or use-after-destruction problems.
- * - We want to avoid an ordinary heap allocated object, to avoid triggering
- * memory leak reports, from valgrind, for example.
+ * - We don't want it to ever be destructed, or to explicitly control destruction,
+ * to avoid use-after-destruction problems.
+ * - We want to avoid an ordinary heap allocated object,
+ * to avoid the possibility of memory allocation failures, and
+ * to avoid memory leak reports, from valgrind, for example.
* This is defined as a macro rather than a template function because each invocation
* must define distinct static storage for the object being returned.
*/
diff --git a/icu4c/source/common/locdspnm.cpp b/icu4c/source/common/locdspnm.cpp
index 923fed9..d590a88 100644
--- a/icu4c/source/common/locdspnm.cpp
+++ b/icu4c/source/common/locdspnm.cpp
@@ -557,8 +557,8 @@
if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL &&
( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
// note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
- static UMutex *capitalizationBrkIterLock = STATIC_NEW(UMutex);
- Mutex lock(capitalizationBrkIterLock);
+ static UMutex capitalizationBrkIterLock;
+ Mutex lock(&capitalizationBrkIterLock);
result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
}
#endif
diff --git a/icu4c/source/common/locid.cpp b/icu4c/source/common/locid.cpp
index eecebf4..5868b5e 100644
--- a/icu4c/source/common/locid.cpp
+++ b/icu4c/source/common/locid.cpp
@@ -62,10 +62,7 @@
static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER;
// gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
-static UMutex *gDefaultLocaleMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gDefaultLocaleMutex;
static UHashtable *gDefaultLocalesHashT = NULL;
static Locale *gDefaultLocale = NULL;
@@ -174,7 +171,7 @@
Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
// Synchronize this entire function.
- Mutex lock(gDefaultLocaleMutex());
+ Mutex lock(&gDefaultLocaleMutex);
UBool canonicalize = FALSE;
@@ -711,7 +708,7 @@
Locale::getDefault()
{
{
- Mutex lock(gDefaultLocaleMutex());
+ Mutex lock(&gDefaultLocaleMutex);
if (gDefaultLocale != NULL) {
return *gDefaultLocale;
}
diff --git a/icu4c/source/common/mutex.h b/icu4c/source/common/mutex.h
index 55768fb..d8fdf28 100644
--- a/icu4c/source/common/mutex.h
+++ b/icu4c/source/common/mutex.h
@@ -38,15 +38,12 @@
*
* For example:
*
- * UMutex *myMutex() {
- * static UMutex *m = STATIC_NEW(UMutex);
- * return m;
- * }
+ * static UMutex myMutex;
*
* void Function(int arg1, int arg2)
* {
* static Object* foo; // Shared read-write object
- * Mutex mutex(myMutex()); // or no args for the global lock
+ * Mutex mutex(&myMutex); // or no args for the global lock
* foo->Method();
* // When 'mutex' goes out of scope and gets destroyed here, the lock is released
* }
diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp
index 2f9f2bb..aa36f95 100644
--- a/icu4c/source/common/putil.cpp
+++ b/icu4c/source/common/putil.cpp
@@ -249,8 +249,8 @@
}
static UDate getUTCtime_fake() {
- static UMutex *fakeClockMutex = STATIC_NEW(UMutex);
- umtx_lock(fakeClockMutex);
+ static UMutex fakeClockMutex;
+ umtx_lock(&fakeClockMutex);
if(!fakeClock_set) {
UDate real = getUTCtime_real();
const char *fake_start = getenv("U_FAKETIME_START");
@@ -267,7 +267,7 @@
}
fakeClock_set = TRUE;
}
- umtx_unlock(fakeClockMutex);
+ umtx_unlock(&fakeClockMutex);
return getUTCtime_real() + fakeClock_dt;
}
diff --git a/icu4c/source/common/resbund.cpp b/icu4c/source/common/resbund.cpp
index 4d4909c..7c5063b 100644
--- a/icu4c/source/common/resbund.cpp
+++ b/icu4c/source/common/resbund.cpp
@@ -378,8 +378,8 @@
}
const Locale &ResourceBundle::getLocale(void) const {
- static UMutex *gLocaleLock = STATIC_NEW(UMutex);
- Mutex lock(gLocaleLock);
+ static UMutex gLocaleLock;
+ Mutex lock(&gLocaleLock);
if (fLocale != NULL) {
return *fLocale;
}
diff --git a/icu4c/source/common/serv.cpp b/icu4c/source/common/serv.cpp
index b92e4e4..ce545b9 100644
--- a/icu4c/source/common/serv.cpp
+++ b/icu4c/source/common/serv.cpp
@@ -333,10 +333,7 @@
******************************************************************
*/
-static UMutex *lock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex lock;
ICUService::ICUService()
: name()
@@ -361,7 +358,7 @@
ICUService::~ICUService()
{
{
- Mutex mutex(lock());
+ Mutex mutex(&lock);
clearCaches();
delete factories;
factories = NULL;
@@ -452,7 +449,7 @@
// if factory is not null, we're calling from within the mutex,
// and since some unix machines don't have reentrant mutexes we
// need to make sure not to try to lock it again.
- XMutex mutex(lock(), factory != NULL);
+ XMutex mutex(&lock, factory != NULL);
if (serviceCache == NULL) {
ncthis->serviceCache = new Hashtable(status);
@@ -618,7 +615,7 @@
}
{
- Mutex mutex(lock());
+ Mutex mutex(&lock);
const Hashtable* map = getVisibleIDMap(status);
if (map != NULL) {
ICUServiceKey* fallbackKey = createKey(matchID, status);
@@ -695,7 +692,7 @@
{
{
UErrorCode status = U_ZERO_ERROR;
- Mutex mutex(lock());
+ Mutex mutex(&lock);
const Hashtable* map = getVisibleIDMap(status);
if (map != NULL) {
ICUServiceFactory* f = (ICUServiceFactory*)map->get(id);
@@ -747,7 +744,7 @@
result.setDeleter(userv_deleteStringPair);
if (U_SUCCESS(status)) {
ICUService* ncthis = (ICUService*)this; // cast away semantic const
- Mutex mutex(lock());
+ Mutex mutex(&lock);
if (dnCache != NULL && dnCache->locale != locale) {
delete dnCache;
@@ -852,7 +849,7 @@
ICUService::registerFactory(ICUServiceFactory* factoryToAdopt, UErrorCode& status)
{
if (U_SUCCESS(status) && factoryToAdopt != NULL) {
- Mutex mutex(lock());
+ Mutex mutex(&lock);
if (factories == NULL) {
factories = new UVector(deleteUObject, NULL, status);
@@ -883,7 +880,7 @@
ICUServiceFactory *factory = (ICUServiceFactory*)rkey;
UBool result = FALSE;
if (factory != NULL && factories != NULL) {
- Mutex mutex(lock());
+ Mutex mutex(&lock);
if (factories->removeElement(factory)) {
clearCaches();
@@ -903,7 +900,7 @@
ICUService::reset()
{
{
- Mutex mutex(lock());
+ Mutex mutex(&lock);
reInitializeFactories();
clearCaches();
}
diff --git a/icu4c/source/common/servls.cpp b/icu4c/source/common/servls.cpp
index 1af6b4a..81dc4f7 100644
--- a/icu4c/source/common/servls.cpp
+++ b/icu4c/source/common/servls.cpp
@@ -263,9 +263,9 @@
{
const Locale& loc = Locale::getDefault();
ICULocaleService* ncThis = (ICULocaleService*)this;
- static UMutex *llock = STATIC_NEW(UMutex);
+ static UMutex llock;
{
- Mutex mutex(llock);
+ Mutex mutex(&llock);
if (loc != fallbackLocale) {
ncThis->fallbackLocale = loc;
LocaleUtility::initNameFromLocale(loc, ncThis->fallbackLocaleName);
diff --git a/icu4c/source/common/servnotf.cpp b/icu4c/source/common/servnotf.cpp
index e7a7ca5..f577795 100644
--- a/icu4c/source/common/servnotf.cpp
+++ b/icu4c/source/common/servnotf.cpp
@@ -21,10 +21,7 @@
EventListener::~EventListener() {}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EventListener)
-static UMutex *notifyLock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex notifyLock;
ICUNotifier::ICUNotifier(void)
: listeners(NULL)
@@ -33,7 +30,7 @@
ICUNotifier::~ICUNotifier(void) {
{
- Mutex lmx(notifyLock());
+ Mutex lmx(¬ifyLock);
delete listeners;
listeners = NULL;
}
@@ -50,7 +47,7 @@
}
if (acceptsListener(*l)) {
- Mutex lmx(notifyLock());
+ Mutex lmx(¬ifyLock);
if (listeners == NULL) {
listeners = new UVector(5, status);
} else {
@@ -83,7 +80,7 @@
}
{
- Mutex lmx(notifyLock());
+ Mutex lmx(¬ifyLock);
if (listeners != NULL) {
// identity equality check
for (int i = 0, e = listeners->size(); i < e; ++i) {
@@ -106,7 +103,7 @@
ICUNotifier::notifyChanged(void)
{
if (listeners != NULL) {
- Mutex lmx(notifyLock());
+ Mutex lmx(¬ifyLock);
if (listeners != NULL) {
for (int i = 0, e = listeners->size(); i < e; ++i) {
EventListener* el = (EventListener*)listeners->elementAt(i);
diff --git a/icu4c/source/common/ucln_cmn.cpp b/icu4c/source/common/ucln_cmn.cpp
index bfbf53a..f3e07c6 100644
--- a/icu4c/source/common/ucln_cmn.cpp
+++ b/icu4c/source/common/ucln_cmn.cpp
@@ -65,9 +65,20 @@
ucln_common_registerCleanup(ECleanupCommonType type,
cleanupFunc *func)
{
+ // Thread safety messiness: From ticket 10295, calls to registerCleanup() may occur
+ // concurrently. Although such cases should be storing the same value, they raise errors
+ // from the thread sanity checker. Doing the store within a mutex avoids those.
+ // BUT that can trigger a recursive entry into std::call_once() in umutex.cpp when this code,
+ // running from the call_once function, tries to grab the ICU global mutex, which
+ // re-enters the mutex init path. So, work-around by special casing UCLN_COMMON_MUTEX, not
+ // using the ICU global mutex for it.
+ //
+ // No other point in ICU uses std::call_once().
+
U_ASSERT(UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT);
- if (UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT)
- {
+ if (type == UCLN_COMMON_MUTEX) {
+ gCommonCleanupFunctions[type] = func;
+ } else if (UCLN_COMMON_START < type && type < UCLN_COMMON_COUNT) {
icu::Mutex m; // See ticket 10295 for discussion.
gCommonCleanupFunctions[type] = func;
}
diff --git a/icu4c/source/common/ucln_cmn.h b/icu4c/source/common/ucln_cmn.h
index 0ca911b..d281810 100644
--- a/icu4c/source/common/ucln_cmn.h
+++ b/icu4c/source/common/ucln_cmn.h
@@ -22,8 +22,6 @@
/* These are the cleanup functions for various APIs. */
/* @return true if cleanup complete successfully.*/
-U_CFUNC UBool umtx_cleanup(void);
-
U_CFUNC UBool utrace_cleanup(void);
U_CFUNC UBool ucln_lib_cleanup(void);
@@ -62,6 +60,7 @@
*/
UCLN_COMMON_UNIFIED_CACHE,
UCLN_COMMON_URES,
+ UCLN_COMMON_MUTEX, // Mutexes should be the last to be cleaned up.
UCLN_COMMON_COUNT /* This must be last */
} ECleanupCommonType;
diff --git a/icu4c/source/common/ucnv_bld.cpp b/icu4c/source/common/ucnv_bld.cpp
index 42ddbd3..56fc3d6 100644
--- a/icu4c/source/common/ucnv_bld.cpp
+++ b/icu4c/source/common/ucnv_bld.cpp
@@ -194,10 +194,7 @@
/*initializes some global variables */
static UHashtable *SHARED_DATA_HASHTABLE = NULL;
-static icu::UMutex *cnvCacheMutex() { /* Mutex for synchronizing cnv cache access. */
- static icu::UMutex *m = STATIC_NEW(icu::UMutex);
- return m;
-}
+static icu::UMutex cnvCacheMutex;
/* Note: the global mutex is used for */
/* reference count updates. */
@@ -602,9 +599,9 @@
ucnv_unloadSharedDataIfReady(UConverterSharedData *sharedData)
{
if(sharedData != NULL && sharedData->isReferenceCounted) {
- umtx_lock(cnvCacheMutex());
+ umtx_lock(&cnvCacheMutex);
ucnv_unload(sharedData);
- umtx_unlock(cnvCacheMutex());
+ umtx_unlock(&cnvCacheMutex);
}
}
@@ -612,9 +609,9 @@
ucnv_incrementRefCount(UConverterSharedData *sharedData)
{
if(sharedData != NULL && sharedData->isReferenceCounted) {
- umtx_lock(cnvCacheMutex());
+ umtx_lock(&cnvCacheMutex);
sharedData->referenceCounter++;
- umtx_unlock(cnvCacheMutex());
+ umtx_unlock(&cnvCacheMutex);
}
}
@@ -815,9 +812,9 @@
pArgs->nestedLoads=1;
pArgs->pkg=NULL;
- umtx_lock(cnvCacheMutex());
+ umtx_lock(&cnvCacheMutex);
mySharedConverterData = ucnv_load(pArgs, err);
- umtx_unlock(cnvCacheMutex());
+ umtx_unlock(&cnvCacheMutex);
if (U_FAILURE (*err) || (mySharedConverterData == NULL))
{
return NULL;
@@ -1064,7 +1061,7 @@
* because the sequence of looking up in the cache + incrementing
* is protected by cnvCacheMutex.
*/
- umtx_lock(cnvCacheMutex());
+ umtx_lock(&cnvCacheMutex);
/*
* double loop: A delta/extension-only converter has a pointer to its base table's
* shared data; the first iteration of the outer loop may see the delta converter
@@ -1093,7 +1090,7 @@
}
}
} while(++i == 1 && remaining > 0);
- umtx_unlock(cnvCacheMutex());
+ umtx_unlock(&cnvCacheMutex);
UTRACE_DATA1(UTRACE_INFO, "ucnv_flushCache() exits with %d converters remaining", remaining);
@@ -1199,7 +1196,7 @@
}
algorithmicSharedData = getAlgorithmicTypeFromName(stackArgs.name);
- umtx_lock(cnvCacheMutex());
+ umtx_lock(&cnvCacheMutex);
gDefaultAlgorithmicSharedData = algorithmicSharedData;
gDefaultConverterContainsOption = containsOption;
@@ -1215,7 +1212,7 @@
ucnv_enableCleanup();
- umtx_unlock(cnvCacheMutex());
+ umtx_unlock(&cnvCacheMutex);
}
#endif
@@ -1240,7 +1237,7 @@
but ucnv_setDefaultName is not thread safe.
*/
{
- icu::Mutex lock(cnvCacheMutex());
+ icu::Mutex lock(&cnvCacheMutex);
name = gDefaultConverterName;
}
if(name==NULL) {
diff --git a/icu4c/source/common/ucurr.cpp b/icu4c/source/common/ucurr.cpp
index 105b11d..8117645 100644
--- a/icu4c/source/common/ucurr.cpp
+++ b/icu4c/source/common/ucurr.cpp
@@ -365,10 +365,7 @@
#if !UCONFIG_NO_SERVICE
struct CReg;
-static UMutex *gCRegLock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gCRegLock;
static CReg* gCRegHead = 0;
struct CReg : public icu::UMemory {
@@ -394,14 +391,14 @@
if (status && U_SUCCESS(*status) && _iso && _id) {
CReg* n = new CReg(_iso, _id);
if (n) {
- umtx_lock(gCRegLock());
+ umtx_lock(&gCRegLock);
if (!gCRegHead) {
/* register for the first time */
ucln_common_registerCleanup(UCLN_COMMON_CURRENCY, currency_cleanup);
}
n->next = gCRegHead;
gCRegHead = n;
- umtx_unlock(gCRegLock());
+ umtx_unlock(&gCRegLock);
return n;
}
*status = U_MEMORY_ALLOCATION_ERROR;
@@ -411,7 +408,7 @@
static UBool unreg(UCurrRegistryKey key) {
UBool found = FALSE;
- umtx_lock(gCRegLock());
+ umtx_lock(&gCRegLock);
CReg** p = &gCRegHead;
while (*p) {
@@ -424,13 +421,13 @@
p = &((*p)->next);
}
- umtx_unlock(gCRegLock());
+ umtx_unlock(&gCRegLock);
return found;
}
static const UChar* get(const char* id) {
const UChar* result = NULL;
- umtx_lock(gCRegLock());
+ umtx_lock(&gCRegLock);
CReg* p = gCRegHead;
/* register cleanup of the mutex */
@@ -442,7 +439,7 @@
}
p = p->next;
}
- umtx_unlock(gCRegLock());
+ umtx_unlock(&gCRegLock);
return result;
}
@@ -1356,10 +1353,7 @@
// It is a simple round-robin replacement strategy.
static int8_t currentCacheEntryIndex = 0;
-static UMutex *gCurrencyCacheMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gCurrencyCacheMutex;
// Cache deletion
static void
@@ -1408,7 +1402,7 @@
CurrencyNameStruct* currencySymbols = NULL;
CurrencyNameCacheEntry* cacheEntry = NULL;
- umtx_lock(gCurrencyCacheMutex());
+ umtx_lock(&gCurrencyCacheMutex);
// in order to handle racing correctly,
// not putting 'search' in a separate function.
int8_t found = -1;
@@ -1423,13 +1417,13 @@
cacheEntry = currCache[found];
++(cacheEntry->refCount);
}
- umtx_unlock(gCurrencyCacheMutex());
+ umtx_unlock(&gCurrencyCacheMutex);
if (found == -1) {
collectCurrencyNames(locale, ¤cyNames, &total_currency_name_count, ¤cySymbols, &total_currency_symbol_count, ec);
if (U_FAILURE(ec)) {
return NULL;
}
- umtx_lock(gCurrencyCacheMutex());
+ umtx_lock(&gCurrencyCacheMutex);
// check again.
for (int8_t i = 0; i < CURRENCY_NAME_CACHE_NUM; ++i) {
if (currCache[i]!= NULL &&
@@ -1468,19 +1462,19 @@
cacheEntry = currCache[found];
++(cacheEntry->refCount);
}
- umtx_unlock(gCurrencyCacheMutex());
+ umtx_unlock(&gCurrencyCacheMutex);
}
return cacheEntry;
}
static void releaseCacheEntry(CurrencyNameCacheEntry* cacheEntry) {
- umtx_lock(gCurrencyCacheMutex());
+ umtx_lock(&gCurrencyCacheMutex);
--(cacheEntry->refCount);
if (cacheEntry->refCount == 0) { // remove
deleteCacheEntry(cacheEntry);
}
- umtx_unlock(gCurrencyCacheMutex());
+ umtx_unlock(&gCurrencyCacheMutex);
}
U_CAPI void
diff --git a/icu4c/source/common/udata.cpp b/icu4c/source/common/udata.cpp
index 853a32f..bf7025a 100644
--- a/icu4c/source/common/udata.cpp
+++ b/icu4c/source/common/udata.cpp
@@ -831,8 +831,8 @@
* Use a specific mutex to avoid nested locks of the global mutex.
*/
#if MAP_IMPLEMENTATION==MAP_STDIO
- static UMutex *extendICUDataMutex = STATIC_NEW(UMutex);
- umtx_lock(extendICUDataMutex);
+ static UMutex extendICUDataMutex;
+ umtx_lock(&extendICUDataMutex);
#endif
if(!umtx_loadAcquire(gHaveTriedToLoadCommonData)) {
/* See if we can explicitly open a .dat file for the ICUData. */
@@ -868,7 +868,7 @@
/* Also handles a race through here before gHaveTriedToLoadCommonData is set. */
#if MAP_IMPLEMENTATION==MAP_STDIO
- umtx_unlock(extendICUDataMutex);
+ umtx_unlock(&extendICUDataMutex);
#endif
return didUpdate; /* Return true if ICUData pointer was updated. */
/* (Could potentially have been done by another thread racing */
diff --git a/icu4c/source/common/umutex.cpp b/icu4c/source/common/umutex.cpp
index 774071e..d31753f 100644
--- a/icu4c/source/common/umutex.cpp
+++ b/icu4c/source/common/umutex.cpp
@@ -24,6 +24,7 @@
#include "unicode/utypes.h"
#include "uassert.h"
+#include "ucln_cmn.h"
#include "cmemory.h"
U_NAMESPACE_BEGIN
@@ -35,24 +36,90 @@
#error U_USER_MUTEX_CPP not supported
#endif
+// Check that UMutex is trivially constructable & destructable, which ensures that
+// static instances are not running static constructors or destructors.
+#if (defined(__GNUG__) && __GNUC__ < 5) || (defined(__clang__) && __clang_major__ < 5)
+// skip
+#else
+static_assert(std::is_trivially_constructible<UMutex>::value, "UMutex not trivially constructable.");
+static_assert(std::is_trivially_destructible<UMutex>::value, "UMutex not trivially destructable.");
+#endif
+
+
/*************************************************************************************************
*
* ICU Mutex wrappers.
*
*************************************************************************************************/
+namespace {
+std::mutex *initMutex;
+std::condition_variable *initCondition;
+
// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
-static UMutex *globalMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
+UMutex globalMutex;
+
+std::once_flag initFlag;
+std::once_flag *pInitFlag = &initFlag;
+
+} // Anonymous namespace
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV umtx_cleanup() {
+ initMutex->~mutex();
+ initCondition->~condition_variable();
+ UMutex::cleanup();
+
+ // Reset the once_flag, by destructing it and creating a fresh one in its place.
+ // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
+ pInitFlag->~once_flag();
+ pInitFlag = new(&initFlag) std::once_flag();
+ return true;
}
+static void U_CALLCONV umtx_init() {
+ initMutex = STATIC_NEW(std::mutex);
+ initCondition = STATIC_NEW(std::condition_variable);
+ ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
+}
+U_CDECL_END
+
+
+std::mutex *UMutex::getMutex() {
+ std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
+ if (retPtr == nullptr) {
+ std::call_once(*pInitFlag, umtx_init);
+ std::lock_guard<std::mutex> guard(*initMutex);
+ if (fMutex.load() == nullptr) {
+ fMutex = new(fStorage) std::mutex();
+ retPtr = fMutex;
+ fListLink = gListHead;
+ gListHead = this;
+ }
+ }
+ return retPtr;
+}
+
+UMutex *UMutex::gListHead = nullptr;
+
+void UMutex::cleanup() {
+ UMutex *next = nullptr;
+ for (UMutex *m = gListHead; m != nullptr; m = next) {
+ (*m->fMutex).~mutex();
+ m->fMutex = nullptr;
+ next = m->fListLink;
+ m->fListLink = nullptr;
+ }
+ gListHead = nullptr;
+}
+
+
U_CAPI void U_EXPORT2
umtx_lock(UMutex *mutex) {
if (mutex == nullptr) {
- mutex = globalMutex();
+ mutex = &globalMutex;
}
- mutex->fMutex.lock();
+ mutex->lock();
}
@@ -60,9 +127,9 @@
umtx_unlock(UMutex* mutex)
{
if (mutex == nullptr) {
- mutex = globalMutex();
+ mutex = &globalMutex;
}
- mutex->fMutex.unlock();
+ mutex->unlock();
}
@@ -72,17 +139,6 @@
*
*************************************************************************************************/
-static std::mutex &initMutex() {
- static std::mutex *m = STATIC_NEW(std::mutex);
- return *m;
-}
-
-static std::condition_variable &initCondition() {
- static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
- return *cv;
-}
-
-
// This function is called when a test of a UInitOnce::fState reveals that
// initialization has not completed, that we either need to call the init
// function on this thread, or wait for some other thread to complete.
@@ -93,8 +149,8 @@
//
U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce &uio) {
- std::unique_lock<std::mutex> lock(initMutex());
-
+ std::call_once(*pInitFlag, umtx_init);
+ std::unique_lock<std::mutex> lock(*initMutex);
if (umtx_loadAcquire(uio.fState) == 0) {
umtx_storeRelease(uio.fState, 1);
return true; // Caller will next call the init function.
@@ -102,7 +158,7 @@
while (umtx_loadAcquire(uio.fState) == 1) {
// Another thread is currently running the initialization.
// Wait until it completes.
- initCondition().wait(lock);
+ initCondition->wait(lock);
}
U_ASSERT(uio.fState == 2);
return false;
@@ -119,10 +175,10 @@
U_COMMON_API void U_EXPORT2
umtx_initImplPostInit(UInitOnce &uio) {
{
- std::unique_lock<std::mutex> lock(initMutex());
+ std::unique_lock<std::mutex> lock(*initMutex);
umtx_storeRelease(uio.fState, 2);
}
- initCondition().notify_all();
+ initCondition->notify_all();
}
U_NAMESPACE_END
diff --git a/icu4c/source/common/umutex.h b/icu4c/source/common/umutex.h
index 476fcef..d6164f9 100755
--- a/icu4c/source/common/umutex.h
+++ b/icu4c/source/common/umutex.h
@@ -23,6 +23,7 @@
#include <atomic>
#include <condition_variable>
#include <mutex>
+#include <type_traits>
#include "unicode/utypes.h"
#include "unicode/uclean.h"
@@ -36,10 +37,11 @@
#error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
#endif
-
// Export an explicit template instantiation of std::atomic<int32_t>.
// When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
// See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
+//
+// Similar story for std::atomic<std::mutex *>, and the exported UMutex class.
#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
#if defined(__clang__) || defined(_MSC_VER)
#if defined(__clang__)
@@ -48,12 +50,14 @@
#pragma clang diagnostic ignored "-Winstantiation-after-specialization"
#endif
template struct U_COMMON_API std::atomic<int32_t>;
+template struct U_COMMON_API std::atomic<std::mutex *>;
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#elif defined(__GNUC__)
// For GCC this class is already exported/visible, so no need for U_COMMON_API.
template struct std::atomic<int32_t>;
+template struct std::atomic<std::mutex *>;
#endif
#endif
@@ -182,34 +186,66 @@
/**
- * ICU Mutex wrappers. Originally wrapped operating system mutexes, giving the rest of ICU a
- * platform independent set of mutex operations. Now vestigial, wrapping std::mutex only.
- * For internal ICU use only.
+ * UMutex - ICU Mutex class.
*
- * Caution: do not directly declare static or global instances of UMutex. Doing so can introduce
- * static initializers, which are disallowed in ICU library code. Instead, use the following
- * idiom, which avoids static init and also avoids ordering issues on destruction
- * (use after delete) by avoiding destruction altogether.
+ * This is the preferred Mutex class for use within ICU implementation code.
+ * It is a thin wrapper over C++ std::mutex, with these additions:
+ * - Static instances are safe, not triggering static construction or destruction,
+ * and the associated order of construction or destruction issues.
+ * - Plumbed into u_cleanup() for destructing the underlying std::mutex,
+ * which frees any OS level resources they may be holding.
*
- * UMutex *myMutex() {
- * static UMutex *m = STATIC_NEW(UMutex);
- * return m;
- * }
- * ...
+ * Limitations:
+ * - Static or global instances only. Cannot be heap allocated. Cannot appear as a
+ * member of another class.
+ * - No condition variables or other advanced features. If needed, you will need to use
+ * std::mutex and std::condition_variable directly. For an example, see unifiedcache.cpp
*
- * Mutex lock(myMutex()); // hold myMutex until the variable "lock" goes out of scope.
+ * Typical Usage:
+ * static UMutex myMutex;
+ *
+ * {
+ * Mutex lock(myMutex);
+ * ... // Do stuff that is protected by myMutex;
+ * } // myMutex is released when lock goes out of scope.
*/
-struct UMutex : public icu::UMemory {
+class U_COMMON_API UMutex {
+public:
UMutex() = default;
~UMutex() = default;
+
UMutex(const UMutex &other) = delete;
UMutex &operator =(const UMutex &other) = delete;
+ void *operator new(size_t) = delete;
- std::mutex fMutex = {}; // Note: struct - pubic members - because most access is from
- // // plain C style functions (umtx_lock(), etc.)
+ // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
+ void lock() {
+ std::mutex *m = fMutex.load(std::memory_order_acquire);
+ if (m == nullptr) { m = getMutex(); }
+ m->lock();
+ }
+ void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); };
+
+ static void cleanup();
+
+private:
+ alignas(std::mutex) char fStorage[sizeof(std::mutex)];
+ std::atomic<std::mutex *> fMutex;
+
+ /** All initialized UMutexes are kept in a linked list, so that they can be found,
+ * and the underlying std::mutex destructed, by u_cleanup().
+ */
+ UMutex *fListLink;
+ static UMutex *gListHead;
+
+ /** Out-of-line function to lazily initialize a UMutex on first use.
+ * Initial fast check is inline, in lock().
+ */
+ std::mutex *getMutex();
};
+
/* Lock a mutex.
* @param mutex The given mutex to be locked. Pass NULL to specify
* the global ICU mutex. Recursive locks are an error
diff --git a/icu4c/source/common/unifiedcache.cpp b/icu4c/source/common/unifiedcache.cpp
index ed7cf57..f2dd916 100644
--- a/icu4c/source/common/unifiedcache.cpp
+++ b/icu4c/source/common/unifiedcache.cpp
@@ -20,14 +20,8 @@
#include "ucln_cmn.h"
static icu::UnifiedCache *gCache = NULL;
-static std::mutex &gCacheMutex() {
- static std::mutex *m = STATIC_NEW(std::mutex);
- return *m;
-}
-static std::condition_variable &gInProgressValueAddedCond() {
- static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
- return *cv;
-}
+static std::mutex *gCacheMutex = nullptr;
+static std::condition_variable *gInProgressValueAddedCond;
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
static const int32_t MAX_EVICT_ITERATIONS = 10;
@@ -38,10 +32,12 @@
U_CDECL_BEGIN
static UBool U_CALLCONV unifiedcache_cleanup() {
gCacheInitOnce.reset();
- if (gCache) {
- delete gCache;
- gCache = NULL;
- }
+ delete gCache;
+ gCache = nullptr;
+ gCacheMutex->~mutex();
+ gCacheMutex = nullptr;
+ gInProgressValueAddedCond->~condition_variable();
+ gInProgressValueAddedCond = nullptr;
return TRUE;
}
U_CDECL_END
@@ -76,6 +72,8 @@
ucln_common_registerCleanup(
UCLN_COMMON_UNIFIED_CACHE, unifiedcache_cleanup);
+ gCacheMutex = STATIC_NEW(std::mutex);
+ gInProgressValueAddedCond = STATIC_NEW(std::condition_variable);
gCache = new UnifiedCache(status);
if (gCache == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
@@ -137,28 +135,28 @@
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
fMaxUnused = count;
fMaxPercentageOfInUse = percentageOfInUseItems;
}
int32_t UnifiedCache::unusedCount() const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
return uhash_count(fHashtable) - fNumValuesInUse;
}
int64_t UnifiedCache::autoEvictedCount() const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
return fAutoEvictedCount;
}
int32_t UnifiedCache::keyCount() const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
return uhash_count(fHashtable);
}
void UnifiedCache::flush() const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
// Use a loop in case cache items that are flushed held hard references to
// other cache items making those additional cache items eligible for
@@ -167,7 +165,7 @@
}
void UnifiedCache::handleUnreferencedObject() const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
--fNumValuesInUse;
_runEvictionSlice();
}
@@ -186,7 +184,7 @@
}
void UnifiedCache::dumpContents() const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
_dumpContents();
}
@@ -226,7 +224,7 @@
// Now all that should be left in the cache are entries that refer to
// each other and entries with hard references from outside the cache.
// Nothing we can do about these so proceed to wipe out the cache.
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
_flush(TRUE);
}
uhash_close(fHashtable);
@@ -327,7 +325,7 @@
const CacheKeyBase &key,
const SharedObject *&value,
UErrorCode &status) const {
- std::lock_guard<std::mutex> lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(*gCacheMutex);
const UHashElement *element = uhash_find(fHashtable, &key);
if (element != NULL && !_inProgress(element)) {
_fetch(element, value, status);
@@ -352,14 +350,14 @@
UErrorCode &status) const {
U_ASSERT(value == NULL);
U_ASSERT(status == U_ZERO_ERROR);
- std::unique_lock<std::mutex> lock(gCacheMutex());
+ std::unique_lock<std::mutex> lock(*gCacheMutex);
const UHashElement *element = uhash_find(fHashtable, &key);
// If the hash table contains an inProgress placeholder entry for this key,
// this means that another thread is currently constructing the value object.
// Loop, waiting for that construction to complete.
while (element != NULL && _inProgress(element)) {
- gInProgressValueAddedCond().wait(lock);
+ gInProgressValueAddedCond->wait(lock);
element = uhash_find(fHashtable, &key);
}
@@ -432,7 +430,7 @@
// Tell waiting threads that we replace in-progress status with
// an error.
- gInProgressValueAddedCond().notify_all();
+ gInProgressValueAddedCond->notify_all();
}
void UnifiedCache::_fetch(
diff --git a/icu4c/source/common/uresbund.cpp b/icu4c/source/common/uresbund.cpp
index 7f99211..57d133e 100644
--- a/icu4c/source/common/uresbund.cpp
+++ b/icu4c/source/common/uresbund.cpp
@@ -31,6 +31,7 @@
#include "ucln_cmn.h"
#include "cmemory.h"
#include "cstring.h"
+#include "mutex.h"
#include "uhash.h"
#include "unicode/uenum.h"
#include "uenumimp.h"
@@ -49,10 +50,7 @@
static UHashtable *cache = NULL;
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
-static UMutex *resbMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex resbMutex;
/* INTERNAL: hashes an entry */
static int32_t U_CALLCONV hashEntry(const UHashTok parm) {
@@ -96,13 +94,12 @@
* Internal function
*/
static void entryIncrease(UResourceDataEntry *entry) {
- umtx_lock(resbMutex());
+ Mutex lock(&resbMutex);
entry->fCountExisting++;
while(entry->fParent != NULL) {
entry = entry->fParent;
entry->fCountExisting++;
}
- umtx_unlock(resbMutex());
}
/**
@@ -184,9 +181,8 @@
/*if shared data hasn't even been lazy evaluated yet
* return 0
*/
- umtx_lock(resbMutex());
+ Mutex lock(&resbMutex);
if (cache == NULL) {
- umtx_unlock(resbMutex());
return 0;
}
@@ -218,7 +214,6 @@
* got decremented by free_entry().
*/
} while(deletedMore);
- umtx_unlock(resbMutex());
return rbDeletedNum;
}
@@ -232,9 +227,8 @@
const UHashElement *e;
UResourceDataEntry *resB;
- umtx_lock(resbMutex());
+ Mutex lock(&resbMutex);
if (cache == NULL) {
- umtx_unlock(resbMutex());
fprintf(stderr,"%s:%d: RB Cache is NULL.\n", __FILE__, __LINE__);
return FALSE;
}
@@ -253,9 +247,6 @@
}
fprintf(stderr,"%s:%d: RB Cache still contains %d items.\n", __FILE__, __LINE__, uhash_count(cache));
-
- umtx_unlock(resbMutex());
-
return cacheNotEmpty;
}
@@ -666,107 +657,105 @@
}
}
- umtx_lock(resbMutex());
- { /* umtx_lock */
- /* We're going to skip all the locales that do not have any data */
- r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+ Mutex lock(&resbMutex); // Lock resbMutex until the end of this function.
+ /* We're going to skip all the locales that do not have any data */
+ r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+
+ // If we failed due to out-of-memory, report the failure and exit early.
+ if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
+ *status = intStatus;
+ goto finish;
+ }
+
+ if(r != NULL) { /* if there is one real locale, we can look for parents. */
+ t1 = r;
+ hasRealData = TRUE;
+ if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
+ UErrorCode usrStatus = U_ZERO_ERROR;
+ UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
+ // If we failed due to out-of-memory, report the failure and exit early.
+ if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
+ *status = intStatus;
+ goto finish;
+ }
+ if ( u1 != NULL ) {
+ if(u1->fBogus == U_ZERO_ERROR) {
+ u1->fParent = t1;
+ r = u1;
+ } else {
+ /* the USR override data wasn't found, set it to be deleted */
+ u1->fCountExisting = 0;
+ }
+ }
+ }
+ if (hasChopped && !isRoot) {
+ if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
+ goto finish;
+ }
+ }
+ }
+
+ /* we could have reached this point without having any real data */
+ /* if that is the case, we need to chain in the default locale */
+ if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
+ /* insert default locale */
+ uprv_strcpy(name, uloc_getDefault());
+ r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
// If we failed due to out-of-memory, report the failure and exit early.
if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
*status = intStatus;
- goto finishUnlock;
+ goto finish;
}
-
- if(r != NULL) { /* if there is one real locale, we can look for parents. */
+ intStatus = U_USING_DEFAULT_WARNING;
+ if(r != NULL) { /* the default locale exists */
t1 = r;
hasRealData = TRUE;
- if ( usingUSRData ) { /* This code inserts user override data into the inheritance chain */
- UErrorCode usrStatus = U_ZERO_ERROR;
- UResourceDataEntry *u1 = init_entry(t1->fName, usrDataPath, &usrStatus);
- // If we failed due to out-of-memory, report the failure and exit early.
- if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
- *status = intStatus;
- goto finishUnlock;
- }
- if ( u1 != NULL ) {
- if(u1->fBogus == U_ZERO_ERROR) {
- u1->fParent = t1;
- r = u1;
- } else {
- /* the USR override data wasn't found, set it to be deleted */
- u1->fCountExisting = 0;
- }
- }
- }
+ isDefault = TRUE;
+ // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
if (hasChopped && !isRoot) {
if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
- goto finishUnlock;
+ goto finish;
}
}
}
+ }
- /* we could have reached this point without having any real data */
- /* if that is the case, we need to chain in the default locale */
- if(r==NULL && openType == URES_OPEN_LOCALE_DEFAULT_ROOT && !isDefault && !isRoot) {
- /* insert default locale */
- uprv_strcpy(name, uloc_getDefault());
- r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
- // If we failed due to out-of-memory, report the failure and exit early.
- if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
- *status = intStatus;
- goto finishUnlock;
- }
+ /* we could still have r == NULL at this point - maybe even default locale is not */
+ /* present */
+ if(r == NULL) {
+ uprv_strcpy(name, kRootLocaleName);
+ r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
+ // If we failed due to out-of-memory, report the failure and exit early.
+ if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
+ *status = intStatus;
+ goto finish;
+ }
+ if(r != NULL) {
+ t1 = r;
intStatus = U_USING_DEFAULT_WARNING;
- if(r != NULL) { /* the default locale exists */
- t1 = r;
- hasRealData = TRUE;
- isDefault = TRUE;
- // TODO: Why not if (usingUSRData) { ... } like in the non-default-locale code path?
- if (hasChopped && !isRoot) {
- if (!loadParentsExceptRoot(t1, name, UPRV_LENGTHOF(name), usingUSRData, usrDataPath, status)) {
- goto finishUnlock;
- }
- }
- }
+ hasRealData = TRUE;
+ } else { /* we don't even have the root locale */
+ *status = U_MISSING_RESOURCE_ERROR;
+ goto finish;
}
-
- /* we could still have r == NULL at this point - maybe even default locale is not */
- /* present */
- if(r == NULL) {
- uprv_strcpy(name, kRootLocaleName);
- r = findFirstExisting(path, name, &isRoot, &hasChopped, &isDefault, &intStatus);
- // If we failed due to out-of-memory, report the failure and exit early.
- if (intStatus == U_MEMORY_ALLOCATION_ERROR) {
- *status = intStatus;
- goto finishUnlock;
- }
- if(r != NULL) {
- t1 = r;
- intStatus = U_USING_DEFAULT_WARNING;
- hasRealData = TRUE;
- } else { /* we don't even have the root locale */
- *status = U_MISSING_RESOURCE_ERROR;
- goto finishUnlock;
- }
- } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 &&
- t1->fParent == NULL && !r->fData.noFallback) {
- if (!insertRootBundle(t1, status)) {
- goto finishUnlock;
- }
- if(!hasRealData) {
- r->fBogus = U_USING_DEFAULT_WARNING;
- }
+ } else if(!isRoot && uprv_strcmp(t1->fName, kRootLocaleName) != 0 &&
+ t1->fParent == NULL && !r->fData.noFallback) {
+ if (!insertRootBundle(t1, status)) {
+ goto finish;
}
-
- // TODO: Does this ever loop?
- while(r != NULL && !isRoot && t1->fParent != NULL) {
- t1->fParent->fCountExisting++;
- t1 = t1->fParent;
+ if(!hasRealData) {
+ r->fBogus = U_USING_DEFAULT_WARNING;
}
- } /* umtx_lock */
-finishUnlock:
- umtx_unlock(resbMutex());
+ }
+ // TODO: Does this ever loop?
+ while(r != NULL && !isRoot && t1->fParent != NULL) {
+ t1->fParent->fCountExisting++;
+ t1 = t1->fParent;
+ }
+
+finish:
if(U_SUCCESS(*status)) {
if(intStatus != U_ZERO_ERROR) {
*status = intStatus;
@@ -790,7 +779,7 @@
return NULL;
}
- umtx_lock(resbMutex());
+ Mutex lock(&resbMutex);
// findFirstExisting() without fallbacks.
UResourceDataEntry *r = init_entry(localeID, path, status);
if(U_SUCCESS(*status)) {
@@ -828,7 +817,6 @@
t1 = t1->fParent;
}
}
- umtx_unlock(resbMutex());
return r;
}
@@ -871,9 +859,8 @@
*/
static void entryClose(UResourceDataEntry *resB) {
- umtx_lock(resbMutex());
+ Mutex lock(&resbMutex);
entryCloseInt(resB);
- umtx_unlock(resbMutex());
}
/*
diff --git a/icu4c/source/common/usprep.cpp b/icu4c/source/common/usprep.cpp
index 5d72cc7..8351a77 100644
--- a/icu4c/source/common/usprep.cpp
+++ b/icu4c/source/common/usprep.cpp
@@ -47,11 +47,7 @@
static UHashtable *SHARED_DATA_HASHTABLE = NULL;
static icu::UInitOnce gSharedDataInitOnce = U_INITONCE_INITIALIZER;
-static UMutex *usprepMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
-
+static UMutex usprepMutex;
/* format version of spp file */
//static uint8_t formatVersion[4]={ 0, 0, 0, 0 };
@@ -151,9 +147,9 @@
* if shared data hasn't even been lazy evaluated yet
* return 0
*/
- umtx_lock(usprepMutex());
+ umtx_lock(&usprepMutex);
if (SHARED_DATA_HASHTABLE == NULL) {
- umtx_unlock(usprepMutex());
+ umtx_unlock(&usprepMutex);
return 0;
}
@@ -184,7 +180,7 @@
}
}
- umtx_unlock(usprepMutex());
+ umtx_unlock(&usprepMutex);
return deletedNum;
}
@@ -262,7 +258,7 @@
}
/* in the mutex block, set the data for this process */
- umtx_lock(usprepMutex());
+ umtx_lock(&usprepMutex);
if(profile->sprepData==NULL) {
profile->sprepData=dataMemory;
dataMemory=NULL;
@@ -271,7 +267,7 @@
} else {
p=(const int32_t *)udata_getMemory(profile->sprepData);
}
- umtx_unlock(usprepMutex());
+ umtx_unlock(&usprepMutex);
/* initialize some variables */
profile->mappingData=(uint16_t *)((uint8_t *)(p+_SPREP_INDEX_TOP)+profile->indexes[_SPREP_INDEX_TRIE_SIZE]);
@@ -328,12 +324,12 @@
stackKey.path = (char*) path;
/* fetch the data from the cache */
- umtx_lock(usprepMutex());
+ umtx_lock(&usprepMutex);
profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
if(profile != NULL) {
profile->refCount++;
}
- umtx_unlock(usprepMutex());
+ umtx_unlock(&usprepMutex);
if(profile == NULL) {
/* else load the data and put the data in the cache */
@@ -365,7 +361,7 @@
return NULL;
}
- umtx_lock(usprepMutex());
+ umtx_lock(&usprepMutex);
// If another thread already inserted the same key/value, refcount and cleanup our thread data
profile = (UStringPrepProfile*) (uhash_get(SHARED_DATA_HASHTABLE,&stackKey));
if(profile != NULL) {
@@ -386,7 +382,7 @@
profile->refCount = 1;
uhash_put(SHARED_DATA_HASHTABLE, key.orphan(), profile, status);
}
- umtx_unlock(usprepMutex());
+ umtx_unlock(&usprepMutex);
}
return profile;
@@ -425,12 +421,12 @@
return;
}
- umtx_lock(usprepMutex());
+ umtx_lock(&usprepMutex);
/* decrement the ref count*/
if(profile->refCount > 0){
profile->refCount--;
}
- umtx_unlock(usprepMutex());
+ umtx_unlock(&usprepMutex);
}
diff --git a/icu4c/source/i18n/astro.cpp b/icu4c/source/i18n/astro.cpp
index d2973d3..f17b6db 100644
--- a/icu4c/source/i18n/astro.cpp
+++ b/icu4c/source/i18n/astro.cpp
@@ -65,10 +65,7 @@
return(uprv_isNaN(d));
}
-static icu::UMutex *ccLock() {
- static icu::UMutex *m = STATIC_NEW(icu::UMutex);
- return m;
-}
+static icu::UMutex ccLock;
U_CDECL_BEGIN
static UBool calendar_astro_cleanup(void) {
@@ -1552,12 +1549,12 @@
if(U_FAILURE(status)) {
return 0;
}
- umtx_lock(ccLock());
+ umtx_lock(&ccLock);
if(*cache == NULL) {
createCache(cache, status);
if(U_FAILURE(status)) {
- umtx_unlock(ccLock());
+ umtx_unlock(&ccLock);
return 0;
}
}
@@ -1565,7 +1562,7 @@
res = uhash_igeti((*cache)->fTable, key);
U_DEBUG_ASTRO_MSG(("%p: GET: [%d] == %d\n", (*cache)->fTable, key, res));
- umtx_unlock(ccLock());
+ umtx_unlock(&ccLock);
return res;
}
@@ -1573,12 +1570,12 @@
if(U_FAILURE(status)) {
return;
}
- umtx_lock(ccLock());
+ umtx_lock(&ccLock);
if(*cache == NULL) {
createCache(cache, status);
if(U_FAILURE(status)) {
- umtx_unlock(ccLock());
+ umtx_unlock(&ccLock);
return;
}
}
@@ -1586,7 +1583,7 @@
uhash_iputi((*cache)->fTable, key, value, &status);
U_DEBUG_ASTRO_MSG(("%p: PUT: [%d] := %d\n", (*cache)->fTable, key, value));
- umtx_unlock(ccLock());
+ umtx_unlock(&ccLock);
}
CalendarCache::CalendarCache(int32_t size, UErrorCode &status) {
diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp
index f6a687e..bd85db1 100644
--- a/icu4c/source/i18n/chnsecal.cpp
+++ b/icu4c/source/i18n/chnsecal.cpp
@@ -51,10 +51,7 @@
// --- The cache --
-static icu::UMutex *astroLock() { // Protects access to gChineseCalendarAstro.
- static icu::UMutex *m = STATIC_NEW(icu::UMutex);
- return m;
-}
+static icu::UMutex astroLock;
static icu::CalendarAstronomer *gChineseCalendarAstro = NULL;
// Lazy Creation & Access synchronized by class CalendarCache with a mutex.
@@ -538,14 +535,14 @@
// PST 1298 with a final result of Dec 14 10:31:59 PST 1299.
double ms = daysToMillis(Grego::fieldsToDay(gyear, UCAL_DECEMBER, 1));
- umtx_lock(astroLock());
+ umtx_lock(&astroLock);
if(gChineseCalendarAstro == NULL) {
gChineseCalendarAstro = new CalendarAstronomer();
ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
}
gChineseCalendarAstro->setTime(ms);
UDate solarLong = gChineseCalendarAstro->getSunTime(CalendarAstronomer::WINTER_SOLSTICE(), TRUE);
- umtx_unlock(astroLock());
+ umtx_unlock(&astroLock);
// Winter solstice is 270 degrees solar longitude aka Dongzhi
cacheValue = (int32_t)millisToDays(solarLong);
@@ -568,14 +565,14 @@
*/
int32_t ChineseCalendar::newMoonNear(double days, UBool after) const {
- umtx_lock(astroLock());
+ umtx_lock(&astroLock);
if(gChineseCalendarAstro == NULL) {
gChineseCalendarAstro = new CalendarAstronomer();
ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
}
gChineseCalendarAstro->setTime(daysToMillis(days));
UDate newMoon = gChineseCalendarAstro->getMoonTime(CalendarAstronomer::NEW_MOON(), after);
- umtx_unlock(astroLock());
+ umtx_unlock(&astroLock);
return (int32_t) millisToDays(newMoon);
}
@@ -600,14 +597,14 @@
*/
int32_t ChineseCalendar::majorSolarTerm(int32_t days) const {
- umtx_lock(astroLock());
+ umtx_lock(&astroLock);
if(gChineseCalendarAstro == NULL) {
gChineseCalendarAstro = new CalendarAstronomer();
ucln_i18n_registerCleanup(UCLN_I18N_CHINESE_CALENDAR, calendar_chinese_cleanup);
}
gChineseCalendarAstro->setTime(daysToMillis(days));
UDate solarLongitude = gChineseCalendarAstro->getSunLongitude();
- umtx_unlock(astroLock());
+ umtx_unlock(&astroLock);
// Compute (floor(solarLongitude / (pi/6)) + 2) % 12
int32_t term = ( ((int32_t)(6 * solarLongitude / CalendarAstronomer::PI)) + 2 ) % 12;
diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp
index 93105e0..c86d9eb 100644
--- a/icu4c/source/i18n/dtfmtsym.cpp
+++ b/icu4c/source/i18n/dtfmtsym.cpp
@@ -1246,9 +1246,9 @@
DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
{
const UnicodeString **result = NULL;
- static UMutex *LOCK = STATIC_NEW(UMutex);
+ static UMutex LOCK;
- umtx_lock(LOCK);
+ umtx_lock(&LOCK);
if (fZoneStrings == NULL) {
if (fLocaleZoneStrings == NULL) {
((DateFormatSymbols*)this)->initZoneStringsArray();
@@ -1259,7 +1259,7 @@
}
rowCount = fZoneStringsRowCount;
columnCount = fZoneStringsColCount;
- umtx_unlock(LOCK);
+ umtx_unlock(&LOCK);
return result;
}
diff --git a/icu4c/source/i18n/dtitvfmt.cpp b/icu4c/source/i18n/dtitvfmt.cpp
index 0976dd5..f5d8694 100644
--- a/icu4c/source/i18n/dtitvfmt.cpp
+++ b/icu4c/source/i18n/dtitvfmt.cpp
@@ -82,10 +82,7 @@
// Mutex, protects access to fDateFormat, fFromCalendar and fToCalendar.
// Needed because these data members are modified by const methods of DateIntervalFormat.
-static UMutex *gFormatterMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gFormatterMutex;
DateIntervalFormat* U_EXPORT2
DateIntervalFormat::createInstance(const UnicodeString& skeleton,
@@ -171,7 +168,7 @@
delete fTimePattern;
delete fDateTimeFormat;
{
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
if ( itvfmt.fDateFormat ) {
fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone();
} else {
@@ -233,7 +230,7 @@
if ((fInfo != fmt->fInfo) && (fInfo == NULL || fmt->fInfo == NULL)) {return FALSE;}
if (fInfo && fmt->fInfo && (*fInfo != *fmt->fInfo )) {return FALSE;}
{
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
if (fDateFormat != fmt->fDateFormat && (fDateFormat == NULL || fmt->fDateFormat == NULL)) {return FALSE;}
if (fDateFormat && fmt->fDateFormat && (*fDateFormat != *fmt->fDateFormat)) {return FALSE;}
}
@@ -295,7 +292,7 @@
handler.setAcceptFirstOnly(TRUE);
int8_t ignore;
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
return formatIntervalImpl(*dtInterval, appendTo, ignore, handler, status);
}
@@ -312,7 +309,7 @@
auto handler = result->getHandler(status);
handler.setCategory(UFIELD_CATEGORY_DATE);
{
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
formatIntervalImpl(dtInterval, string, firstIndex, handler, status);
}
handler.getError(status);
@@ -344,7 +341,7 @@
handler.setAcceptFirstOnly(TRUE);
int8_t ignore;
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
return formatImpl(fromCalendar, toCalendar, appendTo, ignore, handler, status);
}
@@ -362,7 +359,7 @@
auto handler = result->getHandler(status);
handler.setCategory(UFIELD_CATEGORY_DATE);
{
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
formatImpl(fromCalendar, toCalendar, string, firstIndex, handler, status);
}
handler.getError(status);
@@ -600,7 +597,7 @@
DateIntervalFormat::getTimeZone() const
{
if (fDateFormat != NULL) {
- Mutex lock(gFormatterMutex());
+ Mutex lock(&gFormatterMutex);
return fDateFormat->getTimeZone();
}
// If fDateFormat is NULL (unexpected), create default timezone.
diff --git a/icu4c/source/i18n/gender.cpp b/icu4c/source/i18n/gender.cpp
index b57f009..32ddbf9 100644
--- a/icu4c/source/i18n/gender.cpp
+++ b/icu4c/source/i18n/gender.cpp
@@ -98,11 +98,11 @@
return NULL;
}
- static UMutex *gGenderMetaLock = STATIC_NEW(UMutex);
+ static UMutex gGenderMetaLock;
const GenderInfo* result = NULL;
const char* key = locale.getName();
{
- Mutex lock(gGenderMetaLock);
+ Mutex lock(&gGenderMetaLock);
result = (const GenderInfo*) uhash_get(gGenderInfoCache, key);
}
if (result) {
@@ -118,7 +118,7 @@
// Try to put our GenderInfo object in cache. If there is a race condition,
// favor the GenderInfo object that is already in the cache.
{
- Mutex lock(gGenderMetaLock);
+ Mutex lock(&gGenderMetaLock);
GenderInfo* temp = (GenderInfo*) uhash_get(gGenderInfoCache, key);
if (temp) {
result = temp;
diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp
index b44b60c..6e91d6e 100644
--- a/icu4c/source/i18n/islamcal.cpp
+++ b/icu4c/source/i18n/islamcal.cpp
@@ -470,8 +470,8 @@
{
double age = 0;
- static UMutex *astroLock = STATIC_NEW(UMutex); // pod bay door lock
- umtx_lock(astroLock);
+ static UMutex astroLock; // pod bay door lock
+ umtx_lock(&astroLock);
if(gIslamicCalendarAstro == NULL) {
gIslamicCalendarAstro = new CalendarAstronomer();
if (gIslamicCalendarAstro == NULL) {
@@ -482,7 +482,7 @@
}
gIslamicCalendarAstro->setTime(time);
age = gIslamicCalendarAstro->getMoonAge();
- umtx_unlock(astroLock);
+ umtx_unlock(&astroLock);
// Convert to degrees and normalize...
age = age * 180 / CalendarAstronomer::PI;
diff --git a/icu4c/source/i18n/listformatter.cpp b/icu4c/source/i18n/listformatter.cpp
index 0260546..fa518fe 100644
--- a/icu4c/source/i18n/listformatter.cpp
+++ b/icu4c/source/i18n/listformatter.cpp
@@ -144,9 +144,9 @@
keyBuffer.append(':', errorCode).append(style, errorCode);
UnicodeString key(keyBuffer.data(), -1, US_INV);
ListFormatInternal* result = nullptr;
- static UMutex *listFormatterMutex = STATIC_NEW(UMutex);
+ static UMutex listFormatterMutex;
{
- Mutex m(listFormatterMutex);
+ Mutex m(&listFormatterMutex);
if (listPatternHash == nullptr) {
initializeHash(errorCode);
if (U_FAILURE(errorCode)) {
@@ -164,7 +164,7 @@
}
{
- Mutex m(listFormatterMutex);
+ Mutex m(&listFormatterMutex);
ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
if (temp != nullptr) {
delete result;
diff --git a/icu4c/source/i18n/measfmt.cpp b/icu4c/source/i18n/measfmt.cpp
index cb51038..610d298 100644
--- a/icu4c/source/i18n/measfmt.cpp
+++ b/icu4c/source/i18n/measfmt.cpp
@@ -801,10 +801,10 @@
// #13606: DateFormat is not thread-safe, but MeasureFormat advertises itself as thread-safe.
FieldPosition smallestFieldPosition(smallestField);
UnicodeString draft;
- static UMutex *dateFmtMutex = STATIC_NEW(UMutex);
- umtx_lock(dateFmtMutex);
+ static UMutex dateFmtMutex;
+ umtx_lock(&dateFmtMutex);
dateFmt.format(date, draft, smallestFieldPosition, status);
- umtx_unlock(dateFmtMutex);
+ umtx_unlock(&dateFmtMutex);
// If we find field for smallest amount replace it with the formatted
// smallest amount from above taking care to replace the integer part
diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp
index d0c96b6..8dcc8fa 100644
--- a/icu4c/source/i18n/numfmt.cpp
+++ b/icu4c/source/i18n/numfmt.cpp
@@ -1362,8 +1362,8 @@
// TODO: Bad hash key usage, see ticket #8504.
int32_t hashKey = desiredLocale.hashCode();
- static UMutex *nscacheMutex = STATIC_NEW(UMutex);
- Mutex lock(nscacheMutex);
+ static UMutex nscacheMutex;
+ Mutex lock(&nscacheMutex);
ns = (NumberingSystem *)uhash_iget(NumberingSystem_cache, hashKey);
if (ns == NULL) {
ns = NumberingSystem::createInstance(desiredLocale,status);
diff --git a/icu4c/source/i18n/rbt.cpp b/icu4c/source/i18n/rbt.cpp
index d56d46b..50bffb3 100644
--- a/icu4c/source/i18n/rbt.cpp
+++ b/icu4c/source/i18n/rbt.cpp
@@ -253,14 +253,14 @@
//
// TODO(andy): Need a better scheme for handling this.
- static UMutex *transliteratorDataMutex = STATIC_NEW(UMutex);
+ static UMutex transliteratorDataMutex;
UBool needToLock;
{
Mutex m;
needToLock = (&text != gLockedText);
}
if (needToLock) {
- umtx_lock(transliteratorDataMutex); // Contention, longish waits possible here.
+ umtx_lock(&transliteratorDataMutex); // Contention, longish waits possible here.
Mutex m;
gLockedText = &text;
lockedMutexAtThisLevel = TRUE;
@@ -279,7 +279,7 @@
Mutex m;
gLockedText = NULL;
}
- umtx_unlock(transliteratorDataMutex);
+ umtx_unlock(&transliteratorDataMutex);
}
}
diff --git a/icu4c/source/i18n/rbtz.cpp b/icu4c/source/i18n/rbtz.cpp
index d950831..4864555 100644
--- a/icu4c/source/i18n/rbtz.cpp
+++ b/icu4c/source/i18n/rbtz.cpp
@@ -149,16 +149,16 @@
void
RuleBasedTimeZone::completeConst(UErrorCode& status) const {
- static UMutex *gLock = STATIC_NEW(UMutex);
+ static UMutex gLock;
if (U_FAILURE(status)) {
return;
}
- umtx_lock(gLock);
+ umtx_lock(&gLock);
if (!fUpToDate) {
RuleBasedTimeZone *ncThis = const_cast<RuleBasedTimeZone*>(this);
ncThis->complete(status);
}
- umtx_unlock(gLock);
+ umtx_unlock(&gLock);
}
void
diff --git a/icu4c/source/i18n/reldatefmt.cpp b/icu4c/source/i18n/reldatefmt.cpp
index 59732cd..3c41436 100644
--- a/icu4c/source/i18n/reldatefmt.cpp
+++ b/icu4c/source/i18n/reldatefmt.cpp
@@ -1184,8 +1184,8 @@
// Must guarantee that one thread at a time accesses the shared break
// iterator.
- static UMutex *gBrkIterMutex = STATIC_NEW(UMutex);
- Mutex lock(gBrkIterMutex);
+ static UMutex gBrkIterMutex;
+ Mutex lock(&gBrkIterMutex);
str.toTitle(
fOptBreakIterator->get(),
fLocale,
diff --git a/icu4c/source/i18n/simpletz.cpp b/icu4c/source/i18n/simpletz.cpp
index 9321fda..cbf1f9d 100644
--- a/icu4c/source/i18n/simpletz.cpp
+++ b/icu4c/source/i18n/simpletz.cpp
@@ -1084,13 +1084,13 @@
if (U_FAILURE(status)) {
return;
}
- static UMutex *gLock = STATIC_NEW(UMutex);
- umtx_lock(gLock);
+ static UMutex gLock;
+ umtx_lock(&gLock);
if (!transitionRulesInitialized) {
SimpleTimeZone *ncThis = const_cast<SimpleTimeZone*>(this);
ncThis->initTransitionRules(status);
}
- umtx_unlock(gLock);
+ umtx_unlock(&gLock);
}
void
diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp
index 5e6f40b..678baad 100644
--- a/icu4c/source/i18n/smpdtfmt.cpp
+++ b/icu4c/source/i18n/smpdtfmt.cpp
@@ -230,10 +230,7 @@
static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
-static UMutex *LOCK() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex LOCK;
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
@@ -1266,14 +1263,14 @@
if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
return;
}
- umtx_lock(LOCK());
+ umtx_lock(&LOCK);
if (fSharedNumberFormatters == NULL) {
fSharedNumberFormatters = allocSharedNumberFormatters();
if (fSharedNumberFormatters == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
}
}
- umtx_unlock(LOCK());
+ umtx_unlock(&LOCK);
if (U_FAILURE(status)) {
return;
@@ -3901,11 +3898,11 @@
} else if (fDateOverride.isBogus() && fHasHanYearChar) {
// No current override (=> no Gannen numbering) but new pattern needs it;
// use procedures from initNUmberFormatters / adoptNumberFormat
- umtx_lock(LOCK());
+ umtx_lock(&LOCK);
if (fSharedNumberFormatters == NULL) {
fSharedNumberFormatters = allocSharedNumberFormatters();
}
- umtx_unlock(LOCK());
+ umtx_unlock(&LOCK);
if (fSharedNumberFormatters != NULL) {
Locale ovrLoc(fLocale.getLanguage(),fLocale.getCountry(),fLocale.getVariant(),"numbers=jpanyear");
UErrorCode status = U_ZERO_ERROR;
@@ -4237,7 +4234,7 @@
TimeZoneFormat *
SimpleDateFormat::tzFormat(UErrorCode &status) const {
if (fTimeZoneFormat == NULL) {
- umtx_lock(LOCK());
+ umtx_lock(&LOCK);
{
if (fTimeZoneFormat == NULL) {
TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
@@ -4248,7 +4245,7 @@
const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
}
}
- umtx_unlock(LOCK());
+ umtx_unlock(&LOCK);
}
return fTimeZoneFormat;
}
diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp
index 38e6d64..284334e 100644
--- a/icu4c/source/i18n/timezone.cpp
+++ b/icu4c/source/i18n/timezone.cpp
@@ -527,10 +527,7 @@
// -------------------------------------
-static UMutex *gDefaultZoneMutex() {
- static UMutex* m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gDefaultZoneMutex;
/**
* Initialize DEFAULT_ZONE from the system default time zone.
@@ -541,7 +538,7 @@
{
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
- Mutex lock(gDefaultZoneMutex());
+ Mutex lock(&gDefaultZoneMutex);
// If setDefault() has already been called we can skip getting the
// default zone information from the system.
if (DEFAULT_ZONE != NULL) {
@@ -575,7 +572,7 @@
{
umtx_initOnce(gDefaultZoneInitOnce, initDefault);
{
- Mutex lock(gDefaultZoneMutex());
+ Mutex lock(&gDefaultZoneMutex);
return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
}
}
@@ -588,7 +585,7 @@
if (zone != NULL)
{
{
- Mutex lock(gDefaultZoneMutex());
+ Mutex lock(&gDefaultZoneMutex);
TimeZone *old = DEFAULT_ZONE;
DEFAULT_ZONE = zone;
delete old;
diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp
index 9f92bb3..3feb0a3 100644
--- a/icu4c/source/i18n/translit.cpp
+++ b/icu4c/source/i18n/translit.cpp
@@ -91,10 +91,7 @@
/**
* The mutex controlling access to registry object.
*/
-static icu::UMutex *registryMutex() {
- static icu::UMutex *m = STATIC_NEW(icu::UMutex);
- return m;
-}
+static icu::UMutex registryMutex;
/**
* System transliterator registry; non-null when initialized.
@@ -981,11 +978,11 @@
TransliteratorAlias* alias = 0;
Transliterator* t = 0;
- umtx_lock(registryMutex());
+ umtx_lock(®istryMutex);
if (HAVE_REGISTRY(ec)) {
t = registry->get(id, alias, ec);
}
- umtx_unlock(registryMutex());
+ umtx_unlock(®istryMutex);
if (U_FAILURE(ec)) {
delete t;
@@ -1013,11 +1010,11 @@
alias = 0;
// Step 2. reget
- umtx_lock(registryMutex());
+ umtx_lock(®istryMutex);
if (HAVE_REGISTRY(ec)) {
t = registry->reget(id, parser, alias, ec);
}
- umtx_unlock(registryMutex());
+ umtx_unlock(®istryMutex);
// Step 3. Loop back around!
} else {
@@ -1215,7 +1212,7 @@
void U_EXPORT2 Transliterator::registerFactory(const UnicodeString& id,
Transliterator::Factory factory,
Transliterator::Token context) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
_registerFactory(id, factory, context);
@@ -1254,7 +1251,7 @@
* @see #unregister
*/
void U_EXPORT2 Transliterator::registerInstance(Transliterator* adoptedPrototype) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
_registerInstance(adoptedPrototype);
@@ -1268,7 +1265,7 @@
void U_EXPORT2 Transliterator::registerAlias(const UnicodeString& aliasID,
const UnicodeString& realID) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
_registerAlias(aliasID, realID);
@@ -1290,7 +1287,7 @@
*/
void U_EXPORT2 Transliterator::unregister(const UnicodeString& ID) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
registry->remove(ID);
@@ -1305,7 +1302,7 @@
*/
int32_t U_EXPORT2 Transliterator::countAvailableIDs(void) {
int32_t retVal = 0;
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
retVal = registry->countAvailableIDs();
@@ -1321,12 +1318,12 @@
*/
const UnicodeString& U_EXPORT2 Transliterator::getAvailableID(int32_t index) {
const UnicodeString* result = NULL;
- umtx_lock(registryMutex());
+ umtx_lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
result = ®istry->getAvailableID(index);
}
- umtx_unlock(registryMutex());
+ umtx_unlock(®istryMutex);
U_ASSERT(result != NULL); // fail if no registry
return *result;
}
@@ -1334,11 +1331,11 @@
StringEnumeration* U_EXPORT2 Transliterator::getAvailableIDs(UErrorCode& ec) {
if (U_FAILURE(ec)) return NULL;
StringEnumeration* result = NULL;
- umtx_lock(registryMutex());
+ umtx_lock(®istryMutex);
if (HAVE_REGISTRY(ec)) {
result = registry->getAvailableIDs();
}
- umtx_unlock(registryMutex());
+ umtx_unlock(®istryMutex);
if (result == NULL) {
ec = U_INTERNAL_TRANSLITERATOR_ERROR;
}
@@ -1346,14 +1343,14 @@
}
int32_t U_EXPORT2 Transliterator::countAvailableSources(void) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
return HAVE_REGISTRY(ec) ? _countAvailableSources() : 0;
}
UnicodeString& U_EXPORT2 Transliterator::getAvailableSource(int32_t index,
UnicodeString& result) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
_getAvailableSource(index, result);
@@ -1362,7 +1359,7 @@
}
int32_t U_EXPORT2 Transliterator::countAvailableTargets(const UnicodeString& source) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
return HAVE_REGISTRY(ec) ? _countAvailableTargets(source) : 0;
}
@@ -1370,7 +1367,7 @@
UnicodeString& U_EXPORT2 Transliterator::getAvailableTarget(int32_t index,
const UnicodeString& source,
UnicodeString& result) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
_getAvailableTarget(index, source, result);
@@ -1380,7 +1377,7 @@
int32_t U_EXPORT2 Transliterator::countAvailableVariants(const UnicodeString& source,
const UnicodeString& target) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
return HAVE_REGISTRY(ec) ? _countAvailableVariants(source, target) : 0;
}
@@ -1389,7 +1386,7 @@
const UnicodeString& source,
const UnicodeString& target,
UnicodeString& result) {
- Mutex lock(registryMutex());
+ Mutex lock(®istryMutex);
UErrorCode ec = U_ZERO_ERROR;
if (HAVE_REGISTRY(ec)) {
_getAvailableVariant(index, source, target, result);
diff --git a/icu4c/source/i18n/tridpars.cpp b/icu4c/source/i18n/tridpars.cpp
index fd9bcfc..9de8a16 100644
--- a/icu4c/source/i18n/tridpars.cpp
+++ b/icu4c/source/i18n/tridpars.cpp
@@ -50,10 +50,7 @@
/**
* The mutex controlling access to SPECIAL_INVERSES
*/
-static UMutex *LOCK() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex LOCK;
TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t,
const UnicodeString& v, UBool sawS,
@@ -662,7 +659,7 @@
bidirectional = FALSE;
}
- Mutex lock(LOCK());
+ Mutex lock(&LOCK);
UnicodeString *tempus = new UnicodeString(inverseTarget); // Used for null pointer check before usage.
if (tempus == NULL) {
@@ -866,9 +863,9 @@
UnicodeString* inverseTarget;
- umtx_lock(LOCK());
+ umtx_lock(&LOCK);
inverseTarget = (UnicodeString*) SPECIAL_INVERSES->get(specs.target);
- umtx_unlock(LOCK());
+ umtx_unlock(&LOCK);
if (inverseTarget != NULL) {
// If the original ID contained "Any-" then make the
diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp
index 22c5ab2..3e7b3bd 100644
--- a/icu4c/source/i18n/tzfmt.cpp
+++ b/icu4c/source/i18n/tzfmt.cpp
@@ -150,10 +150,7 @@
static TextTrieMap *gShortZoneIdTrie = NULL;
static icu::UInitOnce gShortZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
-static UMutex *gLock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gLock;
U_CDECL_BEGIN
/**
@@ -1391,12 +1388,12 @@
return NULL;
}
- umtx_lock(gLock());
+ umtx_lock(&gLock);
if (fTimeZoneGenericNames == NULL) {
TimeZoneFormat *nonConstThis = const_cast<TimeZoneFormat *>(this);
nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status);
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
return fTimeZoneGenericNames;
}
@@ -1407,7 +1404,7 @@
return NULL;
}
- umtx_lock(gLock());
+ umtx_lock(&gLock);
if (fTZDBTimeZoneNames == NULL) {
TZDBTimeZoneNames *tzdbNames = new TZDBTimeZoneNames(fLocale);
if (tzdbNames == NULL) {
@@ -1417,7 +1414,7 @@
nonConstThis->fTZDBTimeZoneNames = tzdbNames;
}
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
return fTZDBTimeZoneNames;
}
diff --git a/icu4c/source/i18n/tzgnames.cpp b/icu4c/source/i18n/tzgnames.cpp
index 5a92a65..e056461 100644
--- a/icu4c/source/i18n/tzgnames.cpp
+++ b/icu4c/source/i18n/tzgnames.cpp
@@ -272,10 +272,7 @@
return results;
}
-static UMutex *gLock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gLock;
class TZGNCore : public UMemory {
public:
@@ -494,11 +491,11 @@
const UChar *locname = NULL;
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(gLock());
+ umtx_lock(&gLock);
{
locname = nonConstThis->getGenericLocationName(tzCanonicalID);
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
if (locname == NULL) {
name.setToBogus();
@@ -749,11 +746,11 @@
const UChar *uplname = NULL;
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(gLock());
+ umtx_lock(&gLock);
{
uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
if (uplname == NULL) {
name.setToBogus();
@@ -1016,11 +1013,11 @@
TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(gLock());
+ umtx_lock(&gLock);
{
fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
if (U_FAILURE(status)) {
return NULL;
@@ -1047,7 +1044,7 @@
// All names are not yet loaded into the local trie.
// Load all available names into the trie. This could be very heavy.
- umtx_lock(gLock());
+ umtx_lock(&gLock);
{
if (!fGNamesTrieFullyLoaded) {
StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
@@ -1069,18 +1066,18 @@
}
}
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
if (U_FAILURE(status)) {
return NULL;
}
- umtx_lock(gLock());
+ umtx_lock(&gLock);
{
// now try it again
fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
}
- umtx_unlock(gLock());
+ umtx_unlock(&gLock);
results = handler.getMatches(maxLen);
if (results != NULL && maxLen > 0) {
@@ -1121,10 +1118,7 @@
} TZGNCoreRef;
// TZGNCore object cache handling
-static UMutex *gTZGNLock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gTZGNLock;
static UHashtable *gTZGNCoreCache = NULL;
static UBool gTZGNCoreCacheInitialized = FALSE;
@@ -1190,13 +1184,13 @@
}
TimeZoneGenericNames::~TimeZoneGenericNames() {
- umtx_lock(gTZGNLock());
+ umtx_lock(&gTZGNLock);
{
U_ASSERT(fRef->refCount > 0);
// Just decrement the reference count
fRef->refCount--;
}
- umtx_unlock(gTZGNLock());
+ umtx_unlock(&gTZGNLock);
}
TimeZoneGenericNames*
@@ -1212,7 +1206,7 @@
TZGNCoreRef *cacheEntry = NULL;
{
- Mutex lock(gTZGNLock());
+ Mutex lock(&gTZGNLock);
if (!gTZGNCoreCacheInitialized) {
// Create empty hashtable
@@ -1304,13 +1298,13 @@
TimeZoneGenericNames::clone() const {
TimeZoneGenericNames* other = new TimeZoneGenericNames();
if (other) {
- umtx_lock(gTZGNLock());
+ umtx_lock(&gTZGNLock);
{
// Just increments the reference count
fRef->refCount++;
other->fRef = fRef;
}
- umtx_unlock(gTZGNLock());
+ umtx_unlock(&gTZGNLock);
}
return other;
}
diff --git a/icu4c/source/i18n/tznames.cpp b/icu4c/source/i18n/tznames.cpp
index bceab39..50d7a66 100644
--- a/icu4c/source/i18n/tznames.cpp
+++ b/icu4c/source/i18n/tznames.cpp
@@ -29,10 +29,7 @@
U_NAMESPACE_BEGIN
// TimeZoneNames object cache handling
-static UMutex *gTimeZoneNamesLock() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gTimeZoneNamesLock;
static UHashtable *gTimeZoneNamesCache = NULL;
static UBool gTimeZoneNamesCacheInitialized = FALSE;
@@ -135,7 +132,7 @@
}
TimeZoneNamesDelegate::TimeZoneNamesDelegate(const Locale& locale, UErrorCode& status) {
- Mutex lock(gTimeZoneNamesLock());
+ Mutex lock(&gTimeZoneNamesLock);
if (!gTimeZoneNamesCacheInitialized) {
// Create empty hashtable if it is not already initialized.
gTimeZoneNamesCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
@@ -211,7 +208,7 @@
}
TimeZoneNamesDelegate::~TimeZoneNamesDelegate() {
- umtx_lock(gTimeZoneNamesLock());
+ umtx_lock(&gTimeZoneNamesLock);
{
if (fTZnamesCacheEntry) {
U_ASSERT(fTZnamesCacheEntry->refCount > 0);
@@ -219,7 +216,7 @@
fTZnamesCacheEntry->refCount--;
}
}
- umtx_unlock(gTimeZoneNamesLock());
+ umtx_unlock(&gTimeZoneNamesLock);
}
UBool
@@ -240,13 +237,13 @@
TimeZoneNamesDelegate::clone() const {
TimeZoneNamesDelegate* other = new TimeZoneNamesDelegate();
if (other != NULL) {
- umtx_lock(gTimeZoneNamesLock());
+ umtx_lock(&gTimeZoneNamesLock);
{
// Just increment the reference count
fTZnamesCacheEntry->refCount++;
other->fTZnamesCacheEntry = fTZnamesCacheEntry;
}
- umtx_unlock(gTimeZoneNamesLock());
+ umtx_unlock(&gTimeZoneNamesLock);
}
return other;
}
diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp
index 09bf12e..d92f5fb 100644
--- a/icu4c/source/i18n/tznames_impl.cpp
+++ b/icu4c/source/i18n/tznames_impl.cpp
@@ -52,10 +52,7 @@
static const char* TZDBNAMES_KEYS[] = {"ss", "sd"};
static const int32_t TZDBNAMES_KEYS_SIZE = UPRV_LENGTHOF(TZDBNAMES_KEYS);
-static UMutex *gDataMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
+static UMutex gDataMutex;
static UHashtable* gTZDBNamesMap = NULL;
static icu::UInitOnce gTZDBNamesMapInitOnce = U_INITONCE_INITIALIZER;
@@ -391,9 +388,9 @@
// Don't do unless it's really required.
// Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
- static UMutex *TextTrieMutex = STATIC_NEW(UMutex);
+ static UMutex TextTrieMutex;
- Mutex lock(TextTrieMutex);
+ Mutex lock(&TextTrieMutex);
if (fLazyContents != NULL) {
TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
nonConstThis->buildTrie(status);
@@ -1217,7 +1214,7 @@
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
{
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
UErrorCode status = U_ZERO_ERROR;
znames = nonConstThis->loadMetaZoneNames(mzID, status);
if (U_FAILURE(status)) { return name; }
@@ -1243,7 +1240,7 @@
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
{
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
UErrorCode status = U_ZERO_ERROR;
tznames = nonConstThis->loadTimeZoneNames(tzID, status);
if (U_FAILURE(status)) { return name; }
@@ -1266,7 +1263,7 @@
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
{
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
UErrorCode status = U_ZERO_ERROR;
tznames = nonConstThis->loadTimeZoneNames(tzID, status);
if (U_FAILURE(status)) { return name; }
@@ -1361,7 +1358,7 @@
// Synchronize so that data is not loaded multiple times.
// TODO: Consider more fine-grained synchronization.
{
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
// First try of lookup.
matches = doFind(handler, text, start, status);
@@ -1588,7 +1585,7 @@
if (U_FAILURE(status)) return;
{
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
internalLoadAllDisplayNames(status);
}
}
@@ -1605,7 +1602,7 @@
// Load the time zone strings
{
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
tznames = (void*) nonConstThis->loadTimeZoneNames(tzID, status);
if (U_FAILURE(status)) { return; }
}
@@ -1625,7 +1622,7 @@
} else {
// Load the meta zone strings
// Mutex is scoped to the "else" statement
- Mutex lock(gDataMutex());
+ Mutex lock(&gDataMutex);
mznames = (void*) nonConstThis->loadMetaZoneNames(mzID, status);
if (U_FAILURE(status)) { return; }
// Note: when the metazone doesn't exist, in Java, loadMetaZoneNames returns
@@ -2253,8 +2250,8 @@
U_ASSERT(status == U_ZERO_ERROR); // already checked length above
mzIDKey[mzID.length()] = 0;
- static UMutex *gTZDBNamesMapLock = STATIC_NEW(UMutex);
- umtx_lock(gTZDBNamesMapLock);
+ static UMutex gTZDBNamesMapLock;
+ umtx_lock(&gTZDBNamesMapLock);
{
void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
if (cacheVal == NULL) {
@@ -2297,7 +2294,7 @@
tzdbNames = (TZDBNames *)cacheVal;
}
}
- umtx_unlock(gTZDBNamesMapLock);
+ umtx_unlock(&gTZDBNamesMapLock);
return tzdbNames;
}
diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp
index cc53ef9..72c590f 100644
--- a/icu4c/source/i18n/zonemeta.cpp
+++ b/icu4c/source/i18n/zonemeta.cpp
@@ -30,10 +30,7 @@
#include "olsontz.h"
#include "uinvchar.h"
-static icu::UMutex *gZoneMetaLock() {
- static icu::UMutex *m = STATIC_NEW(icu::UMutex);
- return m;
-}
+static icu::UMutex gZoneMetaLock;
// CLDR Canonical ID mapping table
static UHashtable *gCanonicalIDCache = NULL;
@@ -266,11 +263,11 @@
}
// Check if it was already cached
- umtx_lock(gZoneMetaLock());
+ umtx_lock(&gZoneMetaLock);
{
canonicalID = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
}
- umtx_unlock(gZoneMetaLock());
+ umtx_unlock(&gZoneMetaLock);
if (canonicalID != NULL) {
return canonicalID;
@@ -351,7 +348,7 @@
U_ASSERT(canonicalID != NULL); // canocanilD must be non-NULL here
// Put the resolved canonical ID to the cache
- umtx_lock(gZoneMetaLock());
+ umtx_lock(&gZoneMetaLock);
{
const UChar* idInCache = (const UChar *)uhash_get(gCanonicalIDCache, utzid);
if (idInCache == NULL) {
@@ -371,7 +368,7 @@
}
}
}
- umtx_unlock(gZoneMetaLock());
+ umtx_unlock(&gZoneMetaLock);
}
return canonicalID;
@@ -449,14 +446,14 @@
// Check if it was already cached
UBool cached = FALSE;
UBool singleZone = FALSE;
- umtx_lock(gZoneMetaLock());
+ umtx_lock(&gZoneMetaLock);
{
singleZone = cached = gSingleZoneCountries->contains((void*)region);
if (!cached) {
cached = gMultiZonesCountries->contains((void*)region);
}
}
- umtx_unlock(gZoneMetaLock());
+ umtx_unlock(&gZoneMetaLock);
if (!cached) {
// We need to go through all zones associated with the region.
@@ -475,7 +472,7 @@
delete ids;
// Cache the result
- umtx_lock(gZoneMetaLock());
+ umtx_lock(&gZoneMetaLock);
{
UErrorCode ec = U_ZERO_ERROR;
if (singleZone) {
@@ -488,7 +485,7 @@
}
}
}
- umtx_unlock(gZoneMetaLock());
+ umtx_unlock(&gZoneMetaLock);
}
if (singleZone) {
@@ -575,11 +572,11 @@
// get the mapping from cache
const UVector *result = NULL;
- umtx_lock(gZoneMetaLock());
+ umtx_lock(&gZoneMetaLock);
{
result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
}
- umtx_unlock(gZoneMetaLock());
+ umtx_unlock(&gZoneMetaLock);
if (result != NULL) {
return result;
@@ -593,7 +590,7 @@
}
// put the new one into the cache
- umtx_lock(gZoneMetaLock());
+ umtx_lock(&gZoneMetaLock);
{
// make sure it's already created
result = (UVector*) uhash_get(gOlsonToMeta, tzidUChars);
@@ -621,7 +618,7 @@
delete tmpResult;
}
}
- umtx_unlock(gZoneMetaLock());
+ umtx_unlock(&gZoneMetaLock);
return result;
}
diff --git a/icu4c/source/io/locbund.cpp b/icu4c/source/io/locbund.cpp
index 4b6fe34..46c97bc 100644
--- a/icu4c/source/io/locbund.cpp
+++ b/icu4c/source/io/locbund.cpp
@@ -47,8 +47,8 @@
static inline UNumberFormat * copyInvariantFormatter(ULocaleBundle *result, UNumberFormatStyle style) {
U_NAMESPACE_USE
- static UMutex *gLock = STATIC_NEW(UMutex);
- Mutex lock(gLock);
+ static UMutex gLock;
+ Mutex lock(&gLock);
if (result->fNumberFormat[style-1] == NULL) {
if (gPosixNumberFormat[style-1] == NULL) {
UErrorCode status = U_ZERO_ERROR;
diff --git a/icu4c/source/test/depstest/depstest.py b/icu4c/source/test/depstest/depstest.py
index d83937d..83dbfc0 100755
--- a/icu4c/source/test/depstest/depstest.py
+++ b/icu4c/source/test/depstest/depstest.py
@@ -107,6 +107,10 @@
allowed_errors = (
("common/umutex.o", "std::__throw_system_error(int)"),
("common/umutex.o", "std::uncaught_exception()"),
+ ("common/umutex.o", "std::__once_callable"),
+ ("common/umutex.o", "std::__once_call"),
+ ("common/umutex.o", "__once_proxy"),
+ ("common/umutex.o", "__tls_get_addr"),
("common/unifiedcache.o", "std::__throw_system_error(int)"),
)
diff --git a/icu4c/source/test/intltest/intltest.cpp b/icu4c/source/test/intltest/intltest.cpp
index c1b6e5b..3d6793e 100644
--- a/icu4c/source/test/intltest/intltest.cpp
+++ b/icu4c/source/test/intltest/intltest.cpp
@@ -1116,8 +1116,8 @@
// All error messages generated by tests funnel through here.
// Multithreaded tests can concurrently generate errors, requiring synchronization
// to keep each message together.
- static UMutex *messageMutex = STATIC_NEW(UMutex);
- Mutex lock(messageMutex);
+ static UMutex messageMutex;
+ Mutex lock(&messageMutex);
// string that starts with a LineFeed character and continues
// with spaces according to the current indentation
diff --git a/icu4c/source/test/intltest/tsmthred.cpp b/icu4c/source/test/intltest/tsmthred.cpp
index 2f92526..396c490 100644
--- a/icu4c/source/test/intltest/tsmthred.cpp
+++ b/icu4c/source/test/intltest/tsmthred.cpp
@@ -62,7 +62,6 @@
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(TestThreads);
- TESTCASE_AUTO(TestMutex);
#if !UCONFIG_NO_FORMATTING
TESTCASE_AUTO(TestThreadedIntl);
#endif
@@ -72,7 +71,6 @@
TESTCASE_AUTO(TestString);
TESTCASE_AUTO(TestArabicShapingThreads);
TESTCASE_AUTO(TestAnyTranslit);
- TESTCASE_AUTO(TestConditionVariables);
TESTCASE_AUTO(TestUnifiedCache);
#if !UCONFIG_NO_TRANSLITERATION
TESTCASE_AUTO(TestBreakTranslit);
@@ -232,108 +230,6 @@
}
-//-----------------------------------------------------------------------
-//
-// TestMutex - a simple (non-stress) test to verify that ICU mutexes
-// and condition variables are functioning. Does not test the use of
-// mutexes within ICU services, but rather that the
-// platform's mutex support is at least superficially there.
-//
-//----------------------------------------------------------------------
-static UMutex *gTestMutexA() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
-static std::condition_variable *gThreadsCountChanged() {
- static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
- return cv;
-}
-
-static int gThreadsStarted = 0;
-static int gThreadsInMiddle = 0;
-static int gThreadsDone = 0;
-
-static const int TESTMUTEX_THREAD_COUNT = 40;
-
-class TestMutexThread : public SimpleThread
-{
-public:
- virtual void run() {
- // This is the code that each of the spawned threads runs.
- // All threads move together throught the started - middle - done sequence together,
- // waiting for all other threads to reach each point before advancing.
- std::unique_lock<std::mutex> lock(gTestMutexA()->fMutex);
- gThreadsStarted += 1;
- gThreadsCountChanged()->notify_all();
- while (gThreadsStarted < TESTMUTEX_THREAD_COUNT) {
- if (gThreadsInMiddle != 0) {
- IntlTest::gTest->errln(
- "%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__, __LINE__, gThreadsInMiddle);
- return;
- }
- gThreadsCountChanged()->wait(lock);
- }
-
- gThreadsInMiddle += 1;
- gThreadsCountChanged()->notify_all();
- while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
- if (gThreadsDone != 0) {
- IntlTest::gTest->errln(
- "%s:%d gThreadsDone = %d. Expected 0.", __FILE__, __LINE__, gThreadsDone);
- return;
- }
- gThreadsCountChanged()->wait(lock);
- }
-
- gThreadsDone += 1;
- gThreadsCountChanged()->notify_all();
- while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
- gThreadsCountChanged()->wait(lock);
- }
- }
-};
-
-void MultithreadTest::TestMutex()
-{
- gThreadsStarted = 0;
- gThreadsInMiddle = 0;
- gThreadsDone = 0;
- int32_t i = 0;
- TestMutexThread threads[TESTMUTEX_THREAD_COUNT];
- {
- std::unique_lock<std::mutex> lock(gTestMutexA()->fMutex);
- for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
- if (threads[i].start() != 0) {
- errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
- return;
- }
- }
-
- // Because we are holding gTestMutexA, all of the threads should be blocked
- // at the start of their run() function.
- if (gThreadsStarted != 0) {
- errln("%s:%d gThreadsStarted=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
- return;
- }
-
- while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
- if (gThreadsDone != 0) {
- errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
- return;
- }
- gThreadsCountChanged()->wait(lock);
- }
-
- while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
- gThreadsCountChanged()->wait(lock);
- }
- }
- for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
- threads[i].join();
- }
-}
-
-
//-------------------------------------------------------------------------------------------
//
// TestMultithreadedIntl. Test ICU Formatting in a multi-threaded environment
@@ -1151,96 +1047,6 @@
}
-//
-// Condition Variables Test
-// Create a swarm of threads.
-// Using a mutex and a condition variables each thread
-// Increments a global count of started threads.
-// Broadcasts that it has started.
-// Waits on the condition that all threads have started.
-// Increments a global count of finished threads.
-// Waits on the condition that all threads have finished.
-// Exits.
-//
-
-class CondThread: public SimpleThread {
- public:
- CondThread() :fFinished(false) {};
- ~CondThread() {};
- void run();
- bool fFinished;
-};
-
-static UMutex *gCTMutex() {
- static UMutex *m = STATIC_NEW(UMutex);
- return m;
-}
-static std::condition_variable *gCTConditionVar() {
- static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
- return cv;
-}
-int gConditionTestOne = 1; // Value one. Non-const, extern linkage to inhibit
- // compiler assuming a known value.
-int gStartedThreads;
-int gFinishedThreads;
-static const int NUMTHREADS = 10;
-
-
-// Worker thread function.
-void CondThread::run() {
- std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
- gStartedThreads += gConditionTestOne;
- gCTConditionVar()->notify_all();
-
- while (gStartedThreads < NUMTHREADS) {
- if (gFinishedThreads != 0) {
- IntlTest::gTest->errln("File %s, Line %d: Error, gStartedThreads = %d, gFinishedThreads = %d",
- __FILE__, __LINE__, gStartedThreads, gFinishedThreads);
- }
- gCTConditionVar()->wait(lock);
- }
-
- gFinishedThreads += gConditionTestOne;
- fFinished = true;
- gCTConditionVar()->notify_all();
-
- while (gFinishedThreads < NUMTHREADS) {
- gCTConditionVar()->wait(lock);
- }
-}
-
-void MultithreadTest::TestConditionVariables() {
- gStartedThreads = 0;
- gFinishedThreads = 0;
- int i;
- CondThread *threads[NUMTHREADS];
-
- {
- std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
- for (i=0; i<NUMTHREADS; ++i) {
- threads[i] = new CondThread;
- threads[i]->start();
- }
-
- while (gStartedThreads < NUMTHREADS) {
- gCTConditionVar()->wait(lock);
- }
-
- while (gFinishedThreads < NUMTHREADS) {
- gCTConditionVar()->wait(lock);
- }
- }
-
- for (i=0; i<NUMTHREADS; ++i) {
- assertTrue(WHERE, threads[i]->fFinished);
- }
-
- for (i=0; i<NUMTHREADS; ++i) {
- threads[i]->join();
- delete threads[i];
- }
-}
-
//
// Unified Cache Test
@@ -1275,6 +1081,9 @@
U_NAMESPACE_BEGIN
+static std::mutex *gCTMutex = nullptr;
+static std::condition_variable *gCTConditionVar = nullptr;
+
template<> U_EXPORT
const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
const void *context, UErrorCode &status) const {
@@ -1292,7 +1101,7 @@
bool firstObject = false;
{
- std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+ std::unique_lock<std::mutex> lock(*gCTMutex);
firstObject = (gObjectsCreated == 0);
if (firstObject) {
// Force the first object creation that comes through to wait
@@ -1303,7 +1112,7 @@
// early, to keep subsequent threads from entering this path.
gObjectsCreated = 1;
while (gObjectsCreated < 3) {
- gCTConditionVar()->wait(lock);
+ gCTConditionVar->wait(lock);
}
}
}
@@ -1319,11 +1128,11 @@
// Log that we created an object. The first object was already counted,
// don't do it again.
{
- std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+ std::unique_lock<std::mutex> lock(*gCTMutex);
if (!firstObject) {
gObjectsCreated += 1;
}
- gCTConditionVar()->notify_all();
+ gCTConditionVar->notify_all();
}
return result;
@@ -1386,7 +1195,9 @@
cache.setEvictionPolicy(2, 0, status);
U_ASSERT(U_SUCCESS(status));
- gFinishedThreads = 0;
+ gCTMutex = new std::mutex();
+ gCTConditionVar = new std::condition_variable();
+
gObjectsCreated = 0;
UnifiedCacheThread *threads[CACHE_LOAD][UPRV_LENGTHOF(gCacheLocales)];
@@ -1428,6 +1239,8 @@
delete threads[i][j];
}
}
+ delete gCTMutex;
+ delete gCTConditionVar;
}
#if !UCONFIG_NO_TRANSLITERATION
diff --git a/icu4c/source/test/intltest/tsmthred.h b/icu4c/source/test/intltest/tsmthred.h
index 565080a..d3983cf 100644
--- a/icu4c/source/test/intltest/tsmthred.h
+++ b/icu4c/source/test/intltest/tsmthred.h
@@ -36,10 +36,6 @@
**/
void TestArabicShapingThreads(void);
- /**
- * test that mutexes work
- **/
- void TestMutex(void);
#if !UCONFIG_NO_FORMATTING
/**
* test that intl functions work in a multithreaded context
@@ -49,7 +45,6 @@
void TestCollators(void);
void TestString();
void TestAnyTranslit();
- void TestConditionVariables();
void TestUnifiedCache();
void TestBreakTranslit();
void TestIncDec();