2 ******************************************************************************
4 * Copyright (C) 1997-2003, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 04/02/97 aliu Creation.
15 * 04/07/99 srl updated
16 * 05/13/99 stephen Changed to umutex (from cmutex).
17 * 11/22/99 aliu Make non-global mutex autoinitialize [j151]
18 ******************************************************************************
21 /* Assume POSIX, and modify as necessary below */
27 #if defined(macintosh)
35 /* Check our settings... */
36 #include "unicode/utypes.h"
40 #if defined(POSIX) && (ICU_USE_THREADS==1)
41 /* Usage: uncomment the following, and breakpoint WeAreDeadlocked to
42 find reentrant issues. */
43 /* # define POSIX_DEBUG_REENTRANCY 1 */
44 # include <pthread.h> /* must be first, so that we get the multithread versions of things. */
46 # ifdef POSIX_DEBUG_REENTRANCY
47 pthread_t gLastThread
;
50 U_EXPORT
void WeAreDeadlocked();
52 void WeAreDeadlocked()
54 puts("ARGH!! We're deadlocked.. break on WeAreDeadlocked() next time.");
56 # endif /* POSIX_DEBUG_REENTRANCY */
57 #endif /* POSIX && (ICU_USE_THREADS==1) */
60 # define WIN32_LEAN_AND_MEAN
72 #if (ICU_USE_THREADS == 1)
74 /* the global mutex. Use it proudly and wash it often. */
75 static UMTX gGlobalMutex
= NULL
;
77 static int32_t gRecursionCount
= 0; /* Detect Recursive entries. For debugging only. */
81 static CRITICAL_SECTION gPlatformMutex
;
84 static pthread_mutex_t gPlatformMutex
; /* The global ICU mutex */
85 static pthread_mutex_t gIncDecMutex
; /* For use by atomic inc/dec, on Unixes only */
88 #endif /* ICU_USE_THREADS==1 */
92 U_CAPI UBool U_EXPORT2
93 umtx_isInitialized(UMTX
*mutex
)
95 #if (ICU_USE_THREADS == 1)
98 return (UBool
)(gGlobalMutex
!= NULL
);
102 isInited
= (*mutex
!= NULL
);
107 return TRUE
; /* Since we don't use threads, it's considered initialized. */
108 #endif /* ICU_USE_THREADS==1 */
111 U_CAPI
void U_EXPORT2
112 umtx_lock(UMTX
*mutex
)
114 #if (ICU_USE_THREADS == 1)
117 mutex
= &gGlobalMutex
;
122 /* Lazy init of a non-global mutexes on first lock is NOT safe on processors
123 * that reorder memory operations. */
124 /* U_ASSERT(FALSE); TODO: Turn this back on */
125 if (mutex
!= &gGlobalMutex
) {
128 umtx_init(NULL
); /* initialize the global mutex - only get
129 here if C++ static init is NOT working,
130 and u_init() hasn't been called.
132 Not thread-safe if this call is contended! */
138 EnterCriticalSection((CRITICAL_SECTION
*) *mutex
);
140 if (mutex
== &gGlobalMutex
) {
142 U_ASSERT(gRecursionCount
== 1);
148 # ifdef POSIX_DEBUG_REENTRANCY
149 if (gInMutex
== TRUE
&& mutex
== &gGlobalMutex
) /* in the mutex -- possible deadlock*/
150 if(pthread_equal(gLastThread
, pthread_self()))
153 pthread_mutex_lock((pthread_mutex_t
*) *mutex
);
155 # ifdef POSIX_DEBUG_REENTRANCY
156 if (mutex
== &gGlobalMutex
) {
157 gLastThread
= pthread_self();
162 #endif /* ICU_USE_THREADS==1 */
165 U_CAPI
void U_EXPORT2
166 umtx_unlock(UMTX
* mutex
)
168 #if (ICU_USE_THREADS==1)
171 mutex
= &gGlobalMutex
;
176 return; /* jitterbug 135, fix for multiprocessor machines */
181 if (mutex
== &gGlobalMutex
) {
183 U_ASSERT(gRecursionCount
== 0);
186 LeaveCriticalSection((CRITICAL_SECTION
*)*mutex
);
188 #elif defined (POSIX)
189 pthread_mutex_unlock((pthread_mutex_t
*)*mutex
);
191 #ifdef POSIX_DEBUG_REENTRANCY
192 if (mutex
== &gGlobalMutex
) {
198 #endif /* ICU_USE_THREADS == 1 */
204 * umtx_raw_init Do the platform specific mutex allocation and initialization
206 #if (ICU_USE_THREADS == 1)
207 static UMTX
umtx_raw_init(void *mem
) {
210 mem
= uprv_malloc(sizeof(CRITICAL_SECTION
));
211 if (mem
== NULL
) {return NULL
;}
213 InitializeCriticalSection((CRITICAL_SECTION
*)mem
);
214 #elif defined( POSIX )
216 mem
= uprv_malloc(sizeof(pthread_mutex_t
));
217 if (mem
== NULL
) {return NULL
;}
219 # if defined (HPUX_CMA)
220 pthread_mutex_init((pthread_mutex_t
*)mem
, pthread_mutexattr_default
);
222 pthread_mutex_init((pthread_mutex_t
*)mem
, NULL
);
227 #endif /* ICU_USE_THREADS */
230 U_CAPI
void U_EXPORT2
231 umtx_init(UMTX
*mutex
)
233 #if (ICU_USE_THREADS == 1)
235 if (mutex
== NULL
) /* initialize the global mutex */
237 /* Note: The initialization of the global mutex is NOT thread safe. */
238 if (gGlobalMutex
!= NULL
) {
241 gGlobalMutex
= umtx_raw_init(&gPlatformMutex
);
243 # ifdef POSIX_DEBUG_REENTRANCY
251 umtx_raw_init(&gIncDecMutex
);
255 /* Not the global mutex.
256 * Thread safe initialization, using the global mutex.
262 isInitialized
= (*mutex
!= NULL
);
268 tMutex
= umtx_raw_init(NULL
);
271 if (*mutex
== NULL
) {
277 umtx_destroy(&tMutex
); /* NOP if (tmutex == NULL) */
279 #endif /* ICU_USE_THREADS==1 */
282 U_CAPI
void U_EXPORT2
283 umtx_destroy(UMTX
*mutex
) {
284 #if (ICU_USE_THREADS == 1)
285 if (mutex
== NULL
) /* destroy the global mutex */
287 mutex
= &gGlobalMutex
;
290 if (*mutex
== NULL
) /* someone already did it. */
294 DeleteCriticalSection((CRITICAL_SECTION
*)*mutex
);
296 #elif defined (POSIX)
297 pthread_mutex_destroy((pthread_mutex_t
*)*mutex
);
301 if (*mutex
!= gGlobalMutex
)
307 #endif /* ICU_USE_THREADS==1 */
311 #if (ICU_USE_THREADS == 1)
321 * Win32 - use the Windows API functions for atomic increment and decrement.
323 U_CAPI
int32_t U_EXPORT2
324 umtx_atomic_inc(int32_t *p
)
326 return InterlockedIncrement(p
);
329 U_CAPI
int32_t U_EXPORT2
330 umtx_atomic_dec(int32_t *p
)
332 return InterlockedDecrement(p
);
335 #elif defined (POSIX)
337 * POSIX platforms without specific atomic operations. Use a posix mutex
338 * to protect the increment and decrement.
339 * The IncDecMutex is in static storage so we don't have to come back and delete it
340 * when the process exits.
343 U_CAPI
int32_t U_EXPORT2
344 umtx_atomic_inc(int32_t *p
)
348 pthread_mutex_lock(&gIncDecMutex
);
350 pthread_mutex_unlock(&gIncDecMutex
);
355 U_CAPI
int32_t U_EXPORT2
356 umtx_atomic_dec(int32_t *p
)
360 pthread_mutex_lock(&gIncDecMutex
);
362 pthread_mutex_unlock(&gIncDecMutex
);
369 /* No recognized platform. */
370 #error No atomic increment and decrement defined for this platform. \
371 Either use the --disable-threads configure option, or define those functions in this file.
373 #endif /* Platform selection for atomic_inc and dec. */
376 #else /* (ICU_USE_THREADS == 0) */
378 /* Threads disabled here */
380 U_CAPI
int32_t U_EXPORT2
381 umtx_atomic_inc(int32_t *p
) {
385 U_CAPI
int32_t U_EXPORT2
386 umtx_atomic_dec(int32_t *p
) {
390 #endif /* (ICU_USE_THREADS == 1) */