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
This commit is contained in:
parent
702fdb6c33
commit
b772241b52
@ -129,8 +129,8 @@ ICULanguageBreakFactory::getEngineFor(UChar32 c) {
|
||||
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);
|
||||
|
@ -48,8 +48,8 @@ UnicodeSet *sets[UCHAR_BINARY_LIMIT] = {};
|
||||
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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
@ -97,6 +97,23 @@ typedef union {
|
||||
*/
|
||||
#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()
|
||||
|
@ -549,8 +549,8 @@ LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage,
|
||||
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
|
||||
|
@ -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 @@ static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER;
|
||||
|
||||
// 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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -249,8 +249,8 @@ static UDate getUTCtime_real() {
|
||||
}
|
||||
|
||||
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 @@ static UDate getUTCtime_fake() {
|
||||
}
|
||||
fakeClock_set = TRUE;
|
||||
}
|
||||
umtx_unlock(&fakeClockMutex);
|
||||
umtx_unlock(fakeClockMutex);
|
||||
|
||||
return getUTCtime_real() + fakeClock_dt;
|
||||
}
|
||||
|
@ -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 @@ void ResourceBundle::getVersion(UVersionInfo versionInfo) const {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -334,8 +334,8 @@ U_CDECL_END
|
||||
*/
|
||||
|
||||
static UMutex *lock() {
|
||||
static UMutex m = U_MUTEX_INITIALIZER;
|
||||
return &m;
|
||||
static UMutex *m = STATIC_NEW(UMutex);
|
||||
return m;
|
||||
}
|
||||
|
||||
ICUService::ICUService()
|
||||
|
@ -263,9 +263,9 @@ ICULocaleService::validateFallbackLocale() const
|
||||
{
|
||||
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);
|
||||
|
@ -22,8 +22,8 @@ EventListener::~EventListener() {}
|
||||
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)
|
||||
|
@ -195,8 +195,8 @@ static struct {
|
||||
/*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. */
|
||||
|
@ -366,8 +366,8 @@ U_CDECL_END
|
||||
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 CurrencyNameCacheEntry* currCache[CURRENCY_NAME_CACHE_NUM] = {NULL};
|
||||
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
|
||||
|
@ -831,8 +831,8 @@ static UBool extendICUData(UErrorCode *pErr)
|
||||
* 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 @@ static UBool extendICUData(UErrorCode *pErr)
|
||||
/* 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 */
|
||||
|
@ -43,8 +43,8 @@ U_NAMESPACE_BEGIN
|
||||
|
||||
// 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 @@ umtx_unlock(UMutex* mutex)
|
||||
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 @@ umtx_condSignal(UConditionVar *cond) {
|
||||
*************************************************************************************************/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,13 +181,24 @@ template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UE
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************************************
|
||||
*
|
||||
/**
|
||||
* 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 @@ struct UMutex : public icu::UMemory {
|
||||
// // 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_lock(UMutex* mutex);
|
||||
*/
|
||||
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
|
||||
|
||||
|
@ -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 @@ void UnifiedCache::setEvictionPolicy(
|
||||
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::flush() const {
|
||||
}
|
||||
|
||||
void UnifiedCache::handleUnreferencedObject() const {
|
||||
Mutex lock(gCacheMutex());
|
||||
std::lock_guard<std::mutex> lock(gCacheMutex());
|
||||
--fNumValuesInUse;
|
||||
_runEvictionSlice();
|
||||
}
|
||||
@ -187,7 +186,7 @@ void UnifiedCache::dump() {
|
||||
}
|
||||
|
||||
void UnifiedCache::dumpContents() const {
|
||||
Mutex lock(gCacheMutex());
|
||||
std::lock_guard<std::mutex> lock(gCacheMutex());
|
||||
_dumpContents();
|
||||
}
|
||||
|
||||
@ -227,7 +226,7 @@ UnifiedCache::~UnifiedCache() {
|
||||
// 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 @@ void UnifiedCache::_putIfAbsentAndGet(
|
||||
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 @@ UBool UnifiedCache::_poll(
|
||||
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 @@ void UnifiedCache::_put(
|
||||
|
||||
// Tell waiting threads that we replace in-progress status with
|
||||
// an error.
|
||||
umtx_condBroadcast(gInProgressValueAddedCond());
|
||||
gInProgressValueAddedCond().notify_all();
|
||||
}
|
||||
|
||||
void UnifiedCache::_fetch(
|
||||
|
@ -50,8 +50,8 @@ static UHashtable *cache = NULL;
|
||||
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 */
|
||||
|
@ -48,8 +48,8 @@ static UHashtable *SHARED_DATA_HASHTABLE = NULL;
|
||||
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 */
|
||||
|
@ -66,8 +66,8 @@ static inline UBool isINVALID(double d) {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -52,8 +52,8 @@ static void debug_chnsecal_msg(const char *pat, ...)
|
||||
|
||||
// --- 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;
|
||||
|
||||
|
@ -1246,9 +1246,9 @@ const UnicodeString**
|
||||
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 @@ DateFormatSymbols::getZoneStrings(int32_t& rowCount, int32_t& columnCount) const
|
||||
}
|
||||
rowCount = fZoneStringsRowCount;
|
||||
columnCount = fZoneStringsColCount;
|
||||
umtx_unlock(&LOCK);
|
||||
umtx_unlock(LOCK);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -83,8 +83,8 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat)
|
||||
// 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
|
||||
|
@ -98,11 +98,11 @@ const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& stat
|
||||
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 @@ const GenderInfo* GenderInfo::getInstance(const Locale& locale, UErrorCode& stat
|
||||
// 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;
|
||||
|
@ -470,8 +470,8 @@ double IslamicCalendar::moonAge(UDate time, UErrorCode &status)
|
||||
{
|
||||
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 @@ double IslamicCalendar::moonAge(UDate time, UErrorCode &status)
|
||||
}
|
||||
gIslamicCalendarAstro->setTime(time);
|
||||
age = gIslamicCalendarAstro->getMoonAge();
|
||||
umtx_unlock(&astroLock);
|
||||
umtx_unlock(astroLock);
|
||||
|
||||
// Convert to degrees and normalize...
|
||||
age = age * 180 / CalendarAstronomer::PI;
|
||||
|
@ -144,9 +144,9 @@ const ListFormatInternal* ListFormatter::getListFormatInternal(
|
||||
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 @@ const ListFormatInternal* ListFormatter::getListFormatInternal(
|
||||
}
|
||||
|
||||
{
|
||||
Mutex m(&listFormatterMutex);
|
||||
Mutex m(listFormatterMutex);
|
||||
ListFormatInternal* temp = static_cast<ListFormatInternal*>(listPatternHash->get(key));
|
||||
if (temp != nullptr) {
|
||||
delete result;
|
||||
|
@ -801,10 +801,10 @@ UnicodeString &MeasureFormat::formatNumeric(
|
||||
// #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
|
||||
|
@ -1362,8 +1362,8 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
|
||||
// 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);
|
||||
|
@ -253,14 +253,14 @@ RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
|
||||
//
|
||||
// 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 @@ RuleBasedTransliterator::handleTransliterate(Replaceable& text, UTransPosition&
|
||||
Mutex m;
|
||||
gLockedText = NULL;
|
||||
}
|
||||
umtx_unlock(&transliteratorDataMutex);
|
||||
umtx_unlock(transliteratorDataMutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,16 +149,16 @@ RuleBasedTimeZone::addTransitionRule(TimeZoneRule* rule, UErrorCode& status) {
|
||||
|
||||
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
|
||||
|
@ -1184,8 +1184,8 @@ UnicodeString& RelativeDateTimeFormatter::adjustForContext(UnicodeString &str) c
|
||||
|
||||
// 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,
|
||||
|
@ -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 @@ SimpleTimeZone::checkTransitionRules(UErrorCode& status) const {
|
||||
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
|
||||
|
@ -231,8 +231,8 @@ 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 = U_MUTEX_INITIALIZER;
|
||||
return &m;
|
||||
static UMutex *m = STATIC_NEW(UMutex);
|
||||
return m;
|
||||
}
|
||||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
|
||||
|
@ -92,8 +92,8 @@ static const char RB_RULE_BASED_IDS[] = "RuleBasedTransliteratorIDs";
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -51,8 +51,8 @@ static UInitOnce gSpecialInversesInitOnce = U_INITONCE_INITIALIZER;
|
||||
* 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,
|
||||
|
@ -151,8 +151,8 @@ static TextTrieMap *gShortZoneIdTrie = NULL;
|
||||
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
|
||||
|
@ -273,8 +273,8 @@ GNameSearchHandler::getMatches(int32_t& maxMatchLen) {
|
||||
}
|
||||
|
||||
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 @@ typedef struct TZGNCoreRef {
|
||||
|
||||
// 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;
|
||||
|
@ -30,8 +30,8 @@ U_NAMESPACE_BEGIN
|
||||
|
||||
// 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;
|
||||
|
@ -53,8 +53,8 @@ static const char* TZDBNAMES_KEYS[] = {"ss", "sd"};
|
||||
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 @@ TextTrieMap::search(const UnicodeString &text, int32_t start,
|
||||
// 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 @@ TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& statu
|
||||
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 @@ TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& statu
|
||||
tzdbNames = (TZDBNames *)cacheVal;
|
||||
}
|
||||
}
|
||||
umtx_unlock(&gTZDBNamesMapLock);
|
||||
umtx_unlock(gTZDBNamesMapLock);
|
||||
|
||||
return tzdbNames;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -47,8 +47,8 @@ U_CDECL_END
|
||||
|
||||
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;
|
||||
|
@ -20,7 +20,7 @@ system_symbols:
|
||||
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: trigonometry
|
||||
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 @@ group: platform
|
||||
# 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
|
||||
|
@ -105,10 +105,9 @@ def _ReadLibrary(root_path, library_name):
|
||||
# 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):
|
||||
|
@ -1116,8 +1116,8 @@ void IntlTest::LL_message( UnicodeString message, UBool newline )
|
||||
// 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
|
||||
|
@ -241,12 +241,12 @@ void MultithreadTest::TestArabicShapingThreads()
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
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 @@ public:
|
||||
// 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 @@ void MultithreadTest::TestMutex()
|
||||
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 @@ class CondThread: public SimpleThread {
|
||||
};
|
||||
|
||||
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 @@ static const int NUMTHREADS = 10;
|
||||
|
||||
// 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 @@ const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
|
||||
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 @@ const UCTMultiThreadItem *LocaleCacheKey<UCTMultiThreadItem>::createObject(
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user