From 803ac8f33c4fa2bbc35cb37aea1c4fffe1a5911c Mon Sep 17 00:00:00 2001 From: Andy Heninger Date: Fri, 5 Oct 2012 21:22:02 +0000 Subject: [PATCH] ICU-9461 Mutex Implementation Rework, merge from devel branch. X-SVN-Rev: 32530 --- icu4c/source/common/common.vcxproj | 2 +- icu4c/source/common/common.vcxproj.filters | 2 +- icu4c/source/common/listformatter.cpp | 2 +- icu4c/source/common/mutex.h | 10 +- icu4c/source/common/putil.cpp | 2 +- icu4c/source/common/serv.cpp | 8 +- icu4c/source/common/servls.cpp | 4 +- icu4c/source/common/servnotf.cpp | 4 +- icu4c/source/common/ubidi_props.c | 3 +- icu4c/source/common/uchar.c | 1 - icu4c/source/common/ucln.h | 1 - icu4c/source/common/ucln_cmn.c | 3 +- icu4c/source/common/ucnv_bld.cpp | 9 +- icu4c/source/common/ucnvmbcs.c | 2 +- icu4c/source/common/udata.cpp | 2 +- icu4c/source/common/uinit.c | 1 - icu4c/source/common/umutex.c | 604 --------------------- icu4c/source/common/umutex.cpp | 483 ++++++++++++++++ icu4c/source/common/umutex.h | 109 +++- icu4c/source/common/uresbund.cpp | 5 +- icu4c/source/common/usprep.cpp | 5 +- icu4c/source/i18n/alphaindex.cpp | 2 +- icu4c/source/i18n/astro.cpp | 5 +- icu4c/source/i18n/chnsecal.cpp | 5 +- icu4c/source/i18n/colldata.cpp | 2 +- icu4c/source/i18n/dtfmtsym.cpp | 2 +- icu4c/source/i18n/gender.cpp | 3 +- icu4c/source/i18n/islamcal.cpp | 5 +- icu4c/source/i18n/numfmt.cpp | 2 +- icu4c/source/i18n/plurrule.cpp | 2 +- icu4c/source/i18n/rbt.cpp | 4 +- icu4c/source/i18n/smpdtfmt.cpp | 3 +- icu4c/source/i18n/timezone.cpp | 13 +- icu4c/source/i18n/translit.cpp | 3 +- icu4c/source/i18n/tridpars.cpp | 5 +- icu4c/source/i18n/tzfmt.cpp | 9 +- icu4c/source/i18n/tzgnames.cpp | 29 +- icu4c/source/i18n/tznames.cpp | 4 +- icu4c/source/i18n/tznames_impl.cpp | 30 +- icu4c/source/i18n/tznames_impl.h | 1 - icu4c/source/i18n/ucurr.cpp | 9 +- icu4c/source/i18n/unicode/tzfmt.h | 5 - icu4c/source/i18n/zonemeta.cpp | 4 +- icu4c/source/test/intltest/tsmthred.cpp | 9 +- 44 files changed, 652 insertions(+), 766 deletions(-) delete mode 100644 icu4c/source/common/umutex.c create mode 100644 icu4c/source/common/umutex.cpp diff --git a/icu4c/source/common/common.vcxproj b/icu4c/source/common/common.vcxproj index c62a1a8e957..9d708136d7d 100644 --- a/icu4c/source/common/common.vcxproj +++ b/icu4c/source/common/common.vcxproj @@ -286,7 +286,7 @@ false - + false false false diff --git a/icu4c/source/common/common.vcxproj.filters b/icu4c/source/common/common.vcxproj.filters index b87cefcf978..01b23c4e3b5 100644 --- a/icu4c/source/common/common.vcxproj.filters +++ b/icu4c/source/common/common.vcxproj.filters @@ -163,7 +163,7 @@ configuration - + configuration diff --git a/icu4c/source/common/listformatter.cpp b/icu4c/source/common/listformatter.cpp index 31c46484a2a..6a6e986377d 100644 --- a/icu4c/source/common/listformatter.cpp +++ b/icu4c/source/common/listformatter.cpp @@ -25,7 +25,7 @@ U_NAMESPACE_BEGIN static Hashtable* listPatternHash = NULL; -static UMTX listFormatterMutex = NULL; +static UMutex listFormatterMutex = U_MUTEX_INITIALIZER; static UChar FIRST_PARAMETER[] = { 0x7b, 0x30, 0x7d }; // "{0}" static UChar SECOND_PARAMETER[] = { 0x7b, 0x31, 0x7d }; // "{0}" diff --git a/icu4c/source/common/mutex.h b/icu4c/source/common/mutex.h index 7f7ef897afa..af8cd8cb9c2 100644 --- a/icu4c/source/common/mutex.h +++ b/icu4c/source/common/mutex.h @@ -1,7 +1,7 @@ /* ****************************************************************************** * -* Copyright (C) 1997-2011, International Business Machines +* Copyright (C) 1997-2012, International Business Machines * Corporation and others. All Rights Reserved. * ****************************************************************************** @@ -33,7 +33,7 @@ U_NAMESPACE_BEGIN // For example: // -// UMTX myMutex; +// UMutex myMutex; // // void Function(int arg1, int arg2) // { @@ -50,17 +50,17 @@ U_NAMESPACE_BEGIN class U_COMMON_API Mutex : public UMemory { public: - inline Mutex(UMTX *mutex = NULL); + inline Mutex(UMutex *mutex = NULL); inline ~Mutex(); private: - UMTX *fMutex; + UMutex *fMutex; Mutex(const Mutex &other); // forbid copying of this class Mutex &operator=(const Mutex &other); // forbid copying of this class }; -inline Mutex::Mutex(UMTX *mutex) +inline Mutex::Mutex(UMutex *mutex) : fMutex(mutex) { umtx_lock(fMutex); diff --git a/icu4c/source/common/putil.cpp b/icu4c/source/common/putil.cpp index 9946d8e1b65..4694aa9a806 100644 --- a/icu4c/source/common/putil.cpp +++ b/icu4c/source/common/putil.cpp @@ -240,7 +240,7 @@ u_signBit(double d) { UDate fakeClock_t0 = 0; /** Time to start the clock from **/ UDate fakeClock_dt = 0; /** Offset (fake time - real time) **/ UBool fakeClock_set = FALSE; /** True if fake clock has spun up **/ -static UMTX fakeClockMutex = NULL; +static UMutex fakeClockMutex = U_MUTEX_INTIALIZER; static UDate getUTCtime_real() { struct timeval posixTime; diff --git a/icu4c/source/common/serv.cpp b/icu4c/source/common/serv.cpp index 2cddcfe65dc..1a8c9166e04 100644 --- a/icu4c/source/common/serv.cpp +++ b/icu4c/source/common/serv.cpp @@ -1,6 +1,6 @@ /** ******************************************************************************* -* Copyright (C) 2001-2011, International Business Machines Corporation. +* Copyright (C) 2001-2012, International Business Machines Corporation. * All Rights Reserved. ******************************************************************************* */ @@ -331,7 +331,7 @@ U_CDECL_END ****************************************************************** */ -static UMTX lock; +static UMutex lock = U_MUTEX_INITIALIZER; ICUService::ICUService() : name() @@ -401,7 +401,7 @@ ICUService::getKey(ICUServiceKey& key, UnicodeString* actualReturn, UErrorCode& // reentrantly even without knowing the thread. class XMutex : public UMemory { public: - inline XMutex(UMTX *mutex, UBool reentering) + inline XMutex(UMutex *mutex, UBool reentering) : fMutex(mutex) , fActive(!reentering) { @@ -412,7 +412,7 @@ public: } private: - UMTX *fMutex; + UMutex *fMutex; UBool fActive; }; diff --git a/icu4c/source/common/servls.cpp b/icu4c/source/common/servls.cpp index 0e29bfcee6f..418be4a5d94 100644 --- a/icu4c/source/common/servls.cpp +++ b/icu4c/source/common/servls.cpp @@ -1,6 +1,6 @@ /** ******************************************************************************* - * Copyright (C) 2001-2011, International Business Machines Corporation and * + * Copyright (C) 2001-2012, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* * @@ -25,7 +25,7 @@ U_NAMESPACE_BEGIN -static UMTX llock; +static UMutex llock = U_MUTEX_INITIALIZER; ICULocaleService::ICULocaleService() : fallbackLocale(Locale::getDefault()) { diff --git a/icu4c/source/common/servnotf.cpp b/icu4c/source/common/servnotf.cpp index feecbc31dd2..dbcbe92df80 100644 --- a/icu4c/source/common/servnotf.cpp +++ b/icu4c/source/common/servnotf.cpp @@ -1,6 +1,6 @@ /** ******************************************************************************* - * Copyright (C) 2001-2011, International Business Machines Corporation and * + * Copyright (C) 2001-2012, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -19,7 +19,7 @@ U_NAMESPACE_BEGIN EventListener::~EventListener() {} UOBJECT_DEFINE_RTTI_IMPLEMENTATION(EventListener) -static UMTX notifyLock; +static UMutex notifyLock = U_MUTEX_INITIALIZER; ICUNotifier::ICUNotifier(void) : listeners(NULL) diff --git a/icu4c/source/common/ubidi_props.c b/icu4c/source/common/ubidi_props.c index 6fca5a34074..e6f197431d2 100644 --- a/icu4c/source/common/ubidi_props.c +++ b/icu4c/source/common/ubidi_props.c @@ -1,7 +1,7 @@ /* ******************************************************************************* * -* Copyright (C) 2004-2011, International Business Machines +* Copyright (C) 2004-2012, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -21,7 +21,6 @@ #include "unicode/udata.h" /* UDataInfo */ #include "ucmndata.h" /* DataHeader */ #include "udatamem.h" -#include "umutex.h" #include "uassert.h" #include "cmemory.h" #include "utrie2.h" diff --git a/icu4c/source/common/uchar.c b/icu4c/source/common/uchar.c index d8520e21629..53f92ffd6be 100644 --- a/icu4c/source/common/uchar.c +++ b/icu4c/source/common/uchar.c @@ -24,7 +24,6 @@ #include "unicode/uscript.h" #include "unicode/udata.h" #include "uassert.h" -#include "umutex.h" #include "cmemory.h" #include "ucln_cmn.h" #include "utrie2.h" diff --git a/icu4c/source/common/ucln.h b/icu4c/source/common/ucln.h index 47f082a154e..2a83d9467ec 100644 --- a/icu4c/source/common/ucln.h +++ b/icu4c/source/common/ucln.h @@ -18,7 +18,6 @@ #define __UCLN_H__ #include "unicode/utypes.h" -#include "umutex.h" /** These are the functions used to register a library's memory cleanup * functions. Each library should define a single library register function diff --git a/icu4c/source/common/ucln_cmn.c b/icu4c/source/common/ucln_cmn.c index a7776ba4a6f..513d796e581 100644 --- a/icu4c/source/common/ucln_cmn.c +++ b/icu4c/source/common/ucln_cmn.c @@ -26,7 +26,7 @@ #include "ucln_imp.h" static UBool gICUInitialized = FALSE; -static UMTX gICUInitMutex = NULL; +static UMutex gICUInitMutex = U_MUTEX_INITIALIZER; static cleanupFunc *gCommonCleanupFunctions[UCLN_COMMON_COUNT]; static cleanupFunc *gLibCleanupFunctions[UCLN_COMMON]; @@ -58,7 +58,6 @@ u_cleanup(void) ucln_lib_cleanup(); - umtx_destroy(&gICUInitMutex); umtx_cleanup(); cmemory_cleanup(); /* undo any heap functions set by u_setMemoryFunctions(). */ gICUInitialized = FALSE; diff --git a/icu4c/source/common/ucnv_bld.cpp b/icu4c/source/common/ucnv_bld.cpp index 02159f97d0e..9532620c57d 100644 --- a/icu4c/source/common/ucnv_bld.cpp +++ b/icu4c/source/common/ucnv_bld.cpp @@ -159,9 +159,9 @@ static struct { /*initializes some global variables */ static UHashtable *SHARED_DATA_HASHTABLE = NULL; -static UMTX cnvCacheMutex = NULL; /* Mutex for synchronizing cnv cache access. */ - /* Note: the global mutex is used for */ - /* reference count updates. */ +static UMutex cnvCacheMutex = U_MUTEX_INITIALIZER; /* Mutex for synchronizing cnv cache access. */ + /* Note: the global mutex is used for */ + /* reference count updates. */ static const char **gAvailableConverters = NULL; static uint16_t gAvailableConverterCount = 0; @@ -219,9 +219,6 @@ static UBool U_CALLCONV ucnv_cleanup(void) { gDefaultAlgorithmicSharedData = NULL; #endif - umtx_destroy(&cnvCacheMutex); /* Don't worry about destroying the mutex even */ - /* if the hash table still exists. The mutex */ - /* will lazily re-init itself if needed. */ return (SHARED_DATA_HASHTABLE == NULL); } diff --git a/icu4c/source/common/ucnvmbcs.c b/icu4c/source/common/ucnvmbcs.c index f3d83a3625e..f88adf1d8d5 100644 --- a/icu4c/source/common/ucnvmbcs.c +++ b/icu4c/source/common/ucnvmbcs.c @@ -54,9 +54,9 @@ #include "ucnvmbcs.h" #include "ucnv_ext.h" #include "ucnv_cnv.h" -#include "umutex.h" #include "cmemory.h" #include "cstring.h" +#include "umutex.h" /* control optimizations according to the platform */ #define MBCS_UNROLL_SINGLE_TO_BMP 1 diff --git a/icu4c/source/common/udata.cpp b/icu4c/source/common/udata.cpp index c4f8752a4eb..0837893eeb0 100644 --- a/icu4c/source/common/udata.cpp +++ b/icu4c/source/common/udata.cpp @@ -806,7 +806,7 @@ static UBool extendICUData(UErrorCode *pErr) * Use a specific mutex to avoid nested locks of the global mutex. */ #if MAP_IMPLEMENTATION==MAP_STDIO - static UMTX extendICUDataMutex = NULL; + static UMutex extendICUDataMutex = U_MUTEX_INITIALIZER; umtx_lock(&extendICUDataMutex); #endif if(!gHaveTriedToLoadCommonData) { diff --git a/icu4c/source/common/uinit.c b/icu4c/source/common/uinit.c index 44d496acbd4..db3f252c5fb 100644 --- a/icu4c/source/common/uinit.c +++ b/icu4c/source/common/uinit.c @@ -21,7 +21,6 @@ #include "icuplugimp.h" #include "ucln.h" #include "ucnv_io.h" -#include "umutex.h" #include "utracimp.h" static void U_CALLCONV diff --git a/icu4c/source/common/umutex.c b/icu4c/source/common/umutex.c deleted file mode 100644 index e36c241adc6..00000000000 --- a/icu4c/source/common/umutex.c +++ /dev/null @@ -1,604 +0,0 @@ -/* -****************************************************************************** -* -* Copyright (C) 1997-2012, International Business Machines -* Corporation and others. All Rights Reserved. -* -****************************************************************************** -* -* File umutex.c -* -* Modification History: -* -* Date Name Description -* 04/02/97 aliu Creation. -* 04/07/99 srl updated -* 05/13/99 stephen Changed to umutex (from cmutex). -* 11/22/99 aliu Make non-global mutex autoinitialize [j151] -****************************************************************************** -*/ - -#include "unicode/utypes.h" -#include "uassert.h" -#include "ucln_cmn.h" - -/* - * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a - * platform independent set of mutex operations. For internal ICU use only. - */ - -#if U_PLATFORM_HAS_WIN32_API - /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */ -# undef POSIX -#elif U_PLATFORM_IMPLEMENTS_POSIX -# define POSIX -#else -# undef POSIX -#endif - -#if defined(POSIX) -# include /* must be first, so that we get the multithread versions of things. */ - -#endif /* POSIX */ - -#if U_PLATFORM_HAS_WIN32_API -# define WIN32_LEAN_AND_MEAN -# define VC_EXTRALEAN -# define NOUSER -# define NOSERVICE -# define NOIME -# define NOMCX -# include -#endif - -#include "umutex.h" -#include "cmemory.h" - -/* - * A note on ICU Mutex Initialization and ICU startup: - * - * ICU mutexes, as used through the rest of the ICU code, are self-initializing. - * To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init - * of other ICU mutexes. For the global mutex itself, we need some other mechanism - * to safely initialize it on first use. This becomes important when two or more - * threads are more or less simultaenously the first to use ICU in a process, and - * are racing into the mutex initialization code. - * - * - * The solution for the global mutex init is platform dependent. - * On POSIX systems, plain C-style initialization can be used on a mutex, with the - * macro PTHREAD_MUTEX_INITIALIZER. The mutex is then ready for use, without - * first calling pthread_mutex_init(). - * - * Windows has no equivalent statically initialized mutex or CRITICAL SECION. - * InitializeCriticalSection() must be called. If the global mutex does not - * appear to be initialized, a thread will create and initialize a new - * CRITICAL_SECTION, then use a Windows InterlockedCompareAndExchange to - * swap it in as the global mutex while avoid problems with race conditions. - */ - -/* On WIN32 mutexes are reentrant. On POSIX platforms they are not, and a deadlock - * will occur if a thread attempts to acquire a mutex it already has locked. - * ICU mutexes (in debug builds) include checking code that will cause an assertion - * failure if a mutex is reentered. If you are having deadlock problems - * on a POSIX machine, debugging may be easier on Windows. - */ - - -#if U_PLATFORM_HAS_WIN32_API -#define MUTEX_TYPE CRITICAL_SECTION -#define PLATFORM_MUTEX_INIT(m) InitializeCriticalSection(m) -#define PLATFORM_MUTEX_LOCK(m) EnterCriticalSection(m) -#define PLATFORM_MUTEX_UNLOCK(m) LeaveCriticalSection(m) -#define PLATFORM_MUTEX_DESTROY(m) DeleteCriticalSection(m) -#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ - InterlockedCompareExchangePointer(dest, newval, oldval) - - -#elif defined(POSIX) -#define MUTEX_TYPE pthread_mutex_t -#define PLATFORM_MUTEX_INIT(m) pthread_mutex_init(m, NULL) -#define PLATFORM_MUTEX_LOCK(m) pthread_mutex_lock(m) -#define PLATFORM_MUTEX_UNLOCK(m) pthread_mutex_unlock(m) -#define PLATFORM_MUTEX_DESTROY(m) pthread_mutex_destroy(m) -#define PLATFORM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#if (U_HAVE_GCC_ATOMICS == 1) -#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ - __sync_val_compare_and_swap(dest, oldval, newval) -#else -#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ - mutexed_compare_and_swap(dest, newval, oldval) -#endif - - -#else -/* Unknown platform. Note that user can still set mutex functions at run time. */ -#define MUTEX_TYPE void * -#define PLATFORM_MUTEX_INIT(m) -#define PLATFORM_MUTEX_LOCK(m) -#define PLATFORM_MUTEX_UNLOCK(m) -#define PLATFORM_MUTEX_DESTROY(m) -#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ - mutexed_compare_and_swap(dest, newval, oldval) - -#endif - -/* Forward declarations */ -static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval); -typedef struct ICUMutex ICUMutex; - -/* - * ICUMutex One of these is set up for each UMTX that is used by other ICU code. - * The opaque UMTX points to the corresponding ICUMutex struct. - * - * Because the total number of ICU mutexes is quite small, no effort has - * been made to squeeze every byte out of this struct. - */ -struct ICUMutex { - UMTX *owner; /* Points back to the UMTX corrsponding to this */ - /* ICUMutex object. */ - - UBool heapAllocated; /* Set if this ICUMutex is heap allocated, and */ - /* will need to be deleted. The global mutex */ - /* is static on POSIX platforms; all others */ - /* will be heap allocated. */ - - ICUMutex *next; /* All ICUMutexes are chained into a list so that */ - /* they can be found and deleted by u_cleanup(). */ - - int32_t recursionCount; /* For debugging, detect recursive mutex locks. */ - - MUTEX_TYPE platformMutex; /* The underlying OS mutex being wrapped. */ - - UMTX userMutex; /* For use with u_setMutexFunctions operations, */ - /* corresponds to platformMutex. */ -}; - - -/* The global ICU mutex. - * For POSIX platforms, it gets a C style initialization, and is ready to use - * at program startup. - * For Windows, it will be lazily instantiated on first use. - */ - -#if defined(POSIX) -static UMTX globalUMTX; -static ICUMutex globalMutex = {&globalUMTX, FALSE, NULL, 0, PLATFORM_MUTEX_INITIALIZER, NULL}; -static UMTX globalUMTX = &globalMutex; -#else -static UMTX globalUMTX = NULL; -#endif - -/* Head of the list of all ICU mutexes. - * Linked list is through ICUMutex::next - * Modifications to the list are synchronized with the global mutex. - * The list is used by u_cleanup(), which needs to dispose of all of the ICU mutexes. - * - * The statically initialized global mutex on POSIX platforms does not get added to this - * mutex list, but that's not a problem - the global mutex gets special handling - * during u_cleanup(). - */ -static ICUMutex *mutexListHead; - - -/* - * User mutex implementation functions. If non-null, call back to these rather than - * directly using the system (Posix or Windows) APIs. See u_setMutexFunctions(). - * (declarations are in uclean.h) - */ -static UMtxInitFn *pMutexInitFn = NULL; -static UMtxFn *pMutexDestroyFn = NULL; -static UMtxFn *pMutexLockFn = NULL; -static UMtxFn *pMutexUnlockFn = NULL; -static const void *gMutexContext = NULL; - - -/* - * umtx_lock - */ -U_CAPI void U_EXPORT2 -umtx_lock(UMTX *mutex) -{ - ICUMutex *m; - - if (mutex == NULL) { - mutex = &globalUMTX; - } - m = (ICUMutex *)*mutex; - if (m == NULL) { - /* See note on lazy initialization, above. We can get away with it here, with mutexes, - * where we couldn't with normal user level data. - */ - umtx_init(mutex); - m = (ICUMutex *)*mutex; - } - U_ASSERT(m->owner == mutex); - - if (pMutexLockFn != NULL) { - (*pMutexLockFn)(gMutexContext, &m->userMutex); - } else { - PLATFORM_MUTEX_LOCK(&m->platformMutex); - } - -#if defined(U_DEBUG) - m->recursionCount++; /* Recursion causes deadlock on Unixes. */ - U_ASSERT(m->recursionCount == 1); /* Recursion detection works on Windows. */ - /* Assertion failure on non-Windows indicates a */ - /* problem with the mutex implementation itself. */ -#endif -} - - - -/* - * umtx_unlock - */ -U_CAPI void U_EXPORT2 -umtx_unlock(UMTX* mutex) -{ - ICUMutex *m; - if(mutex == NULL) { - mutex = &globalUMTX; - } - m = (ICUMutex *)*mutex; - if (m == NULL) { - U_ASSERT(FALSE); /* This mutex is not initialized. */ - return; - } - U_ASSERT(m->owner == mutex); - -#if defined (U_DEBUG) - m->recursionCount--; - U_ASSERT(m->recursionCount == 0); /* Detect unlock of an already unlocked mutex */ -#endif - - if (pMutexUnlockFn) { - (*pMutexUnlockFn)(gMutexContext, &m->userMutex); - } else { - PLATFORM_MUTEX_UNLOCK(&m->platformMutex); - } -} - - -/* umtx_ct Allocate and initialize a new ICUMutex. - * If a non-null pointer is supplied, initialize an existing ICU Mutex. - */ -static ICUMutex *umtx_ct(ICUMutex *m) { - if (m == NULL) { - m = (ICUMutex *)uprv_malloc(sizeof(ICUMutex)); - m->heapAllocated = TRUE; - } - m->next = NULL; /* List of mutexes is maintained at a higher level. */ - m->recursionCount = 0; - m->userMutex = NULL; - if (pMutexInitFn != NULL) { - UErrorCode status = U_ZERO_ERROR; - (*pMutexInitFn)(gMutexContext, &m->userMutex, &status); - U_ASSERT(U_SUCCESS(status)); - } else { - PLATFORM_MUTEX_INIT(&m->platformMutex); - } - return m; -} - - -/* umtx_dt Delete a ICUMutex. Destroy the underlying OS Platform mutex. - * Does not touch the linked list of ICU Mutexes. - */ -static void umtx_dt(ICUMutex *m) { - if (pMutexDestroyFn != NULL) { - (*pMutexDestroyFn)(gMutexContext, &m->userMutex); - m->userMutex = NULL; - } else { - PLATFORM_MUTEX_DESTROY(&m->platformMutex); - } - - if (m->heapAllocated) { - uprv_free(m); - } -} - - -U_CAPI void U_EXPORT2 -umtx_init(UMTX *mutex) { - ICUMutex *m = NULL; - void *originalValue; - - if (*mutex != NULL) { - /* Mutex is already initialized. - * Multiple umtx_init()s of a UMTX by other ICU code are explicitly permitted. - */ - return; - } -#if defined(POSIX) - if (mutex == &globalUMTX) { - m = &globalMutex; - } -#endif - - m = umtx_ct(m); - originalValue = SYNC_COMPARE_AND_SWAP(mutex, NULL, m); - if (originalValue != NULL) { - umtx_dt(m); - return; - } - - m->owner = mutex; - - /* Hook the new mutex into the list of all ICU mutexes, so that we can find and - * delete it for u_cleanup(). - */ - - umtx_lock(NULL); - m->next = mutexListHead; - mutexListHead = m; - umtx_unlock(NULL); - return; -} - - -/* - * umtx_destroy. Un-initialize a mutex, releasing any underlying resources - * that it may be holding. Destroying an already destroyed - * mutex has no effect. Unlike umtx_init(), this function - * is not thread safe; two threads must not concurrently try to - * destroy the same mutex. - */ -U_CAPI void U_EXPORT2 -umtx_destroy(UMTX *mutex) { - ICUMutex *m; - - /* No one should be deleting the global ICU mutex. - * (u_cleanup() does delete it, but does so explicitly, not by passing NULL) - */ - U_ASSERT(mutex != NULL); - if (mutex == NULL) { - return; - } - - m = (ICUMutex *)*mutex; - if (m == NULL) { /* Mutex not initialized, or already destroyed. */ - return; - } - - U_ASSERT(m->owner == mutex); - if (m->owner != mutex) { - return; - } - - /* Remove this mutex from the linked list of mutexes. */ - umtx_lock(NULL); - if (mutexListHead == m) { - mutexListHead = m->next; - } else { - ICUMutex *prev; - for (prev = mutexListHead; prev!=NULL && prev->next!=m; prev = prev->next); - /* Empty for loop body */ - if (prev != NULL) { - prev->next = m->next; - } - } - umtx_unlock(NULL); - - umtx_dt(m); /* Delete the internal ICUMutex */ - *mutex = NULL; /* Clear the caller's UMTX */ -} - - - -U_CAPI void U_EXPORT2 -u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u, - UErrorCode *status) { - if (U_FAILURE(*status)) { - return; - } - - /* Can not set a mutex function to a NULL value */ - if (i==NULL || d==NULL || l==NULL || u==NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - - /* If ICU is not in an initial state, disallow this operation. */ - if (cmemory_inUse()) { - *status = U_INVALID_STATE_ERROR; - return; - } - - /* Kill any existing global mutex. POSIX platforms have a global mutex - * even before any other part of ICU is initialized. - */ - umtx_destroy(&globalUMTX); - - /* Swap in the mutex function pointers. */ - pMutexInitFn = i; - pMutexDestroyFn = d; - pMutexLockFn = l; - pMutexUnlockFn = u; - gMutexContext = context; - -#if defined (POSIX) - /* POSIX platforms must have a pre-initialized global mutex - * to allow other mutexes to initialize safely. */ - umtx_init(&globalUMTX); -#endif -} - - -/* synchronized compare and swap function, for use when OS or compiler built-in - * equivalents aren't available. - * - * This operation relies on the ICU global mutex for synchronization. - * - * There are two cases where this function can be entered when the global mutex is not - * yet initialized - at the end u_cleanup(), and at the end of u_setMutexFunctions, both - * of which re-init the global mutex. But neither function is thread-safe, so the lack of - * synchronization at these points doesn't matter. - */ -static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) { - void *temp; - UBool needUnlock = FALSE; - - if (globalUMTX != NULL) { - umtx_lock(&globalUMTX); - needUnlock = TRUE; - } - - temp = *dest; - if (temp == oldval) { - *dest = newval; - } - - if (needUnlock) { - umtx_unlock(&globalUMTX); - } - return temp; -} - - - -/*----------------------------------------------------------------- - * - * Atomic Increment and Decrement - * umtx_atomic_inc - * umtx_atomic_dec - * - *----------------------------------------------------------------*/ - -/* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */ -static UMtxAtomicFn *pIncFn = NULL; -static UMtxAtomicFn *pDecFn = NULL; -static const void *gIncDecContext = NULL; - -static UMTX gIncDecMutex = NULL; - -U_CAPI int32_t U_EXPORT2 -umtx_atomic_inc(int32_t *p) { - int32_t retVal; - if (pIncFn) { - retVal = (*pIncFn)(gIncDecContext, p); - } else { - #if U_PLATFORM_HAS_WIN32_API - retVal = InterlockedIncrement((LONG*)p); - #elif defined(USE_MAC_OS_ATOMIC_INCREMENT) - retVal = OSAtomicIncrement32Barrier(p); - #elif (U_HAVE_GCC_ATOMICS == 1) - retVal = __sync_add_and_fetch(p, 1); - #elif defined (POSIX) - umtx_lock(&gIncDecMutex); - retVal = ++(*p); - umtx_unlock(&gIncDecMutex); - #else - /* Unknown Platform. */ - retVal = ++(*p); - #endif - } - return retVal; -} - -U_CAPI int32_t U_EXPORT2 -umtx_atomic_dec(int32_t *p) { - int32_t retVal; - if (pDecFn) { - retVal = (*pDecFn)(gIncDecContext, p); - } else { - #if U_PLATFORM_HAS_WIN32_API - retVal = InterlockedDecrement((LONG*)p); - #elif defined(USE_MAC_OS_ATOMIC_INCREMENT) - retVal = OSAtomicDecrement32Barrier(p); - #elif (U_HAVE_GCC_ATOMICS == 1) - retVal = __sync_sub_and_fetch(p, 1); - #elif defined (POSIX) - umtx_lock(&gIncDecMutex); - retVal = --(*p); - umtx_unlock(&gIncDecMutex); - #else - /* Unknown Platform. */ - retVal = --(*p); - #endif - } - return retVal; -} - - - -U_CAPI void U_EXPORT2 -u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp, - UErrorCode *status) { - if (U_FAILURE(*status)) { - return; - } - /* Can not set a mutex function to a NULL value */ - if (ip==NULL || dp==NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; - return; - } - /* If ICU is not in an initial state, disallow this operation. */ - if (cmemory_inUse()) { - *status = U_INVALID_STATE_ERROR; - return; - } - - pIncFn = ip; - pDecFn = dp; - gIncDecContext = context; - -#if U_DEBUG - { - int32_t testInt = 0; - U_ASSERT(umtx_atomic_inc(&testInt) == 1); /* Sanity Check. Do the functions work at all? */ - U_ASSERT(testInt == 1); - U_ASSERT(umtx_atomic_dec(&testInt) == 0); - U_ASSERT(testInt == 0); - } -#endif -} - - - -/* - * Mutex Cleanup Function - * - * Destroy the global mutex(es), and reset the mutex function callback pointers. - */ -U_CFUNC UBool umtx_cleanup(void) { - ICUMutex *thisMutex = NULL; - ICUMutex *nextMutex = NULL; - - /* Extra, do-nothing function call to suppress compiler warnings on platforms where - * mutexed_compare_and_swap is not otherwise used. */ - mutexed_compare_and_swap(&globalUMTX, NULL, NULL); - - /* Delete all of the ICU mutexes. Do the global mutex last because it is used during - * the umtx_destroy operation of other mutexes. - */ - for (thisMutex=mutexListHead; thisMutex!=NULL; thisMutex=nextMutex) { - UMTX *umtx = thisMutex->owner; - nextMutex = thisMutex->next; - U_ASSERT(*umtx = (void *)thisMutex); - if (umtx != &globalUMTX) { - umtx_destroy(umtx); - } - } - umtx_destroy(&globalUMTX); - - pMutexInitFn = NULL; - pMutexDestroyFn = NULL; - pMutexLockFn = NULL; - pMutexUnlockFn = NULL; - gMutexContext = NULL; - pIncFn = NULL; - pDecFn = NULL; - gIncDecContext = NULL; - gIncDecMutex = NULL; - -#if defined (POSIX) - /* POSIX platforms must come out of u_cleanup() with a functioning global mutex - * to permit the safe resumption of use of ICU in multi-threaded environments. - */ - umtx_init(&globalUMTX); -#endif - return TRUE; -} - - diff --git a/icu4c/source/common/umutex.cpp b/icu4c/source/common/umutex.cpp new file mode 100644 index 00000000000..a7299a5cfd1 --- /dev/null +++ b/icu4c/source/common/umutex.cpp @@ -0,0 +1,483 @@ +/* +****************************************************************************** +* +* Copyright (C) 1997-2012, International Business Machines +* Corporation and others. All Rights Reserved. +* +****************************************************************************** +* +* File umutex.cpp +* +* Modification History: +* +* Date Name Description +* 04/02/97 aliu Creation. +* 04/07/99 srl updated +* 05/13/99 stephen Changed to umutex (from cmutex). +* 11/22/99 aliu Make non-global mutex autoinitialize [j151] +****************************************************************************** +*/ + +#include "unicode/utypes.h" +#include "uassert.h" +#include "ucln_cmn.h" + +/* + * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a + * platform independent set of mutex operations. For internal ICU use only. + */ + +#if U_PLATFORM_HAS_WIN32_API + /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */ +# undef POSIX +#elif U_PLATFORM_IMPLEMENTS_POSIX +# define POSIX +#else +# undef POSIX +#endif + +#if defined(POSIX) +# include /* must be first, so that we get the multithread versions of things. */ +#endif /* POSIX */ + +#if U_PLATFORM_HAS_WIN32_API +# define WIN32_LEAN_AND_MEAN +# define VC_EXTRALEAN +# define NOUSER +# define NOSERVICE +# define NOIME +# define NOMCX +# include +#endif + +#include "umutex.h" +#include "cmemory.h" + +#if U_PLATFORM_HAS_WIN32_API +#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ + InterlockedCompareExchangePointer(dest, newval, oldval) + +#elif defined(POSIX) +#if (U_HAVE_GCC_ATOMICS == 1) +#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ + __sync_val_compare_and_swap(dest, oldval, newval) +#else +#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ + mutexed_compare_and_swap(dest, newval, oldval) +#endif + +#else +// Unknown platform. Note that user can still set mutex functions at run time. +#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \ + mutexed_compare_and_swap(dest, newval, oldval) +#endif + +static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval); + +// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer. +static UMutex globalMutex = U_MUTEX_INITIALIZER; + +// Implementation mutex. Used for compare & swap when no intrinsic is available, and +// for safe initialization of user defined mutexes. +static UMutex implMutex = U_MUTEX_INITIALIZER; + +// List of all user mutexes that have been initialized. +// Used to allow us to destroy them when cleaning up ICU. +// Normal platform mutexes are not kept track of in this way - they survive until the process is shut down. +// Normal platfrom mutexes don't allocate storage, so not cleaning them up won't trigger memory leak complaints. +// +// Note: putting this list in allocated memory would be awkward to arrange, because memory allocations +// are used as a flag to indicate that ICU has been initialized, and setting other ICU +// override functions will no longer work. +// +static const int MUTEX_LIST_LIMIT = 100; +static UMutex *gMutexList[MUTEX_LIST_LIMIT]; +static int gMutexListSize = 0; + + +/* + * User mutex implementation functions. If non-null, call back to these rather than + * directly using the system (Posix or Windows) APIs. See u_setMutexFunctions(). + * (declarations are in uclean.h) + */ +static UMtxInitFn *pMutexInitFn = NULL; +static UMtxFn *pMutexDestroyFn = NULL; +static UMtxFn *pMutexLockFn = NULL; +static UMtxFn *pMutexUnlockFn = NULL; +static const void *gMutexContext = NULL; + + +// Clean up (undo) the effects of u_setMutexFunctions(). +// +static void usrMutexCleanup() { + if (pMutexDestroyFn != NULL) { + for (int i = 0; i < gMutexListSize; i++) { + UMutex *m = gMutexList[i]; + U_ASSERT(m->fInitialized); + (*pMutexDestroyFn)(gMutexContext, &m->fUserMutex); + m->fInitialized = FALSE; + } + (*pMutexDestroyFn)(gMutexContext, &globalMutex.fUserMutex); + (*pMutexDestroyFn)(gMutexContext, &implMutex.fUserMutex); + } + gMutexListSize = 0; + pMutexInitFn = NULL; + pMutexDestroyFn = NULL; + pMutexLockFn = NULL; + pMutexUnlockFn = NULL; + gMutexContext = NULL; +} + + +/* + * User mutex lock. + * + * User mutexes need to be initialized before they can be used. We use the impl mutex + * to synchronize the initialization check. This could be sped up on platforms that + * support alternate ways to safely check the initialization flag. + * + */ +static void usrMutexLock(UMutex *mutex) { + UErrorCode status = U_ZERO_ERROR; + if (!(mutex == &implMutex || mutex == &globalMutex)) { + umtx_lock(&implMutex); + if (!mutex->fInitialized) { + (*pMutexInitFn)(gMutexContext, &mutex->fUserMutex, &status); + U_ASSERT(U_SUCCESS(status)); + mutex->fInitialized = TRUE; + U_ASSERT(gMutexListSize < MUTEX_LIST_LIMIT); + if (gMutexListSize < MUTEX_LIST_LIMIT) { + gMutexList[gMutexListSize] = mutex; + ++gMutexListSize; + } + } + umtx_unlock(&implMutex); + } + (*pMutexLockFn)(gMutexContext, &mutex->fUserMutex); +} + + + +#if defined(POSIX) + +// +// POSIX implementation of UMutex. +// +// Each UMutex has a corresponding pthread_mutex_t. +// All are statically initialized and ready for use. +// There is no runtime mutex initialization code needed. + +U_CAPI void U_EXPORT2 +umtx_lock(UMutex *mutex) { + if (mutex == NULL) { + mutex = &globalMutex; + } + if (pMutexLockFn) { + usrMutexLock(mutex); + } else { + #if U_DEBUG + // #if to avoid unused variable warnings in non-debug builds. + int sysErr = pthread_mutex_lock(&mutex->fMutex); + U_ASSERT(sysErr == 0); + #else + pthread_mutex_lock(&mutex->fMutex); + #endif + } +} + + +U_CAPI void U_EXPORT2 +umtx_unlock(UMutex* mutex) +{ + if (mutex == NULL) { + mutex = &globalMutex; + } + if (pMutexUnlockFn) { + (*pMutexUnlockFn)(gMutexContext, &mutex->fUserMutex); + } else { + #if U_DEBUG + // #if to avoid unused variable warnings in non-debug builds. + int sysErr = pthread_mutex_unlock(&mutex->fMutex); + U_ASSERT(sysErr == 0); + #else + pthread_mutex_unlock(&mutex->fMutex); + #endif + } +} + +#elif U_PLATFORM_HAS_WIN32_API +// +// Windows implementation of UMutex. +// +// Each UMutex has a corresponding Windows CRITICAL_SECTION. +// CRITICAL_SECTIONS must be initialized before use. This is done +// with a InitOnceExcuteOnce operation. +// +// InitOnceExecuteOnce was introduced with Windows Vista. For now ICU +// must support Windows XP, so we roll our own. ICU will switch to the +// native Windows InitOnceExecuteOnce when possible. + +typedef UBool (*U_PINIT_ONCE_FN) ( + U_INIT_ONCE *initOnce, + void *parameter, + void **context +); + +UBool u_InitOnceExecuteOnce( + U_INIT_ONCE *initOnce, + U_PINIT_ONCE_FN initFn, + void *parameter, + void **context) { + for (;;) { + long previousState = InterlockedCompareExchange( + &initOnce->fState, // Destination, + 1, // Exchange Value + 0); // Compare value + if (previousState == 2) { + // Initialization was already completed. + if (context != NULL) { + *context = initOnce->fContext; + } + return TRUE; + } + if (previousState == 1) { + // Initialization is in progress in some other thread. + // Loop until it completes. + Sleep(1); + continue; + } + + // Initialization needed. Execute the callback function to do it. + U_ASSERT(previousState == 0); + U_ASSERT(initOnce->fState == 1); + UBool success = (*initFn)(initOnce, parameter, &initOnce->fContext); + U_ASSERT(success); // ICU is not supporting the failure case. + + // Assign the state indicating that initialization has completed. + // Using InterlockedCompareExchange to do it ensures that all + // threads will have a consistent view of memory. + previousState = InterlockedCompareExchange(&initOnce->fState, 2, 1); + U_ASSERT(previousState == 1); + // Next loop iteration will see the initialization and return. + } +}; + +static UBool winMutexInit(U_INIT_ONCE *initOnce, void *param, void **context) { + UMutex *mutex = static_cast(param); + U_ASSERT(sizeof(CRITICAL_SECTION) <= sizeof(mutex->fCS)); + InitializeCriticalSection((CRITICAL_SECTION *)mutex->fCS); + return TRUE; +} + +/* + * umtx_lock + */ +U_CAPI void U_EXPORT2 +umtx_lock(UMutex *mutex) { + if (mutex == NULL) { + mutex = &globalMutex; + } + if (pMutexLockFn) { + usrMutexLock(mutex); + } else { + u_InitOnceExecuteOnce(&mutex->fInitOnce, winMutexInit, mutex, NULL); + EnterCriticalSection((CRITICAL_SECTION *)mutex->fCS); + } +} + +U_CAPI void U_EXPORT2 +umtx_unlock(UMutex* mutex) +{ + if (mutex == NULL) { + mutex = &globalMutex; + } + if (pMutexUnlockFn) { + (*pMutexUnlockFn)(gMutexContext, &mutex->fUserMutex); + } else { + LeaveCriticalSection((CRITICAL_SECTION *)mutex->fCS); + } +} + +#endif // Windows Implementation + + +U_CAPI void U_EXPORT2 +u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u, + UErrorCode *status) { + if (U_FAILURE(*status)) { + return; + } + + /* Can not set a mutex function to a NULL value */ + if (i==NULL || d==NULL || l==NULL || u==NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + + /* If ICU is not in an initial state, disallow this operation. */ + if (cmemory_inUse()) { + *status = U_INVALID_STATE_ERROR; + return; + } + + // Clean up any previously set user mutex functions. + // It's possible to call u_setMutexFunctions() more than once without without explicitly cleaning up, + // and the last call should take. Kind of a corner case, but it worked once, there is a test for + // it, so we keep it working. The global and impl mutexes will have been created by the + // previous u_setMutexFunctions(), and now need to be destroyed. + + usrMutexCleanup(); + + /* Swap in the mutex function pointers. */ + pMutexInitFn = i; + pMutexDestroyFn = d; + pMutexLockFn = l; + pMutexUnlockFn = u; + gMutexContext = context; + gMutexListSize = 0; + + /* Initialize the global and impl mutexes. Safe to do at this point because + * u_setMutexFunctions must be done in a single-threaded envioronment. Not thread safe. + */ + (*pMutexInitFn)(gMutexContext, &globalMutex.fUserMutex, status); + globalMutex.fInitialized = TRUE; + (*pMutexInitFn)(gMutexContext, &implMutex.fUserMutex, status); + implMutex.fInitialized = TRUE; +} + + + +/* synchronized compare and swap function, for use when OS or compiler built-in + * equivalents aren't available. + */ +static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) { + umtx_lock(&implMutex); + void *temp = *dest; + if (temp == oldval) { + *dest = newval; + } + umtx_unlock(&implMutex); + + return temp; +} + + + +/*----------------------------------------------------------------- + * + * Atomic Increment and Decrement + * umtx_atomic_inc + * umtx_atomic_dec + * + *----------------------------------------------------------------*/ + +/* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */ +static UMtxAtomicFn *pIncFn = NULL; +static UMtxAtomicFn *pDecFn = NULL; +static const void *gIncDecContext = NULL; + +#if defined (POSIX) && (U_HAVE_GCC_ATOMICS == 0) +static UMutex gIncDecMutex = U_MUTEX_INITIALIZER; +#endif + +U_CAPI int32_t U_EXPORT2 +umtx_atomic_inc(int32_t *p) { + int32_t retVal; + if (pIncFn) { + retVal = (*pIncFn)(gIncDecContext, p); + } else { + #if U_PLATFORM_HAS_WIN32_API + retVal = InterlockedIncrement((LONG*)p); + #elif defined(USE_MAC_OS_ATOMIC_INCREMENT) + retVal = OSAtomicIncrement32Barrier(p); + #elif (U_HAVE_GCC_ATOMICS == 1) + retVal = __sync_add_and_fetch(p, 1); + #elif defined (POSIX) + umtx_lock(&gIncDecMutex); + retVal = ++(*p); + umtx_unlock(&gIncDecMutex); + #else + /* Unknown Platform. */ + retVal = ++(*p); + #endif + } + return retVal; +} + +U_CAPI int32_t U_EXPORT2 +umtx_atomic_dec(int32_t *p) { + int32_t retVal; + if (pDecFn) { + retVal = (*pDecFn)(gIncDecContext, p); + } else { + #if U_PLATFORM_HAS_WIN32_API + retVal = InterlockedDecrement((LONG*)p); + #elif defined(USE_MAC_OS_ATOMIC_INCREMENT) + retVal = OSAtomicDecrement32Barrier(p); + #elif (U_HAVE_GCC_ATOMICS == 1) + retVal = __sync_sub_and_fetch(p, 1); + #elif defined (POSIX) + umtx_lock(&gIncDecMutex); + retVal = --(*p); + umtx_unlock(&gIncDecMutex); + #else + /* Unknown Platform. */ + retVal = --(*p); + #endif + } + return retVal; +} + + + +U_CAPI void U_EXPORT2 +u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp, + UErrorCode *status) { + if (U_FAILURE(*status)) { + return; + } + /* Can not set a mutex function to a NULL value */ + if (ip==NULL || dp==NULL) { + *status = U_ILLEGAL_ARGUMENT_ERROR; + return; + } + /* If ICU is not in an initial state, disallow this operation. */ + if (cmemory_inUse()) { + *status = U_INVALID_STATE_ERROR; + return; + } + + pIncFn = ip; + pDecFn = dp; + gIncDecContext = context; + +#if U_DEBUG + { + int32_t testInt = 0; + U_ASSERT(umtx_atomic_inc(&testInt) == 1); /* Sanity Check. Do the functions work at all? */ + U_ASSERT(testInt == 1); + U_ASSERT(umtx_atomic_dec(&testInt) == 0); + U_ASSERT(testInt == 0); + } +#endif +} + + +/* + * Mutex Cleanup Function + * Reset the mutex function callback pointers. + * Called from the global ICU u_cleanup() function. + */ +U_CFUNC UBool umtx_cleanup(void) { + /* Extra, do-nothing function call to suppress compiler warnings on platforms where + * mutexed_compare_and_swap is not otherwise used. */ + void *pv = &globalMutex; + mutexed_compare_and_swap(&pv, NULL, NULL); + usrMutexCleanup(); + + pIncFn = NULL; + pDecFn = NULL; + gIncDecContext = NULL; + + return TRUE; +} diff --git a/icu4c/source/common/umutex.h b/icu4c/source/common/umutex.h index b2ce411d9a1..259cca37fbd 100644 --- a/icu4c/source/common/umutex.h +++ b/icu4c/source/common/umutex.h @@ -22,10 +22,31 @@ #include "unicode/uclean.h" #include "putilimp.h" +/* For _ReadWriteBarrier(). */ #if defined(_MSC_VER) && _MSC_VER >= 1500 # include #endif +/* For CRITICAL_SECTION */ +#if U_PLATFORM_HAS_WIN32_API +#if 0 +/* TODO(andy): Why doesn't windows.h compile in all files? It does in some. + * The intent was to include windows.h here, and have struct UMutex + * have an embedded CRITICAL_SECTION when building on Windows. + * The workaround is to put some char[] storage in UMutex instead, + * avoiding the need to include windows.h everwhere this header is included. + */ +# define WIN32_LEAN_AND_MEAN +# define VC_EXTRALEAN +# define NOUSER +# define NOSERVICE +# define NOIME +# define NOMCX +# include +#endif /* 0 */ +#define U_WINDOWS_CRIT_SEC_SIZE 64 +#endif /* win32 */ + #if U_PLATFORM_IS_DARWIN_BASED #if defined(__STRICT_ANSI__) #define UPRV_REMAP_INLINE @@ -117,40 +138,78 @@ * an alternative C++ mutex API is defined in the file common/mutex.h */ +/* + * UMutex - Mutexes for use by ICU implementation code. + * Must be declared as static or globals. They cannot appear as members + * of other objects. + * UMutex structs must be initialized. + * Example: + * static UMutex = U_MUTEX_INITIALIZER; + * The declaration of struct UMutex is platform dependent. + */ + + +#if U_PLATFORM_HAS_WIN32_API + +/* U_INIT_ONCE mimics the windows API INIT_ONCE, which exists on Windows Vista and newer. + * When ICU no longer needs to support older Windows platforms (XP) that do not have + * a native INIT_ONCE, switch this implementation over to wrap the native Windows APIs. + */ +typedef struct U_INIT_ONCE { + long fState; + void *fContext; +} U_INIT_ONCE; +#define U_INIT_ONCE_STATIC_INIT {0, NULL} + +typedef struct UMutex { + U_INIT_ONCE fInitOnce; + UMTX fUserMutex; + UBool fInitialized; /* Applies to fUserMutex only. */ + /* CRITICAL_SECTION fCS; */ /* See note above. Unresolved problems with including + * Windows.h, which would allow using CRITICAL_SECTION + * directly here. */ + char fCS[U_WINDOWS_CRIT_SEC_SIZE]; +} UMutex; + +/* Initializer for a static UMUTEX. Deliberately contains no value for the + * CRITICAL_SECTION. + */ +#define U_MUTEX_INITIALIZER {U_INIT_ONCE_STATIC_INIT, NULL, FALSE} + +#elif U_PLATFORM_IMPLEMENTS_POSIX +#include + +struct UMutex { + pthread_mutex_t fMutex; + UMTX fUserMutex; + UBool fInitialized; +}; +#define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, NULL, FALSE} + +#else +/* Unknow platform type. */ +struct UMutex { + void *fMutex; +}; +#define U_MUTEX_INITIALIZER {NULL} +#error Unknown Platform. + +#endif + +typedef struct UMutex UMutex; + /* Lock a mutex. * @param mutex The given mutex to be locked. Pass NULL to specify * the global ICU mutex. Recursive locks are an error * and may cause a deadlock on some platforms. */ -U_CAPI void U_EXPORT2 umtx_lock ( UMTX* mutex ); +U_CAPI void U_EXPORT2 umtx_lock(UMutex* mutex); -/* Unlock a mutex. Pass in NULL if you want the single global - mutex. +/* Unlock a mutex. * @param mutex The given mutex to be unlocked. Pass NULL to specify * the global ICU mutex. */ -U_CAPI void U_EXPORT2 umtx_unlock ( UMTX* mutex ); - -/* Initialize a mutex. Use it this way: - umtx_init( &aMutex ); - * ICU Mutexes do not need explicit initialization before use. Use of this - * function is not necessary. - * Initialization of an already initialized mutex has no effect, and is safe to do. - * Initialization of mutexes is thread safe. Two threads can concurrently - * initialize the same mutex without causing problems. - * @param mutex The given mutex to be initialized - */ -U_CAPI void U_EXPORT2 umtx_init ( UMTX* mutex ); - -/* Destroy a mutex. This will free the resources of a mutex. - * Use it this way: - * umtx_destroy( &aMutex ); - * Destroying an already destroyed mutex has no effect, and causes no problems. - * This function is not thread safe. Two threads must not attempt to concurrently - * destroy the same mutex. - * @param mutex The given mutex to be destroyed. - */ -U_CAPI void U_EXPORT2 umtx_destroy( UMTX *mutex ); +U_CAPI void U_EXPORT2 umtx_unlock (UMutex* mutex); /* * Atomic Increment and Decrement of an int32_t value. diff --git a/icu4c/source/common/uresbund.cpp b/icu4c/source/common/uresbund.cpp index 64498ecbb21..0404e36a821 100644 --- a/icu4c/source/common/uresbund.cpp +++ b/icu4c/source/common/uresbund.cpp @@ -42,7 +42,7 @@ TODO: This cache should probably be removed when the deprecated code is */ static UHashtable *cache = NULL; -static UMTX resbMutex = NULL; +static UMutex resbMutex = U_MUTEX_INITIALIZER; /* INTERNAL: hashes an entry */ static int32_t U_CALLCONV hashEntry(const UHashTok parm) { @@ -260,9 +260,6 @@ static UBool U_CALLCONV ures_cleanup(void) cache = NULL; } } - if (cache == NULL && resbMutex != NULL) { - umtx_destroy(&resbMutex); - } return (cache == NULL); } diff --git a/icu4c/source/common/usprep.cpp b/icu4c/source/common/usprep.cpp index 925ed38b717..93832e96521 100644 --- a/icu4c/source/common/usprep.cpp +++ b/icu4c/source/common/usprep.cpp @@ -43,7 +43,7 @@ Static cache for already opened StringPrep profiles */ static UHashtable *SHARED_DATA_HASHTABLE = NULL; -static UMTX usprepMutex = NULL; +static UMutex usprepMutex = U_MUTEX_INITIALIZER; /* format version of spp file */ //static uint8_t formatVersion[4]={ 0, 0, 0, 0 }; @@ -196,9 +196,6 @@ static UBool U_CALLCONV usprep_cleanup(void){ } } - umtx_destroy(&usprepMutex); /* Don't worry about destroying the mutex even */ - /* if the hash table still exists. The mutex */ - /* will lazily re-init itself if needed. */ return (SHARED_DATA_HASHTABLE == NULL); } U_CDECL_END diff --git a/icu4c/source/i18n/alphaindex.cpp b/icu4c/source/i18n/alphaindex.cpp index cf51a03fe4e..93f1a7174bc 100644 --- a/icu4c/source/i18n/alphaindex.cpp +++ b/icu4c/source/i18n/alphaindex.cpp @@ -653,7 +653,7 @@ const UnicodeString *AlphabeticIndex::EMPTY_STRING; // sufficiently heavy that the cost of the mutex check is not significant. void AlphabeticIndex::staticInit(UErrorCode &status) { - static UMTX IndexCharsInitMutex; + static UMutex IndexCharsInitMutex = U_MUTEX_INITIALIZER; Mutex mutex(&IndexCharsInitMutex); if (indexCharactersAreInitialized || U_FAILURE(status)) { diff --git a/icu4c/source/i18n/astro.cpp b/icu4c/source/i18n/astro.cpp index f4ea55e146a..dfbe9fadc21 100644 --- a/icu4c/source/i18n/astro.cpp +++ b/icu4c/source/i18n/astro.cpp @@ -1,5 +1,5 @@ /************************************************************************ - * Copyright (C) 1996-2011, International Business Machines Corporation + * Copyright (C) 1996-2012, International Business Machines Corporation * and others. All Rights Reserved. ************************************************************************ * 2003-nov-07 srl Port from Java @@ -63,11 +63,10 @@ static inline UBool isINVALID(double d) { return(uprv_isNaN(d)); } -static UMTX ccLock = NULL; +static UMutex ccLock = U_MUTEX_INITIALIZER; U_CDECL_BEGIN static UBool calendar_astro_cleanup(void) { - umtx_destroy(&ccLock); return TRUE; } U_CDECL_END diff --git a/icu4c/source/i18n/chnsecal.cpp b/icu4c/source/i18n/chnsecal.cpp index 2d67c683576..9c9dc79dd24 100644 --- a/icu4c/source/i18n/chnsecal.cpp +++ b/icu4c/source/i18n/chnsecal.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** - * Copyright (C) 2007-2011, International Business Machines Corporation + * Copyright (C) 2007-2012, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -48,7 +48,7 @@ static void debug_chnsecal_msg(const char *pat, ...) // --- The cache -- -static UMTX astroLock = 0; // pod bay door lock +static UMutex astroLock = U_MUTEX_INITIALIZER; // pod bay door lock static icu::CalendarAstronomer *gChineseCalendarAstro = NULL; static icu::CalendarCache *gChineseCalendarWinterSolsticeCache = NULL; static icu::CalendarCache *gChineseCalendarNewYearCache = NULL; @@ -90,7 +90,6 @@ static UBool calendar_chinese_cleanup(void) { delete gChineseCalendarNewYearCache; gChineseCalendarNewYearCache = NULL; } - umtx_destroy(&astroLock); return TRUE; } U_CDECL_END diff --git a/icu4c/source/i18n/colldata.cpp b/icu4c/source/i18n/colldata.cpp index a488ea07726..875aa9da52b 100644 --- a/icu4c/source/i18n/colldata.cpp +++ b/icu4c/source/i18n/colldata.cpp @@ -480,7 +480,7 @@ private: UHashtable *cache; }; -static UMTX lock; +static UMutex lock = U_MUTEX_INITIALIZER; U_CDECL_BEGIN static void U_CALLCONV diff --git a/icu4c/source/i18n/dtfmtsym.cpp b/icu4c/source/i18n/dtfmtsym.cpp index e0a9165d153..77d8d0527f1 100644 --- a/icu4c/source/i18n/dtfmtsym.cpp +++ b/icu4c/source/i18n/dtfmtsym.cpp @@ -177,7 +177,7 @@ static const char gQuartersTag[]="quarters"; static const char gContextTransformsTag[]="contextTransforms"; -static UMTX LOCK; +static UMutex LOCK = U_MUTEX_INITIALIZER; /** * Jitterbug 2974: MSVC has a bug whereby new X[0] behaves badly. diff --git a/icu4c/source/i18n/gender.cpp b/icu4c/source/i18n/gender.cpp index 051c345086b..1e60fcb05f6 100644 --- a/icu4c/source/i18n/gender.cpp +++ b/icu4c/source/i18n/gender.cpp @@ -28,7 +28,7 @@ #include "uhash.h" static UHashtable* gGenderInfoCache = NULL; -static UMTX gGenderMetaLock = NULL; +static UMutex gGenderMetaLock = U_MUTEX_INITIALIZER; static const char* gNeutralStr = "neutral"; static const char* gMailTaintsStr = "maleTaints"; static const char* gMixedNeutralStr = "mixedNeutral"; @@ -44,7 +44,6 @@ enum GenderStyle { U_CDECL_BEGIN static UBool U_CALLCONV gender_cleanup(void) { - umtx_destroy(&gGenderMetaLock); if (gGenderInfoCache != NULL) { uhash_close(gGenderInfoCache); gGenderInfoCache = NULL; diff --git a/icu4c/source/i18n/islamcal.cpp b/icu4c/source/i18n/islamcal.cpp index 968c88ab661..6d553787da3 100644 --- a/icu4c/source/i18n/islamcal.cpp +++ b/icu4c/source/i18n/islamcal.cpp @@ -1,6 +1,6 @@ /* ****************************************************************************** -* Copyright (C) 2003-2011, International Business Machines Corporation +* Copyright (C) 2003-2012, International Business Machines Corporation * and others. All Rights Reserved. ****************************************************************************** * @@ -51,7 +51,7 @@ static void debug_islamcal_msg(const char *pat, ...) // --- The cache -- // cache of months -static UMTX astroLock = 0; // pod bay door lock +static UMutex astroLock = U_MUTEX_INITIALIZER; // pod bay door lock static icu::CalendarCache *gMonthCache = NULL; static icu::CalendarAstronomer *gIslamicCalendarAstro = NULL; @@ -65,7 +65,6 @@ static UBool calendar_islamic_cleanup(void) { delete gIslamicCalendarAstro; gIslamicCalendarAstro = NULL; } - umtx_destroy(&astroLock); return TRUE; } U_CDECL_END diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index 161559ace00..6b4fd06d9c1 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -139,7 +139,7 @@ static const char *gFormatKeys[UNUM_FORMAT_STYLE_COUNT] = { // Static hashtable cache of NumberingSystem objects used by NumberFormat static UHashtable * NumberingSystem_cache = NULL; -static UMTX nscacheMutex = NULL; +static UMutex nscacheMutex = U_MUTEX_INITIALIZER; #if !UCONFIG_NO_SERVICE static icu::ICULocaleService* gService = NULL; diff --git a/icu4c/source/i18n/plurrule.cpp b/icu4c/source/i18n/plurrule.cpp index 2f80a54ec43..2ceb511f488 100644 --- a/icu4c/source/i18n/plurrule.cpp +++ b/icu4c/source/i18n/plurrule.cpp @@ -29,7 +29,7 @@ U_NAMESPACE_BEGIN // shared by all instances when lazy-initializing samples -static UMTX pluralMutex; +static UMutex pluralMutex = U_MUTEX_INITIALIZER; #define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0]) diff --git a/icu4c/source/i18n/rbt.cpp b/icu4c/source/i18n/rbt.cpp index 6041a9245e6..b987ade2c72 100644 --- a/icu4c/source/i18n/rbt.cpp +++ b/icu4c/source/i18n/rbt.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (C) 1999-2008, International Business Machines +* Copyright (C) 1999-2012, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** * Date Name Description @@ -24,7 +24,7 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTransliterator) -static UMTX transliteratorDataMutex = NULL; +static UMutex transliteratorDataMutex = U_MUTEX_INITIALIZER; static Replaceable *gLockedText = NULL; void RuleBasedTransliterator::_construct(const UnicodeString& rules, diff --git a/icu4c/source/i18n/smpdtfmt.cpp b/icu4c/source/i18n/smpdtfmt.cpp index f5daecf4778..6af257d64d2 100644 --- a/icu4c/source/i18n/smpdtfmt.cpp +++ b/icu4c/source/i18n/smpdtfmt.cpp @@ -209,8 +209,7 @@ static const int32_t gFieldRangeBias[] = { static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000; static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000; - -static UMTX LOCK; +static UMutex LOCK = U_MUTEX_INITIALIZER; UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat) diff --git a/icu4c/source/i18n/timezone.cpp b/icu4c/source/i18n/timezone.cpp index 7c85b8ed9db..ca98ef30bd0 100644 --- a/icu4c/source/i18n/timezone.cpp +++ b/icu4c/source/i18n/timezone.cpp @@ -109,8 +109,8 @@ static const UChar UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x static const int32_t GMT_ID_LENGTH = 3; static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11; -static UMTX LOCK; -static UMTX TZSET_LOCK; +static UMutex LOCK = U_MUTEX_INITIALIZER; +static UMutex TZSET_LOCK = U_MUTEX_INITIALIZER; static icu::TimeZone* DEFAULT_ZONE = NULL; static icu::TimeZone* _GMT = NULL; static icu::TimeZone* _UNKNOWN_ZONE = NULL; @@ -153,15 +153,6 @@ static UBool U_CALLCONV timeZone_cleanup(void) uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES); MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0; - if (LOCK) { - umtx_destroy(&LOCK); - LOCK = NULL; - } - if (TZSET_LOCK) { - umtx_destroy(&TZSET_LOCK); - TZSET_LOCK = NULL; - } - return TRUE; } U_CDECL_END diff --git a/icu4c/source/i18n/translit.cpp b/icu4c/source/i18n/translit.cpp index e82cd59b0ab..bb9ba9b1903 100644 --- a/icu4c/source/i18n/translit.cpp +++ b/icu4c/source/i18n/translit.cpp @@ -89,7 +89,7 @@ static const char RB_RULE_BASED_IDS[] = "RuleBasedTransliteratorIDs"; /** * The mutex controlling access to registry object. */ -static UMTX registryMutex = 0; +static UMutex registryMutex = U_MUTEX_INITIALIZER; /** * System transliterator registry; non-null when initialized. @@ -1633,7 +1633,6 @@ U_CFUNC UBool utrans_transliterator_cleanup(void) { delete registry; registry = NULL; } - umtx_destroy(®istryMutex); return TRUE; } diff --git a/icu4c/source/i18n/tridpars.cpp b/icu4c/source/i18n/tridpars.cpp index b195e5234ed..37a7adeff15 100644 --- a/icu4c/source/i18n/tridpars.cpp +++ b/icu4c/source/i18n/tridpars.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** -* Copyright (c) 2002-2011, International Business Machines Corporation +* Copyright (c) 2002-2012, International Business Machines Corporation * and others. All Rights Reserved. ********************************************************************** * Date Name Description @@ -45,7 +45,7 @@ static Hashtable* SPECIAL_INVERSES = NULL; /** * The mutex controlling access to SPECIAL_INVERSES */ -static UMTX LOCK = 0; +static UMutex LOCK = U_MUTEX_INITIALIZER; TransliteratorIDParser::Specs::Specs(const UnicodeString& s, const UnicodeString& t, const UnicodeString& v, UBool sawS, @@ -928,7 +928,6 @@ void TransliteratorIDParser::cleanup() { delete SPECIAL_INVERSES; SPECIAL_INVERSES = NULL; } - umtx_destroy(&LOCK); } U_NAMESPACE_END diff --git a/icu4c/source/i18n/tzfmt.cpp b/icu4c/source/i18n/tzfmt.cpp index a8617455924..2c694760b9d 100644 --- a/icu4c/source/i18n/tzfmt.cpp +++ b/icu4c/source/i18n/tzfmt.cpp @@ -243,7 +243,7 @@ U_CDECL_END UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TimeZoneFormat) TimeZoneFormat::TimeZoneFormat(const Locale& locale, UErrorCode& status) -: fLock(NULL),fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL), fDefParseOptionFlags(0) { +: fLocale(locale), fTimeZoneNames(NULL), fTimeZoneGenericNames(NULL), fDefParseOptionFlags(0) { for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS; i++) { fGMTOffsetPatternItems[i] = NULL; @@ -346,7 +346,6 @@ TimeZoneFormat::~TimeZoneFormat() { for (int32_t i = 0; i <= UTZFMT_PAT_NEGATIVE_HMS; i++) { delete fGMTOffsetPatternItems[i]; } - umtx_destroy(&fLock); } TimeZoneFormat& @@ -1005,6 +1004,8 @@ TimeZoneFormat::formatSpecific(const TimeZone& tz, UTimeZoneNameType stdType, UT return name; } +static UMutex gLock = U_MUTEX_INITIALIZER; + const TimeZoneGenericNames* TimeZoneFormat::getTimeZoneGenericNames(UErrorCode& status) const { if (U_FAILURE(status)) { @@ -1015,13 +1016,13 @@ TimeZoneFormat::getTimeZoneGenericNames(UErrorCode& status) const { UMTX_CHECK(&gZoneMetaLock, (fTimeZoneGenericNames == NULL), create); if (create) { TimeZoneFormat *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { if (fTimeZoneGenericNames == NULL) { nonConstThis->fTimeZoneGenericNames = TimeZoneGenericNames::createInstance(fLocale, status); } } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); } return fTimeZoneGenericNames; diff --git a/icu4c/source/i18n/tzgnames.cpp b/icu4c/source/i18n/tzgnames.cpp index 0b1d4b4ef4f..15fbf950a2c 100644 --- a/icu4c/source/i18n/tzgnames.cpp +++ b/icu4c/source/i18n/tzgnames.cpp @@ -267,6 +267,8 @@ GNameSearchHandler::getMatches(int32_t& maxMatchLen) { return results; } +static UMutex gLock = U_MUTEX_INITIALIZER; + class TZGNCore : public UMemory { public: TZGNCore(const Locale& locale, UErrorCode& status); @@ -282,7 +284,6 @@ public: private: Locale fLocale; - UMTX fLock; const TimeZoneNames* fTimeZoneNames; UHashtable* fLocationNamesMap; UHashtable* fPartialLocationNamesMap; @@ -330,7 +331,6 @@ private: // --------------------------------------------------- TZGNCore::TZGNCore(const Locale& locale, UErrorCode& status) : fLocale(locale), - fLock(NULL), fTimeZoneNames(NULL), fLocationNamesMap(NULL), fPartialLocationNamesMap(NULL), @@ -345,7 +345,6 @@ TZGNCore::TZGNCore(const Locale& locale, UErrorCode& status) TZGNCore::~TZGNCore() { cleanup(); - umtx_destroy(&fLock); } void @@ -504,11 +503,11 @@ TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeStri const UChar *locname = NULL; TZGNCore *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { locname = nonConstThis->getGenericLocationName(tzCanonicalID); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (locname == NULL) { name.setToBogus(); @@ -769,11 +768,11 @@ TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID, const UChar *uplname = NULL; TZGNCore *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (uplname == NULL) { name.setToBogus(); @@ -1042,11 +1041,11 @@ TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UE TZGNCore *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (U_FAILURE(status)) { return NULL; @@ -1073,7 +1072,7 @@ TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UE // All names are not yet loaded into the local trie. // Load all available names into the trie. This could be very heavy. - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { if (!fGNamesTrieFullyLoaded) { StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status); @@ -1095,18 +1094,18 @@ TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UE } } } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (U_FAILURE(status)) { return NULL; } - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { // now try it again fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); results = handler.getMatches(maxLen); if (results != NULL && maxLen > 0) { @@ -1147,7 +1146,7 @@ typedef struct TZGNCoreRef { } TZGNCoreRef; // TZGNCore object cache handling -static UMTX gTZGNLock = NULL; +static UMutex gTZGNLock = U_MUTEX_INITIALIZER; static UHashtable *gTZGNCoreCache = NULL; static UBool gTZGNCoreCacheInitialized = FALSE; @@ -1170,8 +1169,6 @@ U_CDECL_BEGIN */ static UBool U_CALLCONV tzgnCore_cleanup(void) { - umtx_destroy(&gTZGNLock); - if (gTZGNCoreCache != NULL) { uhash_close(gTZGNCoreCache); gTZGNCoreCache = NULL; diff --git a/icu4c/source/i18n/tznames.cpp b/icu4c/source/i18n/tznames.cpp index 55ee4168b77..b7fc35c20b0 100644 --- a/icu4c/source/i18n/tznames.cpp +++ b/icu4c/source/i18n/tznames.cpp @@ -33,7 +33,7 @@ static const UChar gRiyadh8[] = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, static const int32_t gRiyadh8Len = 7; // TimeZoneNames object cache handling -static UMTX gTimeZoneNamesLock = NULL; +static UMutex gTimeZoneNamesLock = U_MUTEX_INITIALIZER; static UHashtable *gTimeZoneNamesCache = NULL; static UBool gTimeZoneNamesCacheInitialized = FALSE; @@ -62,8 +62,6 @@ U_CDECL_BEGIN */ static UBool U_CALLCONV timeZoneNames_cleanup(void) { - umtx_destroy(&gTimeZoneNamesLock); - if (gTimeZoneNamesCache != NULL) { uhash_close(gTimeZoneNamesCache); gTimeZoneNamesCache = NULL; diff --git a/icu4c/source/i18n/tznames_impl.cpp b/icu4c/source/i18n/tznames_impl.cpp index a699ec8c0b4..876411bc599 100644 --- a/icu4c/source/i18n/tznames_impl.cpp +++ b/icu4c/source/i18n/tznames_impl.cpp @@ -282,7 +282,7 @@ TextTrieMap::getChildNode(CharacterNode *parent, UChar c) const { } // Mutex for protecting the lazy creation of the Trie node structure on the first call to search(). -static UMTX TextTrieMutex; +static UMutex TextTrieMutex = U_MUTEX_INITIALIZER; // buildTrie() - The Trie node structure is needed. Create it from the data that was // saved at the time the ZoneStringFormatter was created. The Trie is only @@ -837,9 +837,10 @@ deleteZNameInfo(void *obj) { U_CDECL_END +static UMutex gLock = U_MUTEX_INITIALIZER; + TimeZoneNamesImpl::TimeZoneNamesImpl(const Locale& locale, UErrorCode& status) : fLocale(locale), - fLock(NULL), fZoneStrings(NULL), fTZNamesMap(NULL), fMZNamesMap(NULL), @@ -911,7 +912,6 @@ TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID) { TimeZoneNamesImpl::~TimeZoneNamesImpl() { cleanup(); - umtx_destroy(&fLock); } void @@ -1015,11 +1015,11 @@ TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID, ZNames *znames = NULL; TimeZoneNamesImpl *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { znames = nonConstThis->loadMetaZoneNames(mzID); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (znames != NULL) { const UChar* s = znames->getName(type); @@ -1040,11 +1040,11 @@ TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNa TZNames *tznames = NULL; TimeZoneNamesImpl *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { tznames = nonConstThis->loadTimeZoneNames(tzID); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (tznames != NULL) { const UChar *s = tznames->getName(type); @@ -1061,11 +1061,11 @@ TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeStr TZNames *tznames = NULL; TimeZoneNamesImpl *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { tznames = nonConstThis->loadTimeZoneNames(tzID); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (tznames != NULL) { locName = tznames->getLocationName(); @@ -1246,11 +1246,11 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types TimeZoneNamesImpl *nonConstThis = const_cast(this); - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (U_FAILURE(status)) { return NULL; @@ -1266,7 +1266,7 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types delete matches; // All names are not yet loaded into the trie - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { if (!fNamesTrieFullyLoaded) { const UnicodeString *id; @@ -1290,18 +1290,18 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types } } } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); if (U_FAILURE(status)) { return NULL; } - umtx_lock(&nonConstThis->fLock); + umtx_lock(&gLock); { // now try it again fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status); } - umtx_unlock(&nonConstThis->fLock); + umtx_unlock(&gLock); return handler.getMatches(maxLen); } diff --git a/icu4c/source/i18n/tznames_impl.h b/icu4c/source/i18n/tznames_impl.h index 1e64710bebb..c03eb8e6ed4 100644 --- a/icu4c/source/i18n/tznames_impl.h +++ b/icu4c/source/i18n/tznames_impl.h @@ -187,7 +187,6 @@ public: private: Locale fLocale; - UMTX fLock; UResourceBundle* fZoneStrings; diff --git a/icu4c/source/i18n/ucurr.cpp b/icu4c/source/i18n/ucurr.cpp index b86f8e288c6..ed6c53f99fc 100644 --- a/icu4c/source/i18n/ucurr.cpp +++ b/icu4c/source/i18n/ucurr.cpp @@ -102,7 +102,7 @@ static const UChar EUR_STR[] = {0x0045,0x0055,0x0052,0}; static UHashtable* gIsoCodes = NULL; static UBool gIsoCodesInitialized = FALSE; -static UMTX gIsoCodesLock = NULL; +static UMutex gIsoCodesLock = U_MUTEX_INITIALIZER; //------------------------------------------------------------ // Code @@ -113,10 +113,6 @@ static UMTX gIsoCodesLock = NULL; static UBool U_CALLCONV isoCodes_cleanup(void) { - if (gIsoCodesLock != NULL) { - umtx_destroy(&gIsoCodesLock); - } - if (gIsoCodes != NULL) { uhash_close(gIsoCodes); gIsoCodes = NULL; @@ -249,7 +245,7 @@ U_CDECL_END #if !UCONFIG_NO_SERVICE struct CReg; -static UMTX gCRegLock = 0; +static UMutex gCRegLock = U_MUTEX_INITIALIZER; static CReg* gCRegHead = 0; struct CReg : public icu::UMemory { @@ -334,7 +330,6 @@ struct CReg : public icu::UMemory { gCRegHead = gCRegHead->next; delete n; } - umtx_destroy(&gCRegLock); } }; diff --git a/icu4c/source/i18n/unicode/tzfmt.h b/icu4c/source/i18n/unicode/tzfmt.h index 090d8d70ae4..8a68ca19170 100644 --- a/icu4c/source/i18n/unicode/tzfmt.h +++ b/icu4c/source/i18n/unicode/tzfmt.h @@ -141,8 +141,6 @@ typedef enum UTimeZoneFormatParseOption { U_CDECL_END -typedef void *UMTX; - U_NAMESPACE_BEGIN class TimeZoneGenericNames; @@ -528,9 +526,6 @@ protected: TimeZoneFormat(const Locale& locale, UErrorCode& status); private: - /* mutex */ - UMTX fLock; - /* Locale of this object */ Locale fLocale; diff --git a/icu4c/source/i18n/zonemeta.cpp b/icu4c/source/i18n/zonemeta.cpp index e244f9c2f82..932c5ab678c 100644 --- a/icu4c/source/i18n/zonemeta.cpp +++ b/icu4c/source/i18n/zonemeta.cpp @@ -27,7 +27,7 @@ #include "uhash.h" #include "olsontz.h" -static UMTX gZoneMetaLock = NULL; +static UMutex gZoneMetaLock = U_MUTEX_INITIALIZER; // CLDR Canonical ID mapping table static UHashtable *gCanonicalIDCache = NULL; @@ -54,8 +54,6 @@ U_CDECL_BEGIN */ static UBool U_CALLCONV zoneMeta_cleanup(void) { - umtx_destroy(&gZoneMetaLock); - if (gCanonicalIDCache != NULL) { uhash_close(gCanonicalIDCache); gCanonicalIDCache = NULL; diff --git a/icu4c/source/test/intltest/tsmthred.cpp b/icu4c/source/test/intltest/tsmthred.cpp index 2b826058736..fc6a6607ed3 100644 --- a/icu4c/source/test/intltest/tsmthred.cpp +++ b/icu4c/source/test/intltest/tsmthred.cpp @@ -446,8 +446,8 @@ void MultithreadTest::TestArabicShapingThreads() // platform's mutex support is at least superficially there. // //---------------------------------------------------------------------- -static UMTX gTestMutexA = NULL; -static UMTX gTestMutexB = NULL; +static UMutex gTestMutexA = U_MUTEX_INITIALIZER; +static UMutex gTestMutexB = U_MUTEX_INITIALIZER; static int gThreadsStarted = 0; static int gThreadsInMiddle = 0; @@ -550,11 +550,6 @@ void MultithreadTest::TestMutex() } // All threads made it by both mutexes. - // Destroy the test mutexes. - umtx_destroy(&gTestMutexA); - umtx_destroy(&gTestMutexB); - gTestMutexA=NULL; - gTestMutexB=NULL; for (i=0; i