2 ******************************************************************************
4 * Copyright (C) 1997-2011, 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 #include "unicode/utypes.h"
26 * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a
27 * platform independent set of mutex operations. For internal ICU use only.
30 #if U_PLATFORM_HAS_WIN32_API
31 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
33 #elif U_PLATFORM_IMPLEMENTS_POSIX
39 #if defined(POSIX) && (ICU_USE_THREADS==1)
40 # include <pthread.h> /* must be first, so that we get the multithread versions of things. */
42 #endif /* POSIX && (ICU_USE_THREADS==1) */
44 #if U_PLATFORM_HAS_WIN32_API
45 # define WIN32_LEAN_AND_MEAN
58 * A note on ICU Mutex Initialization and ICU startup:
60 * ICU mutexes, as used through the rest of the ICU code, are self-initializing.
61 * To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init
62 * of other ICU mutexes. For the global mutex itself, we need some other mechanism
63 * to safely initialize it on first use. This becomes important when two or more
64 * threads are more or less simultaenously the first to use ICU in a process, and
65 * are racing into the mutex initialization code.
68 * The solution for the global mutex init is platform dependent.
69 * On POSIX systems, plain C-style initialization 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 * swap it in as the global mutex while avoid problems with race conditions.
80 /* On WIN32 mutexes are reentrant. On POSIX platforms they are not, and a deadlock
81 * will occur if a thread attempts to acquire a mutex it already has locked.
82 * ICU mutexes (in debug builds) include checking code that will cause an assertion
83 * failure if a mutex is reentered. If you are having deadlock problems
84 * on a POSIX machine, debugging may be easier on Windows.
88 #if (ICU_USE_THREADS == 0)
89 #define MUTEX_TYPE void *
90 #define PLATFORM_MUTEX_INIT(m)
91 #define PLATFORM_MUTEX_LOCK(m)
92 #define PLATFORM_MUTEX_UNLOCK(m)
93 #define PLATFORM_MUTEX_DESTROY(m)
94 #define PLATFORM_MUTEX_INITIALIZER NULL
95 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
96 mutexed_compare_and_swap(dest, newval, oldval)
99 #elif U_PLATFORM_HAS_WIN32_API
100 #define MUTEX_TYPE CRITICAL_SECTION
101 #define PLATFORM_MUTEX_INIT(m) InitializeCriticalSection(m)
102 #define PLATFORM_MUTEX_LOCK(m) EnterCriticalSection(m)
103 #define PLATFORM_MUTEX_UNLOCK(m) LeaveCriticalSection(m)
104 #define PLATFORM_MUTEX_DESTROY(m) DeleteCriticalSection(m)
105 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
106 InterlockedCompareExchangePointer(dest, newval, oldval)
110 #define MUTEX_TYPE pthread_mutex_t
111 #define PLATFORM_MUTEX_INIT(m) pthread_mutex_init(m, NULL)
112 #define PLATFORM_MUTEX_LOCK(m) pthread_mutex_lock(m)
113 #define PLATFORM_MUTEX_UNLOCK(m) pthread_mutex_unlock(m)
114 #define PLATFORM_MUTEX_DESTROY(m) pthread_mutex_destroy(m)
115 #define PLATFORM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
116 #if (U_HAVE_GCC_ATOMICS == 1)
117 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
118 __sync_val_compare_and_swap(dest, oldval, newval)
120 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
121 mutexed_compare_and_swap(dest, newval, oldval)
126 /* Unknown platform. Note that user can still set mutex functions at run time. */
127 #define MUTEX_TYPE void *
128 #define PLATFORM_MUTEX_INIT(m)
129 #define PLATFORM_MUTEX_LOCK(m)
130 #define PLATFORM_MUTEX_UNLOCK(m)
131 #define PLATFORM_MUTEX_DESTROY(m)
132 #define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
133 mutexed_compare_and_swap(dest, newval, oldval)
137 /* Forward declarations */
138 static void *mutexed_compare_and_swap(void **dest
, void *newval
, void *oldval
);
139 typedef struct ICUMutex ICUMutex
;
142 * ICUMutex One of these is set up for each UMTX that is used by other ICU code.
143 * The opaque UMTX points to the corresponding ICUMutex struct.
145 * Because the total number of ICU mutexes is quite small, no effort has
146 * been made to squeeze every byte out of this struct.
149 UMTX
*owner
; /* Points back to the UMTX corrsponding to this */
150 /* ICUMutex object. */
152 UBool heapAllocated
; /* Set if this ICUMutex is heap allocated, and */
153 /* will need to be deleted. The global mutex */
154 /* is static on POSIX platforms; all others */
155 /* will be heap allocated. */
157 ICUMutex
*next
; /* All ICUMutexes are chained into a list so that */
158 /* they can be found and deleted by u_cleanup(). */
160 int32_t recursionCount
; /* For debugging, detect recursive mutex locks. */
162 MUTEX_TYPE platformMutex
; /* The underlying OS mutex being wrapped. */
164 UMTX userMutex
; /* For use with u_setMutexFunctions operations, */
165 /* corresponds to platformMutex. */
169 /* The global ICU mutex.
170 * For POSIX platforms, it gets a C style initialization, and is ready to use
171 * at program startup.
172 * For Windows, it will be lazily instantiated on first use.
176 static UMTX globalUMTX
;
177 static ICUMutex globalMutex
= {&globalUMTX
, FALSE
, NULL
, 0, PLATFORM_MUTEX_INITIALIZER
, NULL
};
178 static UMTX globalUMTX
= &globalMutex
;
180 static UMTX globalUMTX
= NULL
;
183 /* Head of the list of all ICU mutexes.
184 * Linked list is through ICUMutex::next
185 * Modifications to the list are synchronized with the global mutex.
186 * The list is used by u_cleanup(), which needs to dispose of all of the ICU mutexes.
188 * The statically initialized global mutex on POSIX platforms does not get added to this
189 * mutex list, but that's not a problem - the global mutex gets special handling
190 * during u_cleanup().
192 static ICUMutex
*mutexListHead
;
196 * User mutex implementation functions. If non-null, call back to these rather than
197 * directly using the system (Posix or Windows) APIs. See u_setMutexFunctions().
198 * (declarations are in uclean.h)
200 static UMtxInitFn
*pMutexInitFn
= NULL
;
201 static UMtxFn
*pMutexDestroyFn
= NULL
;
202 static UMtxFn
*pMutexLockFn
= NULL
;
203 static UMtxFn
*pMutexUnlockFn
= NULL
;
204 static const void *gMutexContext
= NULL
;
210 U_CAPI
void U_EXPORT2
211 umtx_lock(UMTX
*mutex
)
218 m
= (ICUMutex
*)*mutex
;
220 /* See note on lazy initialization, above. We can get away with it here, with mutexes,
221 * where we couldn't with normal user level data.
224 m
= (ICUMutex
*)*mutex
;
226 U_ASSERT(m
->owner
== mutex
);
228 if (pMutexLockFn
!= NULL
) {
229 (*pMutexLockFn
)(gMutexContext
, &m
->userMutex
);
231 PLATFORM_MUTEX_LOCK(&m
->platformMutex
);
235 m
->recursionCount
++; /* Recursion causes deadlock on Unixes. */
236 U_ASSERT(m
->recursionCount
== 1); /* Recursion detection works on Windows. */
237 /* Assertion failure on non-Windows indicates a */
238 /* problem with the mutex implementation itself. */
247 U_CAPI
void U_EXPORT2
248 umtx_unlock(UMTX
* mutex
)
254 m
= (ICUMutex
*)*mutex
;
256 U_ASSERT(FALSE
); /* This mutex is not initialized. */
259 U_ASSERT(m
->owner
== mutex
);
261 #if defined (U_DEBUG)
263 U_ASSERT(m
->recursionCount
== 0); /* Detect unlock of an already unlocked mutex */
266 if (pMutexUnlockFn
) {
267 (*pMutexUnlockFn
)(gMutexContext
, &m
->userMutex
);
269 PLATFORM_MUTEX_UNLOCK(&m
->platformMutex
);
274 /* umtx_ct Allocate and initialize a new ICUMutex.
275 * If a non-null pointer is supplied, initialize an existing ICU Mutex.
277 static ICUMutex
*umtx_ct(ICUMutex
*m
) {
279 m
= (ICUMutex
*)uprv_malloc(sizeof(ICUMutex
));
280 m
->heapAllocated
= TRUE
;
282 m
->next
= NULL
; /* List of mutexes is maintained at a higher level. */
283 m
->recursionCount
= 0;
285 if (pMutexInitFn
!= NULL
) {
286 UErrorCode status
= U_ZERO_ERROR
;
287 (*pMutexInitFn
)(gMutexContext
, &m
->userMutex
, &status
);
288 U_ASSERT(U_SUCCESS(status
));
290 PLATFORM_MUTEX_INIT(&m
->platformMutex
);
296 /* umtx_dt Delete a ICUMutex. Destroy the underlying OS Platform mutex.
297 * Does not touch the linked list of ICU Mutexes.
299 static void umtx_dt(ICUMutex
*m
) {
300 if (pMutexDestroyFn
!= NULL
) {
301 (*pMutexDestroyFn
)(gMutexContext
, &m
->userMutex
);
304 PLATFORM_MUTEX_DESTROY(&m
->platformMutex
);
307 if (m
->heapAllocated
) {
313 U_CAPI
void U_EXPORT2
314 umtx_init(UMTX
*mutex
) {
318 if (*mutex
!= NULL
) {
319 /* Mutex is already initialized.
320 * Multiple umtx_init()s of a UMTX by other ICU code are explicitly permitted.
325 if (mutex
== &globalUMTX
) {
331 originalValue
= SYNC_COMPARE_AND_SWAP(mutex
, NULL
, m
);
332 if (originalValue
!= NULL
) {
339 /* Hook the new mutex into the list of all ICU mutexes, so that we can find and
340 * delete it for u_cleanup().
344 m
->next
= mutexListHead
;
352 * umtx_destroy. Un-initialize a mutex, releasing any underlying resources
353 * that it may be holding. Destroying an already destroyed
354 * mutex has no effect. Unlike umtx_init(), this function
355 * is not thread safe; two threads must not concurrently try to
356 * destroy the same mutex.
358 U_CAPI
void U_EXPORT2
359 umtx_destroy(UMTX
*mutex
) {
362 /* No one should be deleting the global ICU mutex.
363 * (u_cleanup() does delete it, but does so explicitly, not by passing NULL)
365 U_ASSERT(mutex
!= NULL
);
370 m
= (ICUMutex
*)*mutex
;
371 if (m
== NULL
) { /* Mutex not initialized, or already destroyed. */
375 U_ASSERT(m
->owner
== mutex
);
376 if (m
->owner
!= mutex
) {
380 /* Remove this mutex from the linked list of mutexes. */
382 if (mutexListHead
== m
) {
383 mutexListHead
= m
->next
;
386 for (prev
= mutexListHead
; prev
!=NULL
&& prev
->next
!=m
; prev
= prev
->next
);
387 /* Empty for loop body */
389 prev
->next
= m
->next
;
394 umtx_dt(m
); /* Delete the internal ICUMutex */
395 *mutex
= NULL
; /* Clear the caller's UMTX */
400 U_CAPI
void U_EXPORT2
401 u_setMutexFunctions(const void *context
, UMtxInitFn
*i
, UMtxFn
*d
, UMtxFn
*l
, UMtxFn
*u
,
402 UErrorCode
*status
) {
403 if (U_FAILURE(*status
)) {
407 /* Can not set a mutex function to a NULL value */
408 if (i
==NULL
|| d
==NULL
|| l
==NULL
|| u
==NULL
) {
409 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
413 /* If ICU is not in an initial state, disallow this operation. */
414 if (cmemory_inUse()) {
415 *status
= U_INVALID_STATE_ERROR
;
419 /* Kill any existing global mutex. POSIX platforms have a global mutex
420 * even before any other part of ICU is initialized.
422 umtx_destroy(&globalUMTX
);
424 /* Swap in the mutex function pointers. */
429 gMutexContext
= context
;
432 /* POSIX platforms must have a pre-initialized global mutex
433 * to allow other mutexes to initialize safely. */
434 umtx_init(&globalUMTX
);
439 /* synchronized compare and swap function, for use when OS or compiler built-in
440 * equivalents aren't available.
442 * This operation relies on the ICU global mutex for synchronization.
444 * There are two cases where this function can be entered when the global mutex is not
445 * yet initialized - at the end u_cleanup(), and at the end of u_setMutexFunctions, both
446 * of which re-init the global mutex. But neither function is thread-safe, so the lack of
447 * synchronization at these points doesn't matter.
449 static void *mutexed_compare_and_swap(void **dest
, void *newval
, void *oldval
) {
451 UBool needUnlock
= FALSE
;
453 if (globalUMTX
!= NULL
) {
454 umtx_lock(&globalUMTX
);
459 if (temp
== oldval
) {
464 umtx_unlock(&globalUMTX
);
471 /*-----------------------------------------------------------------
473 * Atomic Increment and Decrement
477 *----------------------------------------------------------------*/
479 /* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */
480 static UMtxAtomicFn
*pIncFn
= NULL
;
481 static UMtxAtomicFn
*pDecFn
= NULL
;
482 static const void *gIncDecContext
= NULL
;
484 static UMTX gIncDecMutex
= NULL
;
486 U_CAPI
int32_t U_EXPORT2
487 umtx_atomic_inc(int32_t *p
) {
490 retVal
= (*pIncFn
)(gIncDecContext
, p
);
493 /* ICU thread support compiled out. */
495 #elif U_PLATFORM_HAS_WIN32_API
496 retVal
= InterlockedIncrement((LONG
*)p
);
497 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
498 retVal
= OSAtomicIncrement32Barrier(p
);
499 #elif (U_HAVE_GCC_ATOMICS == 1)
500 retVal
= __sync_add_and_fetch(p
, 1);
501 #elif defined (POSIX)
502 umtx_lock(&gIncDecMutex
);
504 umtx_unlock(&gIncDecMutex
);
506 /* Unknown Platform. */
513 U_CAPI
int32_t U_EXPORT2
514 umtx_atomic_dec(int32_t *p
) {
517 retVal
= (*pDecFn
)(gIncDecContext
, p
);
520 /* ICU thread support compiled out. */
522 #elif U_PLATFORM_HAS_WIN32_API
523 retVal
= InterlockedDecrement((LONG
*)p
);
524 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
525 retVal
= OSAtomicDecrement32Barrier(p
);
526 #elif (U_HAVE_GCC_ATOMICS == 1)
527 retVal
= __sync_sub_and_fetch(p
, 1);
528 #elif defined (POSIX)
529 umtx_lock(&gIncDecMutex
);
531 umtx_unlock(&gIncDecMutex
);
533 /* Unknown Platform. */
542 U_CAPI
void U_EXPORT2
543 u_setAtomicIncDecFunctions(const void *context
, UMtxAtomicFn
*ip
, UMtxAtomicFn
*dp
,
544 UErrorCode
*status
) {
545 if (U_FAILURE(*status
)) {
548 /* Can not set a mutex function to a NULL value */
549 if (ip
==NULL
|| dp
==NULL
) {
550 *status
= U_ILLEGAL_ARGUMENT_ERROR
;
553 /* If ICU is not in an initial state, disallow this operation. */
554 if (cmemory_inUse()) {
555 *status
= U_INVALID_STATE_ERROR
;
561 gIncDecContext
= context
;
566 U_ASSERT(umtx_atomic_inc(&testInt
) == 1); /* Sanity Check. Do the functions work at all? */
567 U_ASSERT(testInt
== 1);
568 U_ASSERT(umtx_atomic_dec(&testInt
) == 0);
569 U_ASSERT(testInt
== 0);
577 * Mutex Cleanup Function
579 * Destroy the global mutex(es), and reset the mutex function callback pointers.
581 U_CFUNC UBool
umtx_cleanup(void) {
582 ICUMutex
*thisMutex
= NULL
;
583 ICUMutex
*nextMutex
= NULL
;
585 /* Extra, do-nothing function call to suppress compiler warnings on platforms where
586 * mutexed_compare_and_swap is not otherwise used. */
587 mutexed_compare_and_swap(&globalUMTX
, NULL
, NULL
);
589 /* Delete all of the ICU mutexes. Do the global mutex last because it is used during
590 * the umtx_destroy operation of other mutexes.
592 for (thisMutex
=mutexListHead
; thisMutex
!=NULL
; thisMutex
=nextMutex
) {
593 UMTX
*umtx
= thisMutex
->owner
;
594 nextMutex
= thisMutex
->next
;
595 U_ASSERT(*umtx
= (void *)thisMutex
);
596 if (umtx
!= &globalUMTX
) {
600 umtx_destroy(&globalUMTX
);
603 pMutexDestroyFn
= NULL
;
605 pMutexUnlockFn
= NULL
;
606 gMutexContext
= NULL
;
609 gIncDecContext
= NULL
;
613 /* POSIX platforms must come out of u_cleanup() with a functioning global mutex
614 * to permit the safe resumption of use of ICU in multi-threaded environments.
616 umtx_init(&globalUMTX
);