scuffed-code/icu4c/source/common/umutex.c

336 lines
6.8 KiB
C
Raw Normal View History

1999-08-16 21:50:52 +00:00
/*
******************************************************************************
*
* Copyright (C) 1997-2001, International Business Machines
* Corporation and others. All Rights Reserved.
*
******************************************************************************
1999-08-16 21:50:52 +00:00
*
* File CMUTEX.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]
******************************************************************************
1999-08-16 21:50:52 +00:00
*/
/* Assume POSIX, and modify as necessary below */
#define POSIX
#if defined(_WIN32)
#undef POSIX
#endif
#if defined(macintosh)
#undef POSIX
#endif
#if defined(OS2)
#undef POSIX
#endif
/* Check our settings... */
#include "unicode/utypes.h"
#if defined(POSIX) && (ICU_USE_THREADS==1)
1999-08-16 21:50:52 +00:00
/* Usage: uncomment the following, and breakpoint WeAreDeadlocked to
find reentrant issues. */
/* # define POSIX_DEBUG_REENTRANCY 1 */
# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
# ifdef POSIX_DEBUG_REENTRANCY
pthread_t gLastThread;
UBool gInMutex;
1999-08-16 21:50:52 +00:00
U_EXPORT void WeAreDeadlocked();
void WeAreDeadlocked()
{
puts("ARGH!! We're deadlocked.. break on WeAreDeadlocked() next time.");
}
# endif /* POSIX_DEBUG_REENTRANCY */
#endif /* POSIX && (ICU_USE_THREADS==1) */
1999-08-16 21:50:52 +00:00
#ifdef WIN32
# define WIN32_LEAN_AND_MEAN
# define NOGDI
# define NOUSER
# define NOSERVICE
# define NOIME
# define NOMCX
# include <windows.h>
1999-08-16 21:50:52 +00:00
#endif
#include "umutex.h"
#include "cmemory.h"
1999-08-16 21:50:52 +00:00
#if (ICU_USE_THREADS == 1)
1999-08-16 21:50:52 +00:00
/* the global mutex. Use it proudly and wash it often. */
static UMTX gGlobalMutex = NULL;
1999-08-16 21:50:52 +00:00
#if defined(WIN32)
static CRITICAL_SECTION gPlatformMutex;
#elif defined(POSIX)
static pthread_mutex_t gPlatformMutex;
#endif
#endif /* ICU_USE_THREADS==1 */
U_CAPI void U_EXPORT2
umtx_lock(UMTX *mutex)
1999-08-16 21:50:52 +00:00
{
#if (ICU_USE_THREADS == 1)
if (mutex == NULL)
1999-08-16 21:50:52 +00:00
{
mutex = &gGlobalMutex;
}
1999-08-16 21:50:52 +00:00
if (*mutex == NULL)
{
if (mutex != &gGlobalMutex) {umtx_lock(NULL);};
if (*mutex == NULL) {
umtx_init(mutex);
}
if (mutex != &gGlobalMutex) {umtx_unlock(NULL);};
1999-08-16 21:50:52 +00:00
}
#if defined(WIN32)
1999-08-16 21:50:52 +00:00
EnterCriticalSection((CRITICAL_SECTION*) *mutex);
#elif defined(POSIX)
# ifdef POSIX_DEBUG_REENTRANCY
if (gInMutex == TRUE && mutex == &gGlobalMutex) /* in the mutex -- possible deadlock*/
if(pthread_equal(gLastThread, pthread_self()))
WeAreDeadlocked();
1999-08-16 21:50:52 +00:00
# endif
pthread_mutex_lock((pthread_mutex_t*) *mutex);
# ifdef POSIX_DEBUG_REENTRANCY
if (mutex == &gGlobalMutex) {
gLastThread = pthread_self();
gInMutex = TRUE;
}
1999-08-16 21:50:52 +00:00
# endif
#endif
#endif /* ICU_USE_THREADS==1 */
1999-08-16 21:50:52 +00:00
}
U_CAPI void U_EXPORT2
umtx_unlock(UMTX* mutex)
1999-08-16 21:50:52 +00:00
{
#if (ICU_USE_THREADS==1)
if(mutex == NULL)
1999-08-16 21:50:52 +00:00
{
mutex = &gGlobalMutex;
1999-08-16 21:50:52 +00:00
}
if(*mutex == NULL)
{
return; /* jitterbug 135, fix for multiprocessor machines */
}
1999-08-16 21:50:52 +00:00
#if defined (WIN32)
1999-08-16 21:50:52 +00:00
LeaveCriticalSection((CRITICAL_SECTION*)*mutex);
#elif defined (POSIX)
1999-08-16 21:50:52 +00:00
pthread_mutex_unlock((pthread_mutex_t*)*mutex);
1999-08-16 21:50:52 +00:00
#ifdef POSIX_DEBUG_REENTRANCY
if (mutex == &gGlobalMutex) {
gInMutex = FALSE;
}
1999-08-16 21:50:52 +00:00
#endif
#endif
#endif /* ICU_USE_THREADS == 1 */
1999-08-16 21:50:52 +00:00
}
U_CAPI void U_EXPORT2
umtx_init(UMTX *mutex)
1999-08-16 21:50:52 +00:00
{
#if (ICU_USE_THREADS == 1)
1999-08-16 21:50:52 +00:00
if (mutex == NULL) /* initialize the global mutex */
1999-08-16 21:50:52 +00:00
{
mutex = &gGlobalMutex;
1999-08-16 21:50:52 +00:00
}
if (*mutex != NULL) /* someone already did it. */
return;
1999-08-16 21:50:52 +00:00
if (*mutex == gGlobalMutex)
{
*mutex = &gPlatformMutex;
}
else
{
#if defined (WIN32)
*mutex = uprv_malloc(sizeof(CRITICAL_SECTION));
1999-08-16 21:50:52 +00:00
#elif defined( POSIX )
*mutex = uprv_malloc(sizeof(pthread_mutex_t));
#endif
}
1999-08-16 21:50:52 +00:00
#if defined (WIN32)
InitializeCriticalSection((CRITICAL_SECTION*)*mutex);
1999-08-16 21:50:52 +00:00
#elif defined (POSIX)
# if defined (HPUX_CMA)
1999-08-16 21:50:52 +00:00
pthread_mutex_init((pthread_mutex_t*)*mutex, pthread_mutexattr_default);
# else
pthread_mutex_init((pthread_mutex_t*)*mutex, NULL);
# endif
1999-08-16 21:50:52 +00:00
# ifdef POSIX_DEBUG_REENTRANCY
gInMutex = FALSE;
# endif
#endif
#endif /* ICU_USE_THREADS==1 */
1999-08-16 21:50:52 +00:00
}
U_CAPI void U_EXPORT2
umtx_destroy(UMTX *mutex) {
#if (ICU_USE_THREADS == 1)
if (mutex == NULL) /* initialize the global mutex */
{
mutex = &gGlobalMutex;
}
1999-08-16 21:50:52 +00:00
if (*mutex == NULL) /* someone already did it. */
return;
1999-08-16 21:50:52 +00:00
#if defined (WIN32)
DeleteCriticalSection((CRITICAL_SECTION*)*mutex);
1999-08-16 21:50:52 +00:00
#elif defined (POSIX)
pthread_mutex_destroy((pthread_mutex_t*)*mutex);
1999-08-16 21:50:52 +00:00
#endif
1999-08-16 21:50:52 +00:00
if (*mutex != gGlobalMutex)
{
uprv_free(*mutex);
}
1999-08-16 21:50:52 +00:00
*mutex = NULL;
#endif /* ICU_USE_THREADS==1 */
}
#if (ICU_USE_THREADS == 1)
//
// umtx_atomic_inc
// umtx_atomic_dec
//
#if defined (WIN32)
//
// Win32 - use the Windows API functions for atomic increment and decrement.
//
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)
//
// POSIX platforms without specific atomic operations. Use a posix mutex
// to protect the increment and decrement.
// Put the mutex in static storage so we don't have to come back and delete it
// when the process exits.
//
static pthread_mutex_t gIncDecMutex;
static UBool gIncDecMutexInitialized = FALSE;
U_CAPI int32_t U_EXPORT2
umtx_atomic_inc(int32_t *p)
{
int32_t retVal;
if (gIncDecMutexInitialized == FALSE) {
umtx_lock(NULL);
if (gIncDecMutexInitialized == FALSE) {
# if defined (HPUX_CMA)
pthread_mutex_init((pthread_mutex_t*)&gIncDecMutex, pthread_mutexattr_default);
# else
pthread_mutex_init((pthread_mutex_t*)&gIncDecMutex, NULL);
gIncDecMutexInitialized = TRUE;
}
# endif
umtx_unlock(NULL);
}
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;
}
// TODO: pthread_mutex_destroy() when the time comes.
#else
// No recognized platform.
#warning No atomic increment and decrement defined for this platform.
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 // Platform selection for atomic_inc and dec.
#elif // (ICU_USE_THREADS == 1)
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 // (ICU_USE_THREADS == 1)