ICU-20520 UMutex refactoring.
- Use STATIC_NEW for mutex creation, to avoid order-of-destruction problems
by avoiding destruction altogether, while avoiding memory leak reports.
- Remove UConditionVar, replace with direct use of std::condition_variable
diff --git a/icu4c/source/common/brkeng.cpp b/icu4c/source/common/brkeng.cpp
index 19467dc..80e1158 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 = U_MUTEX_INITIALIZER;
- Mutex m(&gBreakEngineMutex);
+ static UMutex *gBreakEngineMutex = STATIC_NEW(UMutex);
+ 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 030cca9..5ce8cac 100644
--- a/icu4c/source/common/characterproperties.cpp
+++ b/icu4c/source/common/characterproperties.cpp
@@ -48,8 +48,8 @@
UCPMap *maps[UCHAR_INT_LIMIT - UCHAR_INT_START] = {};
icu::UMutex *cpMutex() {
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static icu::UMutex *m = STATIC_NEW(icu::UMutex);
+ return m;
}
//----------------------------------------------------------------
diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h
index f19715c..814e39d 100644
--- a/icu4c/source/common/cmemory.h
+++ b/icu4c/source/common/cmemory.h
@@ -98,6 +98,23 @@
#define U_ALIGNMENT_OFFSET_UP(ptr) (sizeof(UAlignedMemory) - U_ALIGNMENT_OFFSET(ptr))
/**
+ * 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
+ * - 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.
+ * This is defined as a macro rather than a template function because each invocation
+ * must define distinct static storage for the object being returned.
+ */
+#define STATIC_NEW(type) [] () { \
+ alignas(type) static char storage[sizeof(type)]; \
+ return new(storage) type();} ();
+
+/**
* Heap clean up function, called from u_cleanup()
* Clears any user heap functions from u_setMemoryFunctions()
* Does NOT deallocate any remaining allocated memory.
diff --git a/icu4c/source/common/locdspnm.cpp b/icu4c/source/common/locdspnm.cpp
index da35be9..70b0776 100644
--- a/icu4c/source/common/locdspnm.cpp
+++ b/icu4c/source/common/locdspnm.cpp
@@ -549,8 +549,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 = U_MUTEX_INITIALIZER;
- Mutex lock(&capitalizationBrkIterLock);
+ static UMutex *capitalizationBrkIterLock = STATIC_NEW(UMutex);
+ 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 06986b6..eecebf4 100644
--- a/icu4c/source/common/locid.cpp
+++ b/icu4c/source/common/locid.cpp
@@ -38,19 +38,19 @@
#include "unicode/strenum.h"
#include "unicode/stringpiece.h"
#include "unicode/uloc.h"
-#include "putilimp.h"
-#include "mutex.h"
-#include "umutex.h"
-#include "uassert.h"
+
+#include "bytesinkutil.h"
+#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
+#include "mutex.h"
+#include "putilimp.h"
#include "uassert.h"
+#include "ucln_cmn.h"
#include "uhash.h"
#include "ulocimp.h"
-#include "ucln_cmn.h"
+#include "umutex.h"
#include "ustr_imp.h"
-#include "charstr.h"
-#include "bytesinkutil.h"
U_CDECL_BEGIN
static UBool U_CALLCONV locale_cleanup(void);
@@ -63,8 +63,8 @@
// gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
static UMutex *gDefaultLocaleMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
static UHashtable *gDefaultLocalesHashT = NULL;
static Locale *gDefaultLocale = NULL;
diff --git a/icu4c/source/common/mutex.h b/icu4c/source/common/mutex.h
index 47f5e08..55768fb 100644
--- a/icu4c/source/common/mutex.h
+++ b/icu4c/source/common/mutex.h
@@ -28,50 +28,51 @@
U_NAMESPACE_BEGIN
-//----------------------------------------------------------------------------
-// Code within that accesses shared static or global data should
-// should instantiate a Mutex object while doing so. You should make your own
-// private mutex where possible.
-
-// For example:
-//
-// UMutex myMutex = U_MUTEX_INITIALIZER;
-//
-// void Function(int arg1, int arg2)
-// {
-// static Object* foo; // Shared read-write object
-// 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
-// }
-//
-// Note: Do NOT use the form 'Mutex mutex();' as that merely forward-declares a function
-// returning a Mutex. This is a common mistake which silently slips through the
-// compiler!!
-//
+/**
+ * Mutex is a helper class for convenient locking and unlocking of a UMutex.
+ *
+ * Creating a local scope Mutex will lock a UMutex, holding the lock until the Mutex
+ * goes out of scope.
+ *
+ * If no UMutex is specified, the ICU global mutex is implied.
+ *
+ * For example:
+ *
+ * UMutex *myMutex() {
+ * static UMutex *m = STATIC_NEW(UMutex);
+ * return m;
+ * }
+ *
+ * void Function(int arg1, int arg2)
+ * {
+ * static Object* foo; // Shared read-write object
+ * 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
+ * }
+ *
+ * Note: Do NOT use the form 'Mutex mutex();' as that merely forward-declares a function
+ * returning a Mutex. This is a common mistake which silently slips through the
+ * compiler!!
+ */
class U_COMMON_API Mutex : public UMemory {
public:
- inline Mutex(UMutex *mutex = NULL);
- inline ~Mutex();
+ Mutex(UMutex *mutex = nullptr) : fMutex(mutex) {
+ umtx_lock(fMutex);
+ };
+ ~Mutex() {
+ umtx_unlock(fMutex);
+ };
+
+ Mutex(const Mutex &other) = delete; // forbid assigning of this class
+ Mutex &operator=(const Mutex &other) = delete; // forbid copying of this class
+ void *operator new(size_t s) = delete; // forbid heap allocation. Locals only.
private:
- UMutex *fMutex;
-
- Mutex(const Mutex &other); // forbid copying of this class
- Mutex &operator=(const Mutex &other); // forbid copying of this class
+ UMutex *fMutex;
};
-inline Mutex::Mutex(UMutex *mutex)
- : fMutex(mutex)
-{
- umtx_lock(fMutex);
-}
-
-inline Mutex::~Mutex()
-{
- umtx_unlock(fMutex);
-}
U_NAMESPACE_END
diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp
index 289a8aa..2f9f2bb 100644
--- a/icu4c/source/common/putil.cpp
+++ b/icu4c/source/common/putil.cpp
@@ -249,8 +249,8 @@
}
static UDate getUTCtime_fake() {
- static UMutex fakeClockMutex = U_MUTEX_INTIALIZER;
- umtx_lock(&fakeClockMutex);
+ static UMutex *fakeClockMutex = STATIC_NEW(UMutex);
+ 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 08cda3a..4d4909c 100644
--- a/icu4c/source/common/resbund.cpp
+++ b/icu4c/source/common/resbund.cpp
@@ -51,6 +51,7 @@
#include "unicode/utypes.h"
#include "unicode/resbund.h"
+#include "cmemory.h"
#include "mutex.h"
#include "uassert.h"
#include "umutex.h"
@@ -377,8 +378,8 @@
}
const Locale &ResourceBundle::getLocale(void) const {
- static UMutex gLocaleLock = U_MUTEX_INITIALIZER;
- Mutex lock(&gLocaleLock);
+ static UMutex *gLocaleLock = STATIC_NEW(UMutex);
+ Mutex lock(gLocaleLock);
if (fLocale != NULL) {
return *fLocale;
}
diff --git a/icu4c/source/common/serv.cpp b/icu4c/source/common/serv.cpp
index 555c055..b92e4e4 100644
--- a/icu4c/source/common/serv.cpp
+++ b/icu4c/source/common/serv.cpp
@@ -334,8 +334,8 @@
*/
static UMutex *lock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
ICUService::ICUService()
diff --git a/icu4c/source/common/servls.cpp b/icu4c/source/common/servls.cpp
index 90874d1..1af6b4a 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 = U_MUTEX_INITIALIZER;
+ static UMutex *llock = STATIC_NEW(UMutex);
{
- 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 1e65a14..e7a7ca5 100644
--- a/icu4c/source/common/servnotf.cpp
+++ b/icu4c/source/common/servnotf.cpp
@@ -22,8 +22,8 @@
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EventListener)
static UMutex *notifyLock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
ICUNotifier::ICUNotifier(void)
diff --git a/icu4c/source/common/ucnv_bld.cpp b/icu4c/source/common/ucnv_bld.cpp
index b71be8f..42ddbd3 100644
--- a/icu4c/source/common/ucnv_bld.cpp
+++ b/icu4c/source/common/ucnv_bld.cpp
@@ -195,8 +195,8 @@
/*initializes some global variables */
static UHashtable *SHARED_DATA_HASHTABLE = NULL;
static icu::UMutex *cnvCacheMutex() { /* Mutex for synchronizing cnv cache access. */
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static icu::UMutex *m = STATIC_NEW(icu::UMutex);
+ return m;
}
/* Note: the global mutex is used for */
/* reference count updates. */
diff --git a/icu4c/source/common/ucurr.cpp b/icu4c/source/common/ucurr.cpp
index 444adc0..105b11d 100644
--- a/icu4c/source/common/ucurr.cpp
+++ b/icu4c/source/common/ucurr.cpp
@@ -366,8 +366,8 @@
struct CReg;
static UMutex *gCRegLock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
static CReg* gCRegHead = 0;
@@ -1357,8 +1357,8 @@
static int8_t currentCacheEntryIndex = 0;
static UMutex *gCurrencyCacheMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
// Cache deletion
diff --git a/icu4c/source/common/udata.cpp b/icu4c/source/common/udata.cpp
index efcd2a2..853a32f 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 = U_MUTEX_INITIALIZER;
- umtx_lock(&extendICUDataMutex);
+ static UMutex *extendICUDataMutex = STATIC_NEW(UMutex);
+ 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 20b03d6..774071e 100644
--- a/icu4c/source/common/umutex.cpp
+++ b/icu4c/source/common/umutex.cpp
@@ -43,8 +43,8 @@
// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
static UMutex *globalMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
U_CAPI void U_EXPORT2
@@ -65,32 +65,6 @@
mutex->fMutex.unlock();
}
-UConditionVar::UConditionVar() : fCV() {
-}
-
-UConditionVar::~UConditionVar() {
-}
-
-U_CAPI void U_EXPORT2
-umtx_condWait(UConditionVar *cond, UMutex *mutex) {
- if (mutex == nullptr) {
- mutex = globalMutex();
- }
- cond->fCV.wait(mutex->fMutex);
-}
-
-
-U_CAPI void U_EXPORT2
-umtx_condBroadcast(UConditionVar *cond) {
- cond->fCV.notify_all();
-}
-
-
-U_CAPI void U_EXPORT2
-umtx_condSignal(UConditionVar *cond) {
- cond->fCV.notify_one();
-}
-
/*************************************************************************************************
*
@@ -99,13 +73,13 @@
*************************************************************************************************/
static std::mutex &initMutex() {
- static std::mutex m;
- return m;
+ static std::mutex *m = STATIC_NEW(std::mutex);
+ return *m;
}
static std::condition_variable &initCondition() {
- static std::condition_variable cv;
- return cv;
+ static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
+ return *cv;
}
diff --git a/icu4c/source/common/umutex.h b/icu4c/source/common/umutex.h
index d0a7e7a..476fcef 100755
--- a/icu4c/source/common/umutex.h
+++ b/icu4c/source/common/umutex.h
@@ -181,13 +181,24 @@
}
-/*************************************************************************************************
- *
+/**
* 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.
*
- *************************************************************************************************/
+ * 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.
+ *
+ * UMutex *myMutex() {
+ * static UMutex *m = STATIC_NEW(UMutex);
+ * return m;
+ * }
+ * ...
+ *
+ * Mutex lock(myMutex()); // hold myMutex until the variable "lock" goes out of scope.
+ */
struct UMutex : public icu::UMemory {
UMutex() = default;
@@ -199,31 +210,6 @@
// // plain C style functions (umtx_lock(), etc.)
};
-
-struct UConditionVar : public icu::UMemory {
- U_COMMON_API UConditionVar();
- U_COMMON_API ~UConditionVar();
- UConditionVar(const UConditionVar &other) = delete;
- UConditionVar &operator =(const UConditionVar &other) = delete;
-
- std::condition_variable_any fCV;
-};
-
-#define U_MUTEX_INITIALIZER {}
-#define U_CONDITION_INITIALIZER {}
-
-// Implementation notes for UConditionVar:
-//
-// Use an out-of-line constructor to reduce problems with the ICU dependency checker.
-// On Linux, the default constructor of std::condition_variable_any
-// produces an in-line reference to global operator new(), which the
-// dependency checker flags for any file that declares a UConditionVar. With
-// an out-of-line constructor, the dependency is constrained to umutex.o
-//
-// Do not export (U_COMMON_API) the entire class, but only the constructor
-// and destructor, to avoid Windows build problems with attempting to export the
-// std::condition_variable_any.
-
/* Lock a mutex.
* @param mutex The given mutex to be locked. Pass NULL to specify
* the global ICU mutex. Recursive locks are an error
@@ -237,30 +223,6 @@
*/
U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
-/*
- * Wait on a condition variable.
- * The calling thread will unlock the mutex and wait on the condition variable.
- * The mutex must be locked by the calling thread when invoking this function.
- *
- * @param cond the condition variable to wait on.
- * @param mutex the associated mutex.
- */
-
-U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
-
-
-/*
- * Broadcast wakeup of all threads waiting on a Condition.
- *
- * @param cond the condition variable.
- */
-U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
-
-/*
- * Signal a condition variable, waking up one waiting thread.
- */
-U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
-
U_NAMESPACE_END
diff --git a/icu4c/source/common/unifiedcache.cpp b/icu4c/source/common/unifiedcache.cpp
index 641f4ec..ed7cf57 100644
--- a/icu4c/source/common/unifiedcache.cpp
+++ b/icu4c/source/common/unifiedcache.cpp
@@ -13,21 +13,20 @@
#include "unifiedcache.h"
#include <algorithm> // For std::max()
+#include <mutex>
-#include "mutex.h"
#include "uassert.h"
#include "uhash.h"
#include "ucln_cmn.h"
-#include "umutex.h"
static icu::UnifiedCache *gCache = NULL;
-static icu::UMutex *gCacheMutex() {
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+static std::mutex &gCacheMutex() {
+ static std::mutex *m = STATIC_NEW(std::mutex);
+ return *m;
}
-static icu::UConditionVar *gInProgressValueAddedCond() {
- static icu::UConditionVar cv = U_CONDITION_INITIALIZER;
- return &cv;
+static std::condition_variable &gInProgressValueAddedCond() {
+ static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
+ return *cv;
}
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
@@ -138,28 +137,28 @@
status = U_ILLEGAL_ARGUMENT_ERROR;
return;
}
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
fMaxUnused = count;
fMaxPercentageOfInUse = percentageOfInUseItems;
}
int32_t UnifiedCache::unusedCount() const {
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
return uhash_count(fHashtable) - fNumValuesInUse;
}
int64_t UnifiedCache::autoEvictedCount() const {
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
return fAutoEvictedCount;
}
int32_t UnifiedCache::keyCount() const {
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
return uhash_count(fHashtable);
}
void UnifiedCache::flush() const {
- 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
@@ -168,7 +167,7 @@
}
void UnifiedCache::handleUnreferencedObject() const {
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
--fNumValuesInUse;
_runEvictionSlice();
}
@@ -187,7 +186,7 @@
}
void UnifiedCache::dumpContents() const {
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
_dumpContents();
}
@@ -227,7 +226,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.
- Mutex lock(gCacheMutex());
+ std::lock_guard<std::mutex> lock(gCacheMutex());
_flush(TRUE);
}
uhash_close(fHashtable);
@@ -328,7 +327,7 @@
const CacheKeyBase &key,
const SharedObject *&value,
UErrorCode &status) const {
- 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);
@@ -353,15 +352,15 @@
UErrorCode &status) const {
U_ASSERT(value == NULL);
U_ASSERT(status == U_ZERO_ERROR);
- 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)) {
- umtx_condWait(gInProgressValueAddedCond(), gCacheMutex());
- element = uhash_find(fHashtable, &key);
+ gInProgressValueAddedCond().wait(lock);
+ element = uhash_find(fHashtable, &key);
}
// If the hash table contains an entry for the key,
@@ -433,7 +432,7 @@
// Tell waiting threads that we replace in-progress status with
// an error.
- umtx_condBroadcast(gInProgressValueAddedCond());
+ gInProgressValueAddedCond().notify_all();
}
void UnifiedCache::_fetch(
diff --git a/icu4c/source/common/uresbund.cpp b/icu4c/source/common/uresbund.cpp
index 483f5ff..7f99211 100644
--- a/icu4c/source/common/uresbund.cpp
+++ b/icu4c/source/common/uresbund.cpp
@@ -50,8 +50,8 @@
static icu::UInitOnce gCacheInitOnce = U_INITONCE_INITIALIZER;
static UMutex *resbMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
/* INTERNAL: hashes an entry */
diff --git a/icu4c/source/common/usprep.cpp b/icu4c/source/common/usprep.cpp
index eb2b2a1..5d72cc7 100644
--- a/icu4c/source/common/usprep.cpp
+++ b/icu4c/source/common/usprep.cpp
@@ -48,8 +48,8 @@
static icu::UInitOnce gSharedDataInitOnce = U_INITONCE_INITIALIZER;
static UMutex *usprepMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
/* format version of spp file */
diff --git a/icu4c/source/i18n/astro.cpp b/icu4c/source/i18n/astro.cpp
index e6dcfe8..d2973d3 100644
--- a/icu4c/source/i18n/astro.cpp
+++ b/icu4c/source/i18n/astro.cpp
@@ -66,8 +66,8 @@
}
static icu::UMutex *ccLock() {
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static icu::UMutex *m = STATIC_NEW(icu::UMutex);
+ return m;
}
U_CDECL_BEGIN
diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp
index 2472870..f6a687e 100644
--- a/icu4c/source/i18n/chnsecal.cpp
+++ b/icu4c/source/i18n/chnsecal.cpp
@@ -52,8 +52,8 @@
// --- The cache --
static icu::UMutex *astroLock() { // Protects access to gChineseCalendarAstro.
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static icu::UMutex *m = STATIC_NEW(icu::UMutex);
+ return m;
}
static icu::CalendarAstronomer *gChineseCalendarAstro = NULL;
diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp
index 42cf5c5..93105e0 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 = U_MUTEX_INITIALIZER;
+ static UMutex *LOCK = STATIC_NEW(UMutex);
- 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 0e124f5..0976dd5 100644
--- a/icu4c/source/i18n/dtitvfmt.cpp
+++ b/icu4c/source/i18n/dtitvfmt.cpp
@@ -83,8 +83,8 @@
// Needed because these data members are modified by const methods of DateIntervalFormat.
static UMutex *gFormatterMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
DateIntervalFormat* U_EXPORT2
diff --git a/icu4c/source/i18n/gender.cpp b/icu4c/source/i18n/gender.cpp
index 50161e1..b57f009 100644
--- a/icu4c/source/i18n/gender.cpp
+++ b/icu4c/source/i18n/gender.cpp
@@ -98,11 +98,11 @@
return NULL;
}
- static UMutex gGenderMetaLock = U_MUTEX_INITIALIZER;
+ static UMutex *gGenderMetaLock = STATIC_NEW(UMutex);
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 a024f4c..b44b60c 100644
--- a/icu4c/source/i18n/islamcal.cpp
+++ b/icu4c/source/i18n/islamcal.cpp
@@ -470,8 +470,8 @@
{
double age = 0;
- static UMutex astroLock = U_MUTEX_INITIALIZER; // pod bay door lock
- umtx_lock(&astroLock);
+ static UMutex *astroLock = STATIC_NEW(UMutex); // 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 802ab0e..0260546 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 = U_MUTEX_INITIALIZER;
+ static UMutex *listFormatterMutex = STATIC_NEW(UMutex);
{
- 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 0b2ba8f..cb51038 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 = U_MUTEX_INITIALIZER;
- umtx_lock(&dateFmtMutex);
+ static UMutex *dateFmtMutex = STATIC_NEW(UMutex);
+ 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 7adf902..d0c96b6 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 icu::UMutex nscacheMutex = U_MUTEX_INITIALIZER;
- Mutex lock(&nscacheMutex);
+ static UMutex *nscacheMutex = STATIC_NEW(UMutex);
+ 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 b440793..d56d46b 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 = U_MUTEX_INITIALIZER;
+ static UMutex *transliteratorDataMutex = STATIC_NEW(UMutex);
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 4aa143c..d950831 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 = U_MUTEX_INITIALIZER;
+ static UMutex *gLock = STATIC_NEW(UMutex);
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 fd54bf0..59732cd 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 icu::UMutex gBrkIterMutex = U_MUTEX_INITIALIZER;
- Mutex lock(&gBrkIterMutex);
+ static UMutex *gBrkIterMutex = STATIC_NEW(UMutex);
+ Mutex lock(gBrkIterMutex);
str.toTitle(
fOptBreakIterator->get(),
fLocale,
diff --git a/icu4c/source/i18n/simpletz.cpp b/icu4c/source/i18n/simpletz.cpp
index cacfa18..9321fda 100644
--- a/icu4c/source/i18n/simpletz.cpp
+++ b/icu4c/source/i18n/simpletz.cpp
@@ -33,6 +33,7 @@
#include "unicode/gregocal.h"
#include "unicode/smpdtfmt.h"
+#include "cmemory.h"
#include "gregoimp.h"
#include "umutex.h"
@@ -1083,13 +1084,13 @@
if (U_FAILURE(status)) {
return;
}
- static UMutex gLock = U_MUTEX_INITIALIZER;
- umtx_lock(&gLock);
+ static UMutex *gLock = STATIC_NEW(UMutex);
+ 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 e67c453..5e6f40b 100644
--- a/icu4c/source/i18n/smpdtfmt.cpp
+++ b/icu4c/source/i18n/smpdtfmt.cpp
@@ -231,8 +231,8 @@
static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
static UMutex *LOCK() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp
index 7d9c719..9f92bb3 100644
--- a/icu4c/source/i18n/translit.cpp
+++ b/icu4c/source/i18n/translit.cpp
@@ -92,8 +92,8 @@
* The mutex controlling access to registry object.
*/
static icu::UMutex *registryMutex() {
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static icu::UMutex *m = STATIC_NEW(icu::UMutex);
+ return m;
}
/**
diff --git a/icu4c/source/i18n/tridpars.cpp b/icu4c/source/i18n/tridpars.cpp
index f54393b..fd9bcfc 100644
--- a/icu4c/source/i18n/tridpars.cpp
+++ b/icu4c/source/i18n/tridpars.cpp
@@ -51,8 +51,8 @@
* The mutex controlling access to SPECIAL_INVERSES
*/
static UMutex *LOCK() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t,
diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp
index cfde4ac..22c5ab2 100644
--- a/icu4c/source/i18n/tzfmt.cpp
+++ b/icu4c/source/i18n/tzfmt.cpp
@@ -151,8 +151,8 @@
static icu::UInitOnce gShortZoneIdTrieInitOnce = U_INITONCE_INITIALIZER;
static UMutex *gLock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
U_CDECL_BEGIN
diff --git a/icu4c/source/i18n/tzgnames.cpp b/icu4c/source/i18n/tzgnames.cpp
index 8c0d4a2..5a92a65 100644
--- a/icu4c/source/i18n/tzgnames.cpp
+++ b/icu4c/source/i18n/tzgnames.cpp
@@ -273,8 +273,8 @@
}
static UMutex *gLock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
class TZGNCore : public UMemory {
@@ -1122,8 +1122,8 @@
// TZGNCore object cache handling
static UMutex *gTZGNLock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
static UHashtable *gTZGNCoreCache = NULL;
static UBool gTZGNCoreCacheInitialized = FALSE;
diff --git a/icu4c/source/i18n/tznames.cpp b/icu4c/source/i18n/tznames.cpp
index acd6aec..bceab39 100644
--- a/icu4c/source/i18n/tznames.cpp
+++ b/icu4c/source/i18n/tznames.cpp
@@ -30,8 +30,8 @@
// TimeZoneNames object cache handling
static UMutex *gTimeZoneNamesLock() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
static UHashtable *gTimeZoneNamesCache = NULL;
static UBool gTimeZoneNamesCacheInitialized = FALSE;
diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp
index 51d3e17..09bf12e 100644
--- a/icu4c/source/i18n/tznames_impl.cpp
+++ b/icu4c/source/i18n/tznames_impl.cpp
@@ -53,8 +53,8 @@
static const int32_t TZDBNAMES_KEYS_SIZE = UPRV_LENGTHOF(TZDBNAMES_KEYS);
static UMutex *gDataMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
static UHashtable* gTZDBNamesMap = NULL;
@@ -391,9 +391,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 = U_MUTEX_INITIALIZER;
+ static UMutex *TextTrieMutex = STATIC_NEW(UMutex);
- Mutex lock(&TextTrieMutex);
+ Mutex lock(TextTrieMutex);
if (fLazyContents != NULL) {
TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
nonConstThis->buildTrie(status);
@@ -2253,8 +2253,8 @@
U_ASSERT(status == U_ZERO_ERROR); // already checked length above
mzIDKey[mzID.length()] = 0;
- static UMutex gTZDBNamesMapLock = U_MUTEX_INITIALIZER;
- umtx_lock(&gTZDBNamesMapLock);
+ static UMutex *gTZDBNamesMapLock = STATIC_NEW(UMutex);
+ umtx_lock(gTZDBNamesMapLock);
{
void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
if (cacheVal == NULL) {
@@ -2297,7 +2297,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 0e3ee89..cc53ef9 100644
--- a/icu4c/source/i18n/zonemeta.cpp
+++ b/icu4c/source/i18n/zonemeta.cpp
@@ -31,8 +31,8 @@
#include "uinvchar.h"
static icu::UMutex *gZoneMetaLock() {
- static icu::UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static icu::UMutex *m = STATIC_NEW(icu::UMutex);
+ return m;
}
// CLDR Canonical ID mapping table
diff --git a/icu4c/source/io/locbund.cpp b/icu4c/source/io/locbund.cpp
index c4ef195..4b6fe34 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 = U_MUTEX_INITIALIZER;
- Mutex lock(&gLock);
+ static UMutex *gLock = STATIC_NEW(UMutex);
+ 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/dependencies.txt b/icu4c/source/test/depstest/dependencies.txt
index f7404a0..a0f75a6 100644
--- a/icu4c/source/test/depstest/dependencies.txt
+++ b/icu4c/source/test/depstest/dependencies.txt
@@ -20,7 +20,7 @@
c_strings c_string_formatting
int_functions floating_point trigonometry
stdlib_qsort
- pthread system_locale
+ system_locale
stdio_input stdio_output file_io readlink_function dir_io mmap_functions dlfcn
# C++
cplusplus iostream
@@ -82,10 +82,6 @@
group: stdlib_qsort
qsort
-group: pthread
- pthread_mutex_init pthread_mutex_destroy pthread_mutex_lock pthread_mutex_unlock
- pthread_cond_wait pthread_cond_broadcast pthread_cond_signal
-
group: system_locale
getenv
nl_langinfo setlocale newlocale freelocale
@@ -831,7 +827,7 @@
# The "platform" group has no ICU dependencies.
PIC system_misc system_debug malloc_functions ubsan
c_strings c_string_formatting
- floating_point pthread system_locale
+ floating_point system_locale
stdio_input readlink_function dir_io
dlfcn # Move related code into icuplug.c?
cplusplus
diff --git a/icu4c/source/test/depstest/depstest.py b/icu4c/source/test/depstest/depstest.py
index 4d05f06..d83937d 100755
--- a/icu4c/source/test/depstest/depstest.py
+++ b/icu4c/source/test/depstest/depstest.py
@@ -105,10 +105,9 @@
# in a limited (not transitive) context. List of (file_name, symbol)
# TODO: Move this data to dependencies.txt?
allowed_errors = (
- ("common/umutex.o", "operator new(unsigned long)"),
- ("common/umutex.o", "std::__throw_bad_alloc()"),
("common/umutex.o", "std::__throw_system_error(int)"),
("common/umutex.o", "std::uncaught_exception()"),
+ ("common/unifiedcache.o", "std::__throw_system_error(int)"),
)
def _Resolve(name, parents):
diff --git a/icu4c/source/test/intltest/intltest.cpp b/icu4c/source/test/intltest/intltest.cpp
index 201c546..c1b6e5b 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 = U_MUTEX_INITIALIZER;
- Mutex lock(&messageMutex);
+ static UMutex *messageMutex = STATIC_NEW(UMutex);
+ 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 2c7528f..2f92526 100644
--- a/icu4c/source/test/intltest/tsmthred.cpp
+++ b/icu4c/source/test/intltest/tsmthred.cpp
@@ -241,12 +241,12 @@
//
//----------------------------------------------------------------------
static UMutex *gTestMutexA() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
-static UConditionVar *gThreadsCountChanged() {
- static UConditionVar cv = U_CONDITION_INITIALIZER;
- return &cv;
+static std::condition_variable *gThreadsCountChanged() {
+ static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
+ return cv;
}
static int gThreadsStarted = 0;
@@ -262,35 +262,34 @@
// 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.
- umtx_lock(gTestMutexA());
+ std::unique_lock<std::mutex> lock(gTestMutexA()->fMutex);
gThreadsStarted += 1;
- umtx_condBroadcast(gThreadsCountChanged());
+ gThreadsCountChanged()->notify_all();
while (gThreadsStarted < TESTMUTEX_THREAD_COUNT) {
if (gThreadsInMiddle != 0) {
IntlTest::gTest->errln(
"%s:%d gThreadsInMiddle = %d. Expected 0.", __FILE__, __LINE__, gThreadsInMiddle);
return;
}
- umtx_condWait(gThreadsCountChanged(), gTestMutexA());
+ gThreadsCountChanged()->wait(lock);
}
gThreadsInMiddle += 1;
- umtx_condBroadcast(gThreadsCountChanged());
+ gThreadsCountChanged()->notify_all();
while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
if (gThreadsDone != 0) {
IntlTest::gTest->errln(
"%s:%d gThreadsDone = %d. Expected 0.", __FILE__, __LINE__, gThreadsDone);
return;
}
- umtx_condWait(gThreadsCountChanged(), gTestMutexA());
+ gThreadsCountChanged()->wait(lock);
}
gThreadsDone += 1;
- umtx_condBroadcast(gThreadsCountChanged());
+ gThreadsCountChanged()->notify_all();
while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
- umtx_condWait(gThreadsCountChanged(), gTestMutexA());
+ gThreadsCountChanged()->wait(lock);
}
- umtx_unlock(gTestMutexA());
}
};
@@ -301,34 +300,34 @@
gThreadsDone = 0;
int32_t i = 0;
TestMutexThread threads[TESTMUTEX_THREAD_COUNT];
- umtx_lock(gTestMutexA());
- for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
- if (threads[i].start() != 0) {
- errln("%s:%d Error starting thread %d", __FILE__, __LINE__, i);
+ {
+ 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;
}
- }
- // 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;
+ while (gThreadsInMiddle < TESTMUTEX_THREAD_COUNT) {
+ if (gThreadsDone != 0) {
+ errln("%s:%d gThreadsDone=%d. Expected 0.", __FILE__, __LINE__, gThreadsStarted);
+ return;
+ }
+ gThreadsCountChanged()->wait(lock);
}
- umtx_condWait(gThreadsCountChanged(), gTestMutexA());
- }
- while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
- umtx_condWait(gThreadsCountChanged(), gTestMutexA());
+ while (gThreadsDone < TESTMUTEX_THREAD_COUNT) {
+ gThreadsCountChanged()->wait(lock);
+ }
}
- umtx_unlock(gTestMutexA());
-
for (i=0; i<TESTMUTEX_THREAD_COUNT; i++) {
threads[i].join();
}
@@ -1173,12 +1172,12 @@
};
static UMutex *gCTMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
+ static UMutex *m = STATIC_NEW(UMutex);
+ return m;
}
-static UConditionVar *gCTConditionVar() {
- static UConditionVar cv = U_CONDITION_INITIALIZER;
- return &cv;
+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.
@@ -1189,49 +1188,48 @@
// Worker thread function.
void CondThread::run() {
- umtx_lock(gCTMutex());
+ std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
gStartedThreads += gConditionTestOne;
- umtx_condBroadcast(gCTConditionVar());
+ 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);
}
- umtx_condWait(gCTConditionVar(), gCTMutex());
+ gCTConditionVar()->wait(lock);
}
gFinishedThreads += gConditionTestOne;
fFinished = true;
- umtx_condBroadcast(gCTConditionVar());
+ gCTConditionVar()->notify_all();
while (gFinishedThreads < NUMTHREADS) {
- umtx_condWait(gCTConditionVar(), gCTMutex());
+ gCTConditionVar()->wait(lock);
}
- umtx_unlock(gCTMutex());
}
void MultithreadTest::TestConditionVariables() {
gStartedThreads = 0;
gFinishedThreads = 0;
int i;
-
- umtx_lock(gCTMutex());
CondThread *threads[NUMTHREADS];
- for (i=0; i<NUMTHREADS; ++i) {
- threads[i] = new CondThread;
- threads[i]->start();
- }
- while (gStartedThreads < NUMTHREADS) {
- umtx_condWait(gCTConditionVar(), gCTMutex());
- }
+ {
+ std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+ for (i=0; i<NUMTHREADS; ++i) {
+ threads[i] = new CondThread;
+ threads[i]->start();
+ }
- while (gFinishedThreads < NUMTHREADS) {
- umtx_condWait(gCTConditionVar(), gCTMutex());
- }
+ while (gStartedThreads < NUMTHREADS) {
+ gCTConditionVar()->wait(lock);
+ }
- umtx_unlock(gCTMutex());
+ while (gFinishedThreads < NUMTHREADS) {
+ gCTConditionVar()->wait(lock);
+ }
+ }
for (i=0; i<NUMTHREADS; ++i) {
assertTrue(WHERE, threads[i]->fFinished);
@@ -1292,21 +1290,23 @@
return result;
}
- umtx_lock(gCTMutex());
- bool firstObject = (gObjectsCreated == 0);
- if (firstObject) {
- // Force the first object creation that comes through to wait
- // until other have completed. Verifies that cache doesn't
- // deadlock when a creation is slow.
+ bool firstObject = false;
+ {
+ std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+ firstObject = (gObjectsCreated == 0);
+ if (firstObject) {
+ // Force the first object creation that comes through to wait
+ // until other have completed. Verifies that cache doesn't
+ // deadlock when a creation is slow.
- // Note that gObjectsCreated needs to be incremeneted from 0 to 1
- // early, to keep subsequent threads from entering this path.
- gObjectsCreated = 1;
- while (gObjectsCreated < 3) {
- umtx_condWait(gCTConditionVar(), gCTMutex());
+ // Note that gObjectsCreated needs to be incremeneted from 0 to 1
+ // early, to keep subsequent threads from entering this path.
+ gObjectsCreated = 1;
+ while (gObjectsCreated < 3) {
+ gCTConditionVar()->wait(lock);
+ }
}
}
- umtx_unlock(gCTMutex());
const UCTMultiThreadItem *result =
new UCTMultiThreadItem(fLoc.getLanguage());
@@ -1318,12 +1318,13 @@
// Log that we created an object. The first object was already counted,
// don't do it again.
- umtx_lock(gCTMutex());
- if (!firstObject) {
- gObjectsCreated += 1;
+ {
+ std::unique_lock<std::mutex> lock(gCTMutex()->fMutex);
+ if (!firstObject) {
+ gObjectsCreated += 1;
+ }
+ gCTConditionVar()->notify_all();
}
- umtx_condBroadcast(gCTConditionVar());
- umtx_unlock(gCTMutex());
return result;
}