mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-06 14:05:32 +00:00
ICU-9461 Mutex Implementation Rework, merge from devel branch.
X-SVN-Rev: 32530
This commit is contained in:
parent
a2eca4547b
commit
803ac8f33c
44 changed files with 652 additions and 766 deletions
|
@ -286,7 +286,7 @@
|
|||
<DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</DisableLanguageExtensions>
|
||||
</ClCompile>
|
||||
<ClCompile Include="umath.c" />
|
||||
<ClCompile Include="umutex.c">
|
||||
<ClCompile Include="umutex.cpp">
|
||||
<DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</DisableLanguageExtensions>
|
||||
<DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</DisableLanguageExtensions>
|
||||
<DisableLanguageExtensions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</DisableLanguageExtensions>
|
||||
|
|
|
@ -163,7 +163,7 @@
|
|||
<ClCompile Include="umath.c">
|
||||
<Filter>configuration</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="umutex.c">
|
||||
<ClCompile Include="umutex.cpp">
|
||||
<Filter>configuration</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="utrace.c">
|
||||
|
|
|
@ -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}"
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "icuplugimp.h"
|
||||
#include "ucln.h"
|
||||
#include "ucnv_io.h"
|
||||
#include "umutex.h"
|
||||
#include "utracimp.h"
|
||||
|
||||
static void U_CALLCONV
|
||||
|
|
|
@ -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 <pthread.h> /* 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 <windows.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
483
icu4c/source/common/umutex.cpp
Normal file
483
icu4c/source/common/umutex.cpp
Normal file
|
@ -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 <pthread.h> /* 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 <windows.h>
|
||||
#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<UMutex *>(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;
|
||||
}
|
|
@ -22,10 +22,31 @@
|
|||
#include "unicode/uclean.h"
|
||||
#include "putilimp.h"
|
||||
|
||||
/* For _ReadWriteBarrier(). */
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1500
|
||||
# include <intrin.h>
|
||||
#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 <windows.h>
|
||||
#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 <pthread.h>
|
||||
|
||||
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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -480,7 +480,7 @@ private:
|
|||
|
||||
UHashtable *cache;
|
||||
};
|
||||
static UMTX lock;
|
||||
static UMutex lock = U_MUTEX_INITIALIZER;
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static void U_CALLCONV
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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])
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<TimeZoneFormat *>(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;
|
||||
|
|
|
@ -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<TZGNCore *>(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<TZGNCore *>(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<TZGNCore *>(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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<TimeZoneNamesImpl *>(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<TimeZoneNamesImpl *>(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<TimeZoneNamesImpl *>(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<TimeZoneNamesImpl *>(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);
|
||||
}
|
||||
|
|
|
@ -187,7 +187,6 @@ public:
|
|||
private:
|
||||
|
||||
Locale fLocale;
|
||||
UMTX fLock;
|
||||
|
||||
UResourceBundle* fZoneStrings;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<TESTMUTEX_THREAD_COUNT; i++) {
|
||||
delete threads[i];
|
||||
|
|
Loading…
Add table
Reference in a new issue