2 ******************************************************************************
4 * Copyright (C) 1997-2004, 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 #include "unicode/utypes.h"
40 #if defined(POSIX) && (ICU_USE_THREADS==1)
41 # include <pthread.h> /* must be first, so that we get the multithread versions of things. */
43 #endif /* POSIX && (ICU_USE_THREADS==1) */
46 # define WIN32_LEAN_AND_MEAN
59 * A note on ICU Mutex Initialization and ICU startup:
61 * ICU mutexes, as used through the rest of the ICU code, are self-initializing.
62 * To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init
63 * of other ICU mutexes. For the global mutex itself, we need some other mechanism
64 * to safely initialize it on first use. This becomes important if two or more
65 * threads were more or less simultaenously the first to use ICU in a process, and
66 * were racing into the mutex initialization code.
68 * The solution for the global mutex init is platform dependent.
69 * On POSIX systems, C-style init can be used on a mutex, with the
70 * macro PTHREAD_MUTEX_INITIALIZER. The mutex is then ready for use, without
71 * first calling pthread_mutex_init().
73 * Windows has no equivalent statically initialized mutex or CRITICAL SECION.
74 * InitializeCriticalSection() must be called. If the global mutex does not
75 * appear to be initialized, a thread will create and initialize a new
76 * CRITICAL_SECTION, then use a Windows InterlockedCompareAndExchange to
77 * avoid problems with race conditions.
79 * If an application has overridden the ICU mutex implementation
80 * by calling u_setMutexFunctions(), the user supplied init function must
81 * be safe in the event that multiple threads concurrently attempt to init
82 * the same mutex. The first thread should do the init, and the others should
87 #define MAX_MUTEXES 30
88 static UMTX gGlobalMutex
= NULL
;
89 static UMTX gIncDecMutex
= NULL
;
90 #if (ICU_USE_THREADS == 1)
91 static UBool gMutexPoolInitialized
= FALSE
;
92 static char gMutexesInUse
[MAX_MUTEXES
];
95 /*-------------------------------------------------------------
97 * WINDOWS platform variable declarations
99 *-------------------------------------------------------------*/
100 static CRITICAL_SECTION gMutexes
[MAX_MUTEXES
];
101 static CRITICAL_SECTION gGlobalWinMutex
;
104 /* On WIN32 mutexes are reentrant. This makes it difficult to debug
105 * deadlocking problems that show up on POSIXy platforms, where
106 * mutexes deadlock upon reentry. ICU contains checking code for
107 * the global mutex as well as for other mutexes in the pool.
109 * This is for debugging purposes.
111 * This has no effect on non-WIN32 platforms, non-DEBUG builds, and
112 * non-ICU_USE_THREADS builds.
114 * Note: The CRITICAL_SECTION structure already has a RecursionCount
115 * member that can be used for this purpose, but portability to
116 * Win98/NT/2K needs to be tested before use. Works fine on XP.
117 * After portability is confirmed, the built-in RecursionCount can be
118 * used, and the gRecursionCountPool can be removed.
120 * Note: Non-global mutex checking only happens if there is no custom
121 * pMutexLockFn defined. Use one function, not two (don't use
122 * pMutexLockFn and pMutexUnlockFn) so the increment and decrement of
123 * the recursion count don't get out of sync. Users might set just
124 * one function, e.g., to perform a custom action, followed by a
125 * standard call to EnterCriticalSection.
127 #if defined(U_DEBUG) && (ICU_USE_THREADS==1)
128 static int32_t gRecursionCount
= 0; /* detect global mutex locking */
129 static int32_t gRecursionCountPool
[MAX_MUTEXES
]; /* ditto for non-global */
134 /*-------------------------------------------------------------
136 * POSIX platform variable declarations
138 *-------------------------------------------------------------*/
139 static pthread_mutex_t gMutexes
[MAX_MUTEXES
] = {
140 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
,
141 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
,
142 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
,
143 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
,
144 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
,
145 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
,
146 PTHREAD_MUTEX_INITIALIZER
, PTHREAD_MUTEX_INITIALIZER
150 /*-------------------------------------------------------------
152 * UNKNOWN platform declarations
154 *-------------------------------------------------------------*/
155 static void *gMutexes
[MAX_MUTEXES
] = {
164 /* Unknown platform. OK so long as ICU_USE_THREAD is not set.
165 Note that user can still set mutex functions at run time,
166 and that the global mutex variable is still needed in that case. */
167 #if (ICU_USE_THREADS == 1)
168 #error no ICU mutex implementation for this platform
171 #endif /* ICU_USE_THREADS==1 */
177 * User mutex implementation functions. If non-null, call back to these rather than
178 * directly using the system (Posix or Windows) APIs.
179 * (declarations are in uclean.h)
181 static UMtxInitFn
*pMutexInitFn
= NULL
;
182 static UMtxFn
*pMutexDestroyFn
= NULL
;
183 static UMtxFn
*pMutexLockFn
= NULL
;
184 static UMtxFn
*pMutexUnlockFn
= NULL
;
185 static const void *gMutexContext
= NULL
;
192 U_CAPI
void U_EXPORT2
193 umtx_lock(UMTX
*mutex
)
196 mutex
= &gGlobalMutex
;
199 if (*mutex
== NULL
) {
200 /* Lock of an uninitialized mutex. Initialize it before proceeding. */
204 if (pMutexLockFn
!= NULL
) {
205 (*pMutexLockFn
)(gMutexContext
, mutex
);
208 #if (ICU_USE_THREADS == 1)
210 EnterCriticalSection((CRITICAL_SECTION
*) *mutex
);
212 pthread_mutex_lock((pthread_mutex_t
*) *mutex
);
213 #endif /* cascade of platforms */
214 #endif /* ICU_USE_THREADS==1 */
217 #if defined(WIN32) && defined(U_DEBUG) && (ICU_USE_THREADS==1)
218 if (mutex
== &gGlobalMutex
) { /* Detect Reentrant locking of the global mutex. */
219 gRecursionCount
++; /* Recursion causes deadlocks on Unixes. */
220 U_ASSERT(gRecursionCount
== 1); /* Detection works on Windows. Debug problems there. */
222 /* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
223 else if (pMutexLockFn
== NULL
) { /* see comments above */
224 int i
= ((CRITICAL_SECTION
*)*mutex
) - &gMutexes
[0];
225 U_ASSERT(i
>= 0 && i
< MAX_MUTEXES
);
226 ++gRecursionCountPool
[i
];
228 U_ASSERT(gRecursionCountPool
[i
] == 1); /* !Detect Deadlock! */
230 /* This works and is fast, but needs testing on Win98/NT/2K.
231 See comments above. [alan]
232 U_ASSERT((CRITICAL_SECTION*)*mutex >= &gMutexes[0] &&
233 (CRITICAL_SECTION*)*mutex <= &gMutexes[MAX_MUTEXES]);
234 U_ASSERT(((CRITICAL_SECTION*)*mutex)->RecursionCount == 1);
245 U_CAPI
void U_EXPORT2
246 umtx_unlock(UMTX
* mutex
)
249 mutex
= &gGlobalMutex
;
253 #if (ICU_USE_THREADS == 1)
254 U_ASSERT(FALSE
); /* This mutex is not initialized. */
259 #if defined (WIN32) && defined (U_DEBUG) && (ICU_USE_THREADS==1)
260 if (mutex
== &gGlobalMutex
) {
262 U_ASSERT(gRecursionCount
== 0); /* Detect unlock of an already unlocked mutex */
264 /* This handles gGlobalMutex too, but only if there is no pMutexLockFn */
265 else if (pMutexLockFn
== NULL
) { /* see comments above */
266 int i
= ((CRITICAL_SECTION
*)*mutex
) - &gMutexes
[0];
267 U_ASSERT(i
>= 0 && i
< MAX_MUTEXES
);
268 --gRecursionCountPool
[i
];
270 U_ASSERT(gRecursionCountPool
[i
] == 0); /* !Detect Deadlock! */
272 /* This works and is fast, but needs testing on Win98/NT/2K.
273 Note that RecursionCount will be 1, not 0, since we haven't
274 left the CRITICAL_SECTION yet. See comments above. [alan]
275 U_ASSERT((CRITICAL_SECTION*)*mutex >= &gMutexes[0] &&
276 (CRITICAL_SECTION*)*mutex <= &gMutexes[MAX_MUTEXES]);
277 U_ASSERT(((CRITICAL_SECTION*)*mutex)->RecursionCount == 1);
282 if (pMutexUnlockFn
) {
283 (*pMutexUnlockFn
)(gMutexContext
, mutex
);
285 #if (ICU_USE_THREADS==1)
287 LeaveCriticalSection((CRITICAL_SECTION
*)*mutex
);
288 #elif defined (POSIX)
289 pthread_mutex_unlock((pthread_mutex_t
*)*mutex
);
290 #endif /* cascade of platforms */
291 #endif /* ICU_USE_THREADS == 1 */
299 * initGlobalMutex Do the platform specific initialization of the ICU global mutex.
300 * Separated out from the other mutexes because it is different:
301 * Mutex storage is static for POSIX, init must be thread safe
302 * without the use of another mutex.
304 static void initGlobalMutex() {
306 * If User Supplied mutex functions are in use
307 * init the icu global mutex using them.
309 if (pMutexInitFn
!= NULL
) {
310 if (gGlobalMutex
==NULL
) {
311 UErrorCode status
= U_ZERO_ERROR
;
312 (*pMutexInitFn
)(gMutexContext
, &gGlobalMutex
, &status
);
313 if (U_FAILURE(status
)) {
314 /* TODO: how should errors here be handled? */
321 /* No user override of mutex functions.
322 * Use default ICU mutex implementations.
324 #if (ICU_USE_THREADS == 1)
326 * for Windows, init the pool of critical sections that we
327 * will use as needed for ICU mutexes.
330 if (gMutexPoolInitialized
== FALSE
) {
332 for (i
=0; i
<MAX_MUTEXES
; i
++) {
333 InitializeCriticalSection(&gMutexes
[i
]);
334 #if defined (U_DEBUG)
335 gRecursionCountPool
[i
] = 0; /* see comments above */
338 gMutexPoolInitialized
= TRUE
;
340 #elif defined (POSIX)
341 /* TODO: experimental code. Shouldn't need to explicitly init the mutexes. */
342 if (gMutexPoolInitialized
== FALSE
) {
344 for (i
=0; i
<MAX_MUTEXES
; i
++) {
345 pthread_mutex_init(&gMutexes
[i
], NULL
);
347 gMutexPoolInitialized
= TRUE
;
352 * for both Windows & POSIX, the first mutex in the array is used
353 * for the ICU global mutex.
355 gGlobalMutex
= &gMutexes
[0];
356 gMutexesInUse
[0] = 1;
358 #else /* ICU_USE_THREADS */
359 gGlobalMutex
= &gGlobalMutex
; /* With no threads, we must still set the mutex to
360 * some non-null value to make the rest of the
361 * (not ifdefed) mutex code think that it is initialized.
363 #endif /* ICU_USE_THREADS */
370 U_CAPI
void U_EXPORT2
371 umtx_init(UMTX
*mutex
)
373 if (mutex
== NULL
|| mutex
== &gGlobalMutex
) {
377 if (*mutex
!= NULL
) {
378 /* Another thread initialized this mutex first. */
383 if (pMutexInitFn
!= NULL
) {
384 UErrorCode status
= U_ZERO_ERROR
;
385 (*pMutexInitFn
)(gMutexContext
, mutex
, &status
);
386 /* TODO: how to report failure on init? */
391 #if (ICU_USE_THREADS == 1)
392 /* Search through our pool of pre-allocated mutexes for one that is not
395 for (i
=0; i
<MAX_MUTEXES
; i
++) {
396 if (gMutexesInUse
[i
] == 0) {
397 gMutexesInUse
[i
] = 1;
398 *mutex
= &gMutexes
[i
];
406 #if (ICU_USE_THREADS == 1)
407 /* No more mutexes were available from our pre-allocated pool. */
408 /* TODO: how best to deal with this? */
409 U_ASSERT(*mutex
!= NULL
);
416 * umtx_destroy. Un-initialize a mutex, releasing any underlying resources
417 * that it may be holding. Destroying an already destroyed
418 * mutex has no effect. Unlike umtx_init(), this function
419 * is not thread safe; two threads must not concurrently try to
420 * destroy the same mutex.
422 U_CAPI
void U_EXPORT2
423 umtx_destroy(UMTX
*mutex
) {
424 if (mutex
== NULL
) { /* destroy the global mutex */
425 mutex
= &gGlobalMutex
;
428 if (*mutex
== NULL
) { /* someone already did it. */
432 /* The life of the inc/dec mutex is tied to that of the global mutex. */
433 if (mutex
== &gGlobalMutex
) {
434 umtx_destroy(&gIncDecMutex
);
437 if (pMutexDestroyFn
!= NULL
) {
438 /* Mutexes are being managed by the app. Call back to it for the destroy. */
439 (*pMutexDestroyFn
)(gMutexContext
, mutex
);
442 #if (ICU_USE_THREADS == 1)
443 /* Return this mutex to the pool of available mutexes, if it came from the
444 * pool in the first place.
446 /* TODO use pointer math here, instead of iterating! */
448 for (i
=0; i
<MAX_MUTEXES
; i
++) {
449 if (*mutex
== &gMutexes
[i
]) {
450 gMutexesInUse
[i
] = 0;
462 U_CAPI
void U_EXPORT2
463 u_setMutexFunctions(const void *context
, UMtxInitFn
*i
, UMtxFn
*d
, UMtxFn
*l
, UMtxFn
*u
,
464 UErrorCode
*status
) {
465 if (U_FAILURE(*status
)) {
469 /* Can not set a mutex function to a NULL value */
470 if (i
==NULL
|| d
==NULL
|| l
==NULL
|| u
==NULL
) {
471 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
475 /* If ICU is not in an initial state, disallow this operation. */
476 if (cmemory_inUse()) {
477 *status
= U_INVALID_STATE_ERROR
;
481 /* Swap in the mutex function pointers. */
486 gMutexContext
= context
;
487 gGlobalMutex
= NULL
; /* For POSIX, the global mutex will be pre-initialized */
488 /* Undo that, force re-initialization when u_init() */
494 /*-----------------------------------------------------------------
496 * Atomic Increment and Decrement
500 *----------------------------------------------------------------*/
502 /* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */
503 static UMtxAtomicFn
*pIncFn
= NULL
;
504 static UMtxAtomicFn
*pDecFn
= NULL
;
505 static void *gIncDecContext
= NULL
;
508 U_CAPI
int32_t U_EXPORT2
509 umtx_atomic_inc(int32_t *p
) {
512 retVal
= (*pIncFn
)(gIncDecContext
, p
);
514 #if defined (WIN32) && ICU_USE_THREADS == 1
515 retVal
= InterlockedIncrement((LONG
*)p
);
516 #elif defined (POSIX) && ICU_USE_THREADS == 1
517 umtx_lock(&gIncDecMutex
);
519 umtx_unlock(&gIncDecMutex
);
521 /* Unknown Platform, or ICU thread support compiled out. */
528 U_CAPI
int32_t U_EXPORT2
529 umtx_atomic_dec(int32_t *p
) {
532 retVal
= (*pDecFn
)(gIncDecContext
, p
);
534 #if defined (WIN32) && ICU_USE_THREADS == 1
535 retVal
= InterlockedDecrement((LONG
*)p
);
536 #elif defined (POSIX) && ICU_USE_THREADS == 1
537 umtx_lock(&gIncDecMutex
);
539 umtx_unlock(&gIncDecMutex
);
541 /* Unknown Platform, or ICU thread support compiled out. */
548 /* TODO: Some POSIXy platforms have atomic inc/dec functions available. Use them. */
554 U_CAPI
void U_EXPORT2
555 u_setAtomicIncDecFunctions(const void *context
, UMtxAtomicFn
*ip
, UMtxAtomicFn
*dp
,
556 UErrorCode
*status
) {
558 if (U_FAILURE(*status
)) {
561 /* Can not set a mutex function to a NULL value */
562 if (ip
==NULL
|| dp
==NULL
) {
563 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
566 /* If ICU is not in an initial state, disallow this operation. */
567 if (cmemory_inUse()) {
568 *status
= U_INVALID_STATE_ERROR
;
576 U_ASSERT(umtx_atomic_inc(&testInt
) == 1); /* Sanity Check. Do the functions work at all? */
577 U_ASSERT(testInt
== 1);
578 U_ASSERT(umtx_atomic_dec(&testInt
) == 0);
579 U_ASSERT(testInt
== 0);
585 * Mutex Cleanup Function
587 * Destroy the global mutex(es), and reset the mutex function callback pointers.
589 U_CFUNC UBool
umtx_cleanup(void) {
592 pMutexDestroyFn
= NULL
;
594 pMutexUnlockFn
= NULL
;
595 gMutexContext
= NULL
;
601 #if (ICU_USE_THREADS == 1)
602 if (gMutexPoolInitialized
) {
604 for (i
=0; i
<MAX_MUTEXES
; i
++) {
605 if (gMutexesInUse
[i
]) {
607 DeleteCriticalSection(&gMutexes
[i
]);
608 #elif defined (POSIX)
609 pthread_mutex_destroy(&gMutexes
[i
]);
611 gMutexesInUse
[i
] = 0;
615 gMutexPoolInitialized
= FALSE
;