#define POSIX
#if defined(_WIN32)
#undef POSIX
#endif
#if defined(macintosh)
#undef POSIX
#endif
#if defined(OS2)
#undef POSIX
#endif
#include "unicode/utypes.h"
#include "uassert.h"
#if defined(POSIX) && (ICU_USE_THREADS==1)
# include <pthread.h>
# ifdef POSIX_DEBUG_REENTRANCY
pthread_t gLastThread;
UBool gInMutex;
U_EXPORT void WeAreDeadlocked();
void WeAreDeadlocked()
{
puts("ARGH!! We're deadlocked.. break on WeAreDeadlocked() next time.");
}
# endif
#endif
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# define NOGDI
# define NOUSER
# define NOSERVICE
# define NOIME
# define NOMCX
# include <windows.h>
#endif
#include "umutex.h"
#include "cmemory.h"
#if (ICU_USE_THREADS == 1)
static UMTX gGlobalMutex = NULL;
# ifdef _DEBUG
static int32_t gRecursionCount = 0;
# endif
#if defined(WIN32)
static CRITICAL_SECTION gPlatformMutex;
#elif defined(POSIX)
static pthread_mutex_t gPlatformMutex;
static pthread_mutex_t gIncDecMutex;
#endif
#endif
U_CAPI UBool U_EXPORT2
umtx_isInitialized(UMTX *mutex)
{
#if (ICU_USE_THREADS == 1)
if (mutex == NULL)
{
return (UBool)(gGlobalMutex != NULL);
} else {
UBool isInited;
umtx_lock(NULL);
isInited = (*mutex != NULL);
umtx_unlock(NULL);
return isInited;
}
#else
return TRUE;
#endif
}
U_CAPI void U_EXPORT2
umtx_lock(UMTX *mutex)
{
#if (ICU_USE_THREADS == 1)
if (mutex == NULL)
{
mutex = &gGlobalMutex;
}
if (*mutex == NULL)
{
if (mutex != &gGlobalMutex) {
umtx_init(mutex);
} else {
umtx_init(NULL);
}
}
#if defined(WIN32)
EnterCriticalSection((CRITICAL_SECTION*) *mutex);
#ifdef _DEBUG
if (mutex == &gGlobalMutex) {
gRecursionCount++;
U_ASSERT(gRecursionCount == 1);
}
#endif
#elif defined(POSIX)
# ifdef POSIX_DEBUG_REENTRANCY
if (gInMutex == TRUE && mutex == &gGlobalMutex)
if(pthread_equal(gLastThread, pthread_self()))
WeAreDeadlocked();
# endif
pthread_mutex_lock((pthread_mutex_t*) *mutex);
# ifdef POSIX_DEBUG_REENTRANCY
if (mutex == &gGlobalMutex) {
gLastThread = pthread_self();
gInMutex = TRUE;
}
# endif
#endif
#endif
}
U_CAPI void U_EXPORT2
umtx_unlock(UMTX* mutex)
{
#if (ICU_USE_THREADS==1)
if(mutex == NULL)
{
mutex = &gGlobalMutex;
}
if(*mutex == NULL)
{
return;
}
#if defined (WIN32)
#ifdef _DEBUG
if (mutex == &gGlobalMutex) {
gRecursionCount--;
U_ASSERT(gRecursionCount == 0);
}
#endif
LeaveCriticalSection((CRITICAL_SECTION*)*mutex);
#elif defined (POSIX)
pthread_mutex_unlock((pthread_mutex_t*)*mutex);
#ifdef POSIX_DEBUG_REENTRANCY
if (mutex == &gGlobalMutex) {
gInMutex = FALSE;
}
#endif
#endif
#endif
}
#if (ICU_USE_THREADS == 1)
static UMTX umtx_raw_init(void *mem) {
#if defined (WIN32)
if (mem == NULL) {
mem = uprv_malloc(sizeof(CRITICAL_SECTION));
if (mem == NULL) {return NULL;}
}
InitializeCriticalSection((CRITICAL_SECTION*)mem);
#elif defined( POSIX )
if (mem == NULL) {
mem = uprv_malloc(sizeof(pthread_mutex_t));
if (mem == NULL) {return NULL;}
}
# if defined (HPUX_CMA)
pthread_mutex_init((pthread_mutex_t*)mem, pthread_mutexattr_default);
# else
pthread_mutex_init((pthread_mutex_t*)mem, NULL);
# endif
#endif
return (UMTX *)mem;
}
#endif
U_CAPI void U_EXPORT2
umtx_init(UMTX *mutex)
{
#if (ICU_USE_THREADS == 1)
if (mutex == NULL)
{
if (gGlobalMutex != NULL) {
return;
}
gGlobalMutex = umtx_raw_init(&gPlatformMutex);
# ifdef POSIX_DEBUG_REENTRANCY
gInMutex = FALSE;
# endif
#ifdef _DEBUG
gRecursionCount = 0;
#endif
#ifdef POSIX
umtx_raw_init(&gIncDecMutex);
#endif
} else {
UBool isInitialized;
UMTX tMutex = NULL;
umtx_lock(NULL);
isInitialized = (*mutex != NULL);
umtx_unlock(NULL);
if (isInitialized) {
return;
}
tMutex = umtx_raw_init(NULL);
umtx_lock(NULL);
if (*mutex == NULL) {
*mutex = tMutex;
tMutex = NULL;
}
umtx_unlock(NULL);
umtx_destroy(&tMutex);
}
#endif
}
U_CAPI void U_EXPORT2
umtx_destroy(UMTX *mutex) {
#if (ICU_USE_THREADS == 1)
if (mutex == NULL)
{
mutex = &gGlobalMutex;
}
if (*mutex == NULL)
return;
#if defined (WIN32)
DeleteCriticalSection((CRITICAL_SECTION*)*mutex);
#elif defined (POSIX)
pthread_mutex_destroy((pthread_mutex_t*)*mutex);
#endif
if (*mutex != gGlobalMutex)
{
uprv_free(*mutex);
}
*mutex = NULL;
#endif
}
#if (ICU_USE_THREADS == 1)
#if defined (WIN32)
U_CAPI int32_t U_EXPORT2
umtx_atomic_inc(int32_t *p)
{
return InterlockedIncrement(p);
}
U_CAPI int32_t U_EXPORT2
umtx_atomic_dec(int32_t *p)
{
return InterlockedDecrement(p);
}
#elif defined (POSIX)
U_CAPI int32_t U_EXPORT2
umtx_atomic_inc(int32_t *p)
{
int32_t retVal;
pthread_mutex_lock(&gIncDecMutex);
retVal = ++(*p);
pthread_mutex_unlock(&gIncDecMutex);
return retVal;
}
U_CAPI int32_t U_EXPORT2
umtx_atomic_dec(int32_t *p)
{
int32_t retVal;
pthread_mutex_lock(&gIncDecMutex);
retVal = --(*p);
pthread_mutex_unlock(&gIncDecMutex);
return retVal;
}
#else
#error No atomic increment and decrement defined for this platform. \
Either use the --disable-threads configure option, or define those functions in this file.
#endif
#else
U_CAPI int32_t U_EXPORT2
umtx_atomic_inc(int32_t *p) {
return ++(*p);
}
U_CAPI int32_t U_EXPORT2
umtx_atomic_dec(int32_t *p) {
return --(*p);
}
#endif