]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.c
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / common / umutex.c
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
3*
729e4ab9 4* Copyright (C) 1997-2009, International Business Machines
b75a7d8f
A
5* Corporation and others. All Rights Reserved.
6*
7******************************************************************************
8*
729e4ab9 9* File umutex.c
b75a7d8f
A
10*
11* Modification History:
12*
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******************************************************************************
19*/
20
73c04bcf
A
21#include "unicode/utypes.h"
22#include "uassert.h"
23#include "ucln_cmn.h"
24
729e4ab9
A
25/*
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.
28 */
29
73c04bcf
A
30#if defined(U_DARWIN)
31#include <AvailabilityMacros.h>
32#if (ICU_USE_THREADS == 1) && defined(MAC_OS_X_VERSION_10_4) && defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4)
46f4442e
A
33#if defined(__STRICT_ANSI__)
34#define UPRV_REMAP_INLINE
35#define inline
36#endif
73c04bcf
A
37#include <libkern/OSAtomic.h>
38#define USE_MAC_OS_ATOMIC_INCREMENT 1
46f4442e
A
39#if defined(UPRV_REMAP_INLINE)
40#undef inline
41#undef UPRV_REMAP_INLINE
42#endif
73c04bcf
A
43#endif
44#endif
45
b75a7d8f
A
46/* Assume POSIX, and modify as necessary below */
47#define POSIX
48
73c04bcf 49#if defined(U_WINDOWS)
b75a7d8f
A
50#undef POSIX
51#endif
52#if defined(macintosh)
53#undef POSIX
54#endif
55#if defined(OS2)
56#undef POSIX
57#endif
58
b75a7d8f 59#if defined(POSIX) && (ICU_USE_THREADS==1)
b75a7d8f
A
60# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
61
b75a7d8f
A
62#endif /* POSIX && (ICU_USE_THREADS==1) */
63
73c04bcf 64#ifdef U_WINDOWS
b75a7d8f 65# define WIN32_LEAN_AND_MEAN
374ca955 66# define VC_EXTRALEAN
b75a7d8f
A
67# define NOUSER
68# define NOSERVICE
69# define NOIME
70# define NOMCX
71# include <windows.h>
72#endif
73
74#include "umutex.h"
75#include "cmemory.h"
76
374ca955
A
77/*
78 * A note on ICU Mutex Initialization and ICU startup:
79 *
80 * ICU mutexes, as used through the rest of the ICU code, are self-initializing.
81 * To make this work, ICU uses the _ICU GLobal Mutex_ to synchronize the lazy init
82 * of other ICU mutexes. For the global mutex itself, we need some other mechanism
729e4ab9
A
83 * to safely initialize it on first use. This becomes important when two or more
84 * threads are more or less simultaenously the first to use ICU in a process, and
85 * are racing into the mutex initialization code.
86 *
374ca955
A
87 *
88 * The solution for the global mutex init is platform dependent.
729e4ab9 89 * On POSIX systems, plain C-style initialization can be used on a mutex, with the
374ca955
A
90 * macro PTHREAD_MUTEX_INITIALIZER. The mutex is then ready for use, without
91 * first calling pthread_mutex_init().
92 *
93 * Windows has no equivalent statically initialized mutex or CRITICAL SECION.
94 * InitializeCriticalSection() must be called. If the global mutex does not
95 * appear to be initialized, a thread will create and initialize a new
96 * CRITICAL_SECTION, then use a Windows InterlockedCompareAndExchange to
729e4ab9 97 * swap it in as the global mutex while avoid problems with race conditions.
374ca955
A
98 */
99
729e4ab9
A
100/* On WIN32 mutexes are reentrant. On POSIX platforms they are not, and a deadlock
101 * will occur if a thread attempts to acquire a mutex it already has locked.
102 * ICU mutexes (in debug builds) include checking code that will cause an assertion
103 * failure if a mutex is reentered. If you are having deadlock problems
104 * on a POSIX machine, debugging may be easier on Windows.
105 */
374ca955 106
374ca955 107
729e4ab9
A
108#if (ICU_USE_THREADS == 0)
109#define MUTEX_TYPE void *
110#define PLATFORM_MUTEX_INIT(m)
111#define PLATFORM_MUTEX_LOCK(m)
112#define PLATFORM_MUTEX_UNLOCK(m)
113#define PLATFORM_MUTEX_DESTROY(m)
114#define PLATFORM_MUTEX_INITIALIZER NULL
115#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
116 mutexed_compare_and_swap(dest, newval, oldval)
374ca955 117
b75a7d8f 118
729e4ab9
A
119#elif defined(U_WINDOWS)
120#define MUTEX_TYPE CRITICAL_SECTION
121#define PLATFORM_MUTEX_INIT(m) InitializeCriticalSection(m)
122#define PLATFORM_MUTEX_LOCK(m) EnterCriticalSection(m)
123#define PLATFORM_MUTEX_UNLOCK(m) LeaveCriticalSection(m)
124#define PLATFORM_MUTEX_DESTROY(m) DeleteCriticalSection(m)
125#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
126 InterlockedCompareExchangePointer(dest, newval, oldval)
b75a7d8f 127
b75a7d8f 128
729e4ab9
A
129#elif defined(POSIX)
130#define MUTEX_TYPE pthread_mutex_t
131#define PLATFORM_MUTEX_INIT(m) pthread_mutex_init(m, NULL)
132#define PLATFORM_MUTEX_LOCK(m) pthread_mutex_lock(m)
133#define PLATFORM_MUTEX_UNLOCK(m) pthread_mutex_unlock(m)
134#define PLATFORM_MUTEX_DESTROY(m) pthread_mutex_destroy(m)
135#define PLATFORM_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
136#if (U_HAVE_GCC_ATOMICS == 1)
137#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
138 __sync_val_compare_and_swap(dest, oldval, newval)
139#else
140#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
141 mutexed_compare_and_swap(dest, newval, oldval)
374ca955 142#endif
729e4ab9
A
143
144
145#else
146/* Unknown platform. Note that user can still set mutex functions at run time. */
147#define MUTEX_TYPE void *
148#define PLATFORM_MUTEX_INIT(m)
149#define PLATFORM_MUTEX_LOCK(m)
150#define PLATFORM_MUTEX_UNLOCK(m)
151#define PLATFORM_MUTEX_DESTROY(m)
152#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
153 mutexed_compare_and_swap(dest, newval, oldval)
154
b75a7d8f 155#endif
729e4ab9
A
156
157/* Forward declarations */
158static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval);
159typedef struct ICUMutex ICUMutex;
160
161/*
162 * ICUMutex One of these is set up for each UMTX that is used by other ICU code.
163 * The opaque UMTX points to the corresponding ICUMutex struct.
164 *
165 * Because the total number of ICU mutexes is quite small, no effort has
166 * been made to squeeze every byte out of this struct.
167 */
168struct ICUMutex {
169 UMTX *owner; /* Points back to the UMTX corrsponding to this */
170 /* ICUMutex object. */
171
172 UBool heapAllocated; /* Set if this ICUMutex is heap allocated, and */
173 /* will need to be deleted. The global mutex */
174 /* is static on POSIX platforms; all others */
175 /* will be heap allocated. */
176
177 ICUMutex *next; /* All ICUMutexes are chained into a list so that */
178 /* they can be found and deleted by u_cleanup(). */
179
180 int32_t recursionCount; /* For debugging, detect recursive mutex locks. */
181
182 MUTEX_TYPE platformMutex; /* The underlying OS mutex being wrapped. */
183
184 UMTX userMutex; /* For use with u_setMutexFunctions operations, */
185 /* corresponds to platformMutex. */
186};
b75a7d8f
A
187
188
729e4ab9
A
189/* The global ICU mutex.
190 * For POSIX platforms, it gets a C style initialization, and is ready to use
191 * at program startup.
192 * For Windows, it will be lazily instantiated on first use.
193 */
194
195#if defined(POSIX)
196static UMTX globalUMTX;
197static ICUMutex globalMutex = {&globalUMTX, FALSE, NULL, 0, PLATFORM_MUTEX_INITIALIZER, NULL};
198static UMTX globalUMTX = &globalMutex;
199#else
200static UMTX globalUMTX = NULL;
201#endif
202
203/* Head of the list of all ICU mutexes.
204 * Linked list is through ICUMutex::next
205 * Modifications to the list are synchronized with the global mutex.
206 * The list is used by u_cleanup(), which needs to dispose of all of the ICU mutexes.
207 *
208 * The statically initialized global mutex on POSIX platforms does not get added to this
209 * mutex list, but that's not a problem - the global mutex gets special handling
210 * during u_cleanup().
211 */
212static ICUMutex *mutexListHead;
b75a7d8f 213
b75a7d8f 214
374ca955
A
215/*
216 * User mutex implementation functions. If non-null, call back to these rather than
729e4ab9 217 * directly using the system (Posix or Windows) APIs. See u_setMutexFunctions().
374ca955
A
218 * (declarations are in uclean.h)
219 */
220static UMtxInitFn *pMutexInitFn = NULL;
221static UMtxFn *pMutexDestroyFn = NULL;
222static UMtxFn *pMutexLockFn = NULL;
223static UMtxFn *pMutexUnlockFn = NULL;
224static const void *gMutexContext = NULL;
225
226
374ca955
A
227/*
228 * umtx_lock
229 */
b75a7d8f
A
230U_CAPI void U_EXPORT2
231umtx_lock(UMTX *mutex)
232{
729e4ab9
A
233 ICUMutex *m;
234
374ca955 235 if (mutex == NULL) {
729e4ab9 236 mutex = &globalUMTX;
b75a7d8f 237 }
729e4ab9
A
238 m = (ICUMutex *)*mutex;
239 if (m == NULL) {
240 /* See note on lazy initialization, above. We can get away with it here, with mutexes,
241 * where we couldn't with normal user level data.
242 */
374ca955 243 umtx_init(mutex);
729e4ab9 244 m = (ICUMutex *)*mutex;
b75a7d8f 245 }
729e4ab9 246 U_ASSERT(m->owner == mutex);
b75a7d8f 247
374ca955 248 if (pMutexLockFn != NULL) {
729e4ab9 249 (*pMutexLockFn)(gMutexContext, &m->userMutex);
374ca955 250 } else {
729e4ab9 251 PLATFORM_MUTEX_LOCK(&m->platformMutex);
374ca955 252 }
b75a7d8f 253
729e4ab9
A
254#if defined(U_DEBUG)
255 m->recursionCount++; /* Recursion causes deadlock on Unixes. */
256 U_ASSERT(m->recursionCount == 1); /* Recursion detection works on Windows. */
257 /* Assertion failure on non-Windows indicates a */
258 /* problem with the mutex implementation itself. */
259#endif
b75a7d8f
A
260}
261
374ca955
A
262
263
264/*
265 * umtx_unlock
266 */
b75a7d8f
A
267U_CAPI void U_EXPORT2
268umtx_unlock(UMTX* mutex)
269{
729e4ab9 270 ICUMutex *m;
374ca955 271 if(mutex == NULL) {
729e4ab9 272 mutex = &globalUMTX;
b75a7d8f 273 }
729e4ab9
A
274 m = (ICUMutex *)*mutex;
275 if (m == NULL) {
374ca955 276 U_ASSERT(FALSE); /* This mutex is not initialized. */
374ca955 277 return;
b75a7d8f 278 }
729e4ab9 279 U_ASSERT(m->owner == mutex);
b75a7d8f 280
729e4ab9
A
281#if defined (U_DEBUG)
282 m->recursionCount--;
283 U_ASSERT(m->recursionCount == 0); /* Detect unlock of an already unlocked mutex */
b75a7d8f
A
284#endif
285
374ca955 286 if (pMutexUnlockFn) {
729e4ab9 287 (*pMutexUnlockFn)(gMutexContext, &m->userMutex);
374ca955 288 } else {
729e4ab9 289 PLATFORM_MUTEX_UNLOCK(&m->platformMutex);
374ca955 290 }
b75a7d8f
A
291}
292
293
729e4ab9
A
294/* umtx_ct Allocate and initialize a new ICUMutex.
295 * If a non-null pointer is supplied, initialize an existing ICU Mutex.
b75a7d8f 296 */
729e4ab9
A
297static ICUMutex *umtx_ct(ICUMutex *m) {
298 if (m == NULL) {
299 m = (ICUMutex *)uprv_malloc(sizeof(ICUMutex));
300 m->heapAllocated = TRUE;
374ca955 301 }
729e4ab9
A
302 m->next = NULL; /* List of mutexes is maintained at a higher level. */
303 m->recursionCount = 0;
304 m->userMutex = NULL;
305 if (pMutexInitFn != NULL) {
306 UErrorCode status = U_ZERO_ERROR;
307 (*pMutexInitFn)(gMutexContext, &m->userMutex, &status);
308 U_ASSERT(U_SUCCESS(status));
309 } else {
310 PLATFORM_MUTEX_INIT(&m->platformMutex);
374ca955 311 }
729e4ab9 312 return m;
b75a7d8f 313}
b75a7d8f
A
314
315
729e4ab9
A
316/* umtx_dt Delete a ICUMutex. Destroy the underlying OS Platform mutex.
317 * Does not touch the linked list of ICU Mutexes.
318 */
319static void umtx_dt(ICUMutex *m) {
320 if (pMutexDestroyFn != NULL) {
321 (*pMutexDestroyFn)(gMutexContext, &m->userMutex);
322 m->userMutex = NULL;
323 } else {
324 PLATFORM_MUTEX_DESTROY(&m->platformMutex);
325 }
b75a7d8f 326
729e4ab9
A
327 if (m->heapAllocated) {
328 uprv_free(m);
329 }
330}
331
b75a7d8f 332
374ca955 333U_CAPI void U_EXPORT2
729e4ab9
A
334umtx_init(UMTX *mutex) {
335 ICUMutex *m = NULL;
336 void *originalValue;
b75a7d8f 337
729e4ab9
A
338 if (*mutex != NULL) {
339 /* Mutex is already initialized.
340 * Multiple umtx_init()s of a UMTX by other ICU code are explicitly permitted.
341 */
342 return;
343 }
344#if defined(POSIX)
345 if (mutex == &globalUMTX) {
346 m = &globalMutex;
347 }
374ca955 348#endif
374ca955 349
729e4ab9
A
350 m = umtx_ct(m);
351 originalValue = SYNC_COMPARE_AND_SWAP(mutex, NULL, m);
352 if (originalValue != NULL) {
353 umtx_dt(m);
354 return;
b75a7d8f 355 }
729e4ab9
A
356
357 m->owner = mutex;
358
359 /* Hook the new mutex into the list of all ICU mutexes, so that we can find and
360 * delete it for u_cleanup().
361 */
362
363 umtx_lock(NULL);
364 m->next = mutexListHead;
365 mutexListHead = m;
366 umtx_unlock(NULL);
367 return;
b75a7d8f
A
368}
369
374ca955
A
370
371/*
372 * umtx_destroy. Un-initialize a mutex, releasing any underlying resources
373 * that it may be holding. Destroying an already destroyed
374 * mutex has no effect. Unlike umtx_init(), this function
375 * is not thread safe; two threads must not concurrently try to
376 * destroy the same mutex.
377 */
b75a7d8f
A
378U_CAPI void U_EXPORT2
379umtx_destroy(UMTX *mutex) {
729e4ab9
A
380 ICUMutex *m;
381
382 /* No one should be deleting the global ICU mutex.
383 * (u_cleanup() does delete it, but does so explicitly, not by passing NULL)
384 */
385 U_ASSERT(mutex != NULL);
386 if (mutex == NULL) {
387 return;
b75a7d8f 388 }
374ca955 389
729e4ab9
A
390 m = (ICUMutex *)*mutex;
391 if (m == NULL) { /* Mutex not initialized, or already destroyed. */
b75a7d8f 392 return;
374ca955 393 }
b75a7d8f 394
729e4ab9
A
395 U_ASSERT(m->owner == mutex);
396 if (m->owner != mutex) {
397 return;
374ca955 398 }
b75a7d8f 399
729e4ab9
A
400 /* Remove this mutex from the linked list of mutexes. */
401 umtx_lock(NULL);
402 if (mutexListHead == m) {
403 mutexListHead = m->next;
404 } else {
405 ICUMutex *prev;
406 for (prev = mutexListHead; prev!=NULL && prev->next!=m; prev = prev->next);
407 /* Empty for loop body */
408 if (prev != NULL) {
409 prev->next = m->next;
374ca955 410 }
b75a7d8f 411 }
729e4ab9 412 umtx_unlock(NULL);
b75a7d8f 413
729e4ab9
A
414 umtx_dt(m); /* Delete the internal ICUMutex */
415 *mutex = NULL; /* Clear the caller's UMTX */
b75a7d8f
A
416}
417
418
b75a7d8f 419
374ca955
A
420U_CAPI void U_EXPORT2
421u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
422 UErrorCode *status) {
423 if (U_FAILURE(*status)) {
424 return;
425 }
b75a7d8f 426
374ca955
A
427 /* Can not set a mutex function to a NULL value */
428 if (i==NULL || d==NULL || l==NULL || u==NULL) {
429 *status = U_ILLEGAL_ARGUMENT_ERROR;
430 return;
431 }
b75a7d8f 432
374ca955
A
433 /* If ICU is not in an initial state, disallow this operation. */
434 if (cmemory_inUse()) {
435 *status = U_INVALID_STATE_ERROR;
436 return;
437 }
729e4ab9
A
438
439 /* Kill any existing global mutex. POSIX platforms have a global mutex
440 * even before any other part of ICU is initialized.
441 */
442 umtx_destroy(&globalUMTX);
b75a7d8f 443
374ca955
A
444 /* Swap in the mutex function pointers. */
445 pMutexInitFn = i;
446 pMutexDestroyFn = d;
447 pMutexLockFn = l;
448 pMutexUnlockFn = u;
449 gMutexContext = context;
729e4ab9
A
450
451#if defined (POSIX)
452 /* POSIX platforms must have a pre-initialized global mutex
453 * to allow other mutexes to initialize safely. */
454 umtx_init(&globalUMTX);
455#endif
456}
457
458
459/* synchronized compare and swap function, for use when OS or compiler built-in
460 * equivalents aren't available.
461 *
462 * This operation relies on the ICU global mutex for synchronization.
463 *
464 * There are two cases where this function can be entered when the global mutex is not
465 * yet initialized - at the end u_cleanup(), and at the end of u_setMutexFunctions, both
466 * of which re-init the global mutex. But neither function is thread-safe, so the lack of
467 * synchronization at these points doesn't matter.
468 */
469static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) {
470 void *temp;
471 UBool needUnlock = FALSE;
472
473 if (globalUMTX != NULL) {
474 umtx_lock(&globalUMTX);
475 needUnlock = TRUE;
476 }
477
478 temp = *dest;
479 if (temp == oldval) {
480 *dest = newval;
481 }
482
483 if (needUnlock) {
484 umtx_unlock(&globalUMTX);
485 }
486 return temp;
b75a7d8f
A
487}
488
b75a7d8f 489
b75a7d8f 490
374ca955
A
491/*-----------------------------------------------------------------
492 *
493 * Atomic Increment and Decrement
494 * umtx_atomic_inc
495 * umtx_atomic_dec
496 *
497 *----------------------------------------------------------------*/
498
499/* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */
500static UMtxAtomicFn *pIncFn = NULL;
501static UMtxAtomicFn *pDecFn = NULL;
73c04bcf 502static const void *gIncDecContext = NULL;
b75a7d8f 503
729e4ab9 504static UMTX gIncDecMutex = NULL;
b75a7d8f
A
505
506U_CAPI int32_t U_EXPORT2
374ca955
A
507umtx_atomic_inc(int32_t *p) {
508 int32_t retVal;
509 if (pIncFn) {
510 retVal = (*pIncFn)(gIncDecContext, p);
511 } else {
73c04bcf 512 #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
374ca955 513 retVal = InterlockedIncrement((LONG*)p);
73c04bcf
A
514 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
515 retVal = OSAtomicIncrement32Barrier(p);
729e4ab9
A
516 #elif (U_HAVE_GCC_ATOMICS == 1)
517 retVal = __sync_add_and_fetch(p, 1);
374ca955
A
518 #elif defined (POSIX) && ICU_USE_THREADS == 1
519 umtx_lock(&gIncDecMutex);
520 retVal = ++(*p);
521 umtx_unlock(&gIncDecMutex);
522 #else
523 /* Unknown Platform, or ICU thread support compiled out. */
524 retVal = ++(*p);
525 #endif
526 }
527 return retVal;
528}
b75a7d8f 529
374ca955
A
530U_CAPI int32_t U_EXPORT2
531umtx_atomic_dec(int32_t *p) {
532 int32_t retVal;
533 if (pDecFn) {
534 retVal = (*pDecFn)(gIncDecContext, p);
535 } else {
73c04bcf 536 #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
374ca955 537 retVal = InterlockedDecrement((LONG*)p);
73c04bcf
A
538 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
539 retVal = OSAtomicDecrement32Barrier(p);
729e4ab9
A
540 #elif (U_HAVE_GCC_ATOMICS == 1)
541 retVal = __sync_sub_and_fetch(p, 1);
374ca955
A
542 #elif defined (POSIX) && ICU_USE_THREADS == 1
543 umtx_lock(&gIncDecMutex);
544 retVal = --(*p);
545 umtx_unlock(&gIncDecMutex);
546 #else
547 /* Unknown Platform, or ICU thread support compiled out. */
548 retVal = --(*p);
549 #endif
550 }
b75a7d8f
A
551 return retVal;
552}
553
b75a7d8f 554
b75a7d8f 555
374ca955
A
556U_CAPI void U_EXPORT2
557u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
558 UErrorCode *status) {
374ca955
A
559 if (U_FAILURE(*status)) {
560 return;
561 }
562 /* Can not set a mutex function to a NULL value */
563 if (ip==NULL || dp==NULL) {
564 *status = U_ILLEGAL_ARGUMENT_ERROR;
565 return;
566 }
567 /* If ICU is not in an initial state, disallow this operation. */
568 if (cmemory_inUse()) {
569 *status = U_INVALID_STATE_ERROR;
570 return;
571 }
572
573 pIncFn = ip;
574 pDecFn = dp;
73c04bcf
A
575 gIncDecContext = context;
576
577#if !U_RELEASE
578 {
579 int32_t testInt = 0;
580 U_ASSERT(umtx_atomic_inc(&testInt) == 1); /* Sanity Check. Do the functions work at all? */
581 U_ASSERT(testInt == 1);
582 U_ASSERT(umtx_atomic_dec(&testInt) == 0);
583 U_ASSERT(testInt == 0);
584 }
585#endif
b75a7d8f
A
586}
587
b75a7d8f 588
b75a7d8f 589
374ca955
A
590/*
591 * Mutex Cleanup Function
592 *
593 * Destroy the global mutex(es), and reset the mutex function callback pointers.
594 */
595U_CFUNC UBool umtx_cleanup(void) {
729e4ab9
A
596 ICUMutex *thisMutex = NULL;
597 ICUMutex *nextMutex = NULL;
598
599 /* Extra, do-nothing function call to suppress compiler warnings on platforms where
600 * mutexed_compare_and_swap is not otherwise used. */
601 mutexed_compare_and_swap(&globalUMTX, NULL, NULL);
602
603 /* Delete all of the ICU mutexes. Do the global mutex last because it is used during
604 * the umtx_destroy operation of other mutexes.
605 */
606 for (thisMutex=mutexListHead; thisMutex!=NULL; thisMutex=nextMutex) {
607 UMTX *umtx = thisMutex->owner;
608 nextMutex = thisMutex->next;
609 U_ASSERT(*umtx = (void *)thisMutex);
610 if (umtx != &globalUMTX) {
611 umtx_destroy(umtx);
612 }
613 }
614 umtx_destroy(&globalUMTX);
615
374ca955
A
616 pMutexInitFn = NULL;
617 pMutexDestroyFn = NULL;
618 pMutexLockFn = NULL;
619 pMutexUnlockFn = NULL;
620 gMutexContext = NULL;
374ca955
A
621 pIncFn = NULL;
622 pDecFn = NULL;
73c04bcf 623 gIncDecContext = NULL;
374ca955
A
624 gIncDecMutex = NULL;
625
729e4ab9
A
626#if defined (POSIX)
627 /* POSIX platforms must come out of u_cleanup() with a functioning global mutex
628 * to permit the safe resumption of use of ICU in multi-threaded environments.
629 */
630 umtx_init(&globalUMTX);
374ca955 631#endif
374ca955
A
632 return TRUE;
633}
b75a7d8f
A
634
635