]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.c
ICU-491.11.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.c
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
3*
4388f060 4* Copyright (C) 1997-2011, 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
4388f060
A
30#if U_PLATFORM_HAS_WIN32_API
31 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
32# undef POSIX
33#elif U_PLATFORM_IMPLEMENTS_POSIX
34# define POSIX
35#else
36# undef POSIX
b75a7d8f
A
37#endif
38
b75a7d8f 39#if defined(POSIX) && (ICU_USE_THREADS==1)
b75a7d8f
A
40# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
41
b75a7d8f
A
42#endif /* POSIX && (ICU_USE_THREADS==1) */
43
4388f060 44#if U_PLATFORM_HAS_WIN32_API
b75a7d8f 45# define WIN32_LEAN_AND_MEAN
374ca955 46# define VC_EXTRALEAN
b75a7d8f
A
47# define NOUSER
48# define NOSERVICE
49# define NOIME
50# define NOMCX
51# include <windows.h>
52#endif
53
54#include "umutex.h"
55#include "cmemory.h"
56
374ca955
A
57/*
58 * A note on ICU Mutex Initialization and ICU startup:
59 *
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
729e4ab9
A
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.
66 *
374ca955
A
67 *
68 * The solution for the global mutex init is platform dependent.
729e4ab9 69 * On POSIX systems, plain C-style initialization can be used on a mutex, with the
374ca955
A
70 * macro PTHREAD_MUTEX_INITIALIZER. The mutex is then ready for use, without
71 * first calling pthread_mutex_init().
72 *
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
729e4ab9 77 * swap it in as the global mutex while avoid problems with race conditions.
374ca955
A
78 */
79
729e4ab9
A
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.
85 */
374ca955 86
374ca955 87
729e4ab9
A
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)
374ca955 97
b75a7d8f 98
4388f060 99#elif U_PLATFORM_HAS_WIN32_API
729e4ab9
A
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)
b75a7d8f 107
b75a7d8f 108
729e4ab9
A
109#elif defined(POSIX)
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)
119#else
120#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
121 mutexed_compare_and_swap(dest, newval, oldval)
374ca955 122#endif
729e4ab9
A
123
124
125#else
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)
134
b75a7d8f 135#endif
729e4ab9
A
136
137/* Forward declarations */
138static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval);
139typedef struct ICUMutex ICUMutex;
140
141/*
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.
144 *
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.
147 */
148struct ICUMutex {
149 UMTX *owner; /* Points back to the UMTX corrsponding to this */
150 /* ICUMutex object. */
151
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. */
156
157 ICUMutex *next; /* All ICUMutexes are chained into a list so that */
158 /* they can be found and deleted by u_cleanup(). */
159
160 int32_t recursionCount; /* For debugging, detect recursive mutex locks. */
161
162 MUTEX_TYPE platformMutex; /* The underlying OS mutex being wrapped. */
163
164 UMTX userMutex; /* For use with u_setMutexFunctions operations, */
165 /* corresponds to platformMutex. */
166};
b75a7d8f
A
167
168
729e4ab9
A
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.
173 */
174
175#if defined(POSIX)
176static UMTX globalUMTX;
177static ICUMutex globalMutex = {&globalUMTX, FALSE, NULL, 0, PLATFORM_MUTEX_INITIALIZER, NULL};
178static UMTX globalUMTX = &globalMutex;
179#else
180static UMTX globalUMTX = NULL;
181#endif
182
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.
187 *
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().
191 */
192static ICUMutex *mutexListHead;
b75a7d8f 193
b75a7d8f 194
374ca955
A
195/*
196 * User mutex implementation functions. If non-null, call back to these rather than
729e4ab9 197 * directly using the system (Posix or Windows) APIs. See u_setMutexFunctions().
374ca955
A
198 * (declarations are in uclean.h)
199 */
200static UMtxInitFn *pMutexInitFn = NULL;
201static UMtxFn *pMutexDestroyFn = NULL;
202static UMtxFn *pMutexLockFn = NULL;
203static UMtxFn *pMutexUnlockFn = NULL;
204static const void *gMutexContext = NULL;
205
206
374ca955
A
207/*
208 * umtx_lock
209 */
b75a7d8f
A
210U_CAPI void U_EXPORT2
211umtx_lock(UMTX *mutex)
212{
729e4ab9
A
213 ICUMutex *m;
214
374ca955 215 if (mutex == NULL) {
729e4ab9 216 mutex = &globalUMTX;
b75a7d8f 217 }
729e4ab9
A
218 m = (ICUMutex *)*mutex;
219 if (m == NULL) {
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.
222 */
374ca955 223 umtx_init(mutex);
729e4ab9 224 m = (ICUMutex *)*mutex;
b75a7d8f 225 }
729e4ab9 226 U_ASSERT(m->owner == mutex);
b75a7d8f 227
374ca955 228 if (pMutexLockFn != NULL) {
729e4ab9 229 (*pMutexLockFn)(gMutexContext, &m->userMutex);
374ca955 230 } else {
729e4ab9 231 PLATFORM_MUTEX_LOCK(&m->platformMutex);
374ca955 232 }
b75a7d8f 233
729e4ab9
A
234#if defined(U_DEBUG)
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. */
239#endif
b75a7d8f
A
240}
241
374ca955
A
242
243
244/*
245 * umtx_unlock
246 */
b75a7d8f
A
247U_CAPI void U_EXPORT2
248umtx_unlock(UMTX* mutex)
249{
729e4ab9 250 ICUMutex *m;
374ca955 251 if(mutex == NULL) {
729e4ab9 252 mutex = &globalUMTX;
b75a7d8f 253 }
729e4ab9
A
254 m = (ICUMutex *)*mutex;
255 if (m == NULL) {
374ca955 256 U_ASSERT(FALSE); /* This mutex is not initialized. */
374ca955 257 return;
b75a7d8f 258 }
729e4ab9 259 U_ASSERT(m->owner == mutex);
b75a7d8f 260
729e4ab9
A
261#if defined (U_DEBUG)
262 m->recursionCount--;
263 U_ASSERT(m->recursionCount == 0); /* Detect unlock of an already unlocked mutex */
b75a7d8f
A
264#endif
265
374ca955 266 if (pMutexUnlockFn) {
729e4ab9 267 (*pMutexUnlockFn)(gMutexContext, &m->userMutex);
374ca955 268 } else {
729e4ab9 269 PLATFORM_MUTEX_UNLOCK(&m->platformMutex);
374ca955 270 }
b75a7d8f
A
271}
272
273
729e4ab9
A
274/* umtx_ct Allocate and initialize a new ICUMutex.
275 * If a non-null pointer is supplied, initialize an existing ICU Mutex.
b75a7d8f 276 */
729e4ab9
A
277static ICUMutex *umtx_ct(ICUMutex *m) {
278 if (m == NULL) {
279 m = (ICUMutex *)uprv_malloc(sizeof(ICUMutex));
280 m->heapAllocated = TRUE;
374ca955 281 }
729e4ab9
A
282 m->next = NULL; /* List of mutexes is maintained at a higher level. */
283 m->recursionCount = 0;
284 m->userMutex = NULL;
285 if (pMutexInitFn != NULL) {
286 UErrorCode status = U_ZERO_ERROR;
287 (*pMutexInitFn)(gMutexContext, &m->userMutex, &status);
288 U_ASSERT(U_SUCCESS(status));
289 } else {
290 PLATFORM_MUTEX_INIT(&m->platformMutex);
374ca955 291 }
729e4ab9 292 return m;
b75a7d8f 293}
b75a7d8f
A
294
295
729e4ab9
A
296/* umtx_dt Delete a ICUMutex. Destroy the underlying OS Platform mutex.
297 * Does not touch the linked list of ICU Mutexes.
298 */
299static void umtx_dt(ICUMutex *m) {
300 if (pMutexDestroyFn != NULL) {
301 (*pMutexDestroyFn)(gMutexContext, &m->userMutex);
302 m->userMutex = NULL;
303 } else {
304 PLATFORM_MUTEX_DESTROY(&m->platformMutex);
305 }
b75a7d8f 306
729e4ab9
A
307 if (m->heapAllocated) {
308 uprv_free(m);
309 }
310}
311
b75a7d8f 312
374ca955 313U_CAPI void U_EXPORT2
729e4ab9
A
314umtx_init(UMTX *mutex) {
315 ICUMutex *m = NULL;
316 void *originalValue;
b75a7d8f 317
729e4ab9
A
318 if (*mutex != NULL) {
319 /* Mutex is already initialized.
320 * Multiple umtx_init()s of a UMTX by other ICU code are explicitly permitted.
321 */
322 return;
323 }
324#if defined(POSIX)
325 if (mutex == &globalUMTX) {
326 m = &globalMutex;
327 }
374ca955 328#endif
374ca955 329
729e4ab9
A
330 m = umtx_ct(m);
331 originalValue = SYNC_COMPARE_AND_SWAP(mutex, NULL, m);
332 if (originalValue != NULL) {
333 umtx_dt(m);
334 return;
b75a7d8f 335 }
729e4ab9
A
336
337 m->owner = mutex;
338
339 /* Hook the new mutex into the list of all ICU mutexes, so that we can find and
340 * delete it for u_cleanup().
341 */
342
343 umtx_lock(NULL);
344 m->next = mutexListHead;
345 mutexListHead = m;
346 umtx_unlock(NULL);
347 return;
b75a7d8f
A
348}
349
374ca955
A
350
351/*
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.
357 */
b75a7d8f
A
358U_CAPI void U_EXPORT2
359umtx_destroy(UMTX *mutex) {
729e4ab9
A
360 ICUMutex *m;
361
362 /* No one should be deleting the global ICU mutex.
363 * (u_cleanup() does delete it, but does so explicitly, not by passing NULL)
364 */
365 U_ASSERT(mutex != NULL);
366 if (mutex == NULL) {
367 return;
b75a7d8f 368 }
374ca955 369
729e4ab9
A
370 m = (ICUMutex *)*mutex;
371 if (m == NULL) { /* Mutex not initialized, or already destroyed. */
b75a7d8f 372 return;
374ca955 373 }
b75a7d8f 374
729e4ab9
A
375 U_ASSERT(m->owner == mutex);
376 if (m->owner != mutex) {
377 return;
374ca955 378 }
b75a7d8f 379
729e4ab9
A
380 /* Remove this mutex from the linked list of mutexes. */
381 umtx_lock(NULL);
382 if (mutexListHead == m) {
383 mutexListHead = m->next;
384 } else {
385 ICUMutex *prev;
386 for (prev = mutexListHead; prev!=NULL && prev->next!=m; prev = prev->next);
387 /* Empty for loop body */
388 if (prev != NULL) {
389 prev->next = m->next;
374ca955 390 }
b75a7d8f 391 }
729e4ab9 392 umtx_unlock(NULL);
b75a7d8f 393
729e4ab9
A
394 umtx_dt(m); /* Delete the internal ICUMutex */
395 *mutex = NULL; /* Clear the caller's UMTX */
b75a7d8f
A
396}
397
398
b75a7d8f 399
374ca955
A
400U_CAPI void U_EXPORT2
401u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
402 UErrorCode *status) {
403 if (U_FAILURE(*status)) {
404 return;
405 }
b75a7d8f 406
374ca955
A
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;
410 return;
411 }
b75a7d8f 412
374ca955
A
413 /* If ICU is not in an initial state, disallow this operation. */
414 if (cmemory_inUse()) {
415 *status = U_INVALID_STATE_ERROR;
416 return;
417 }
729e4ab9
A
418
419 /* Kill any existing global mutex. POSIX platforms have a global mutex
420 * even before any other part of ICU is initialized.
421 */
422 umtx_destroy(&globalUMTX);
b75a7d8f 423
374ca955
A
424 /* Swap in the mutex function pointers. */
425 pMutexInitFn = i;
426 pMutexDestroyFn = d;
427 pMutexLockFn = l;
428 pMutexUnlockFn = u;
429 gMutexContext = context;
729e4ab9
A
430
431#if defined (POSIX)
432 /* POSIX platforms must have a pre-initialized global mutex
433 * to allow other mutexes to initialize safely. */
434 umtx_init(&globalUMTX);
435#endif
436}
437
438
439/* synchronized compare and swap function, for use when OS or compiler built-in
440 * equivalents aren't available.
441 *
442 * This operation relies on the ICU global mutex for synchronization.
443 *
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.
448 */
449static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) {
450 void *temp;
451 UBool needUnlock = FALSE;
452
453 if (globalUMTX != NULL) {
454 umtx_lock(&globalUMTX);
455 needUnlock = TRUE;
456 }
457
458 temp = *dest;
459 if (temp == oldval) {
460 *dest = newval;
461 }
462
463 if (needUnlock) {
464 umtx_unlock(&globalUMTX);
465 }
466 return temp;
b75a7d8f
A
467}
468
b75a7d8f 469
b75a7d8f 470
374ca955
A
471/*-----------------------------------------------------------------
472 *
473 * Atomic Increment and Decrement
474 * umtx_atomic_inc
475 * umtx_atomic_dec
476 *
477 *----------------------------------------------------------------*/
478
479/* Pointers to user-supplied inc/dec functions. Null if no funcs have been set. */
480static UMtxAtomicFn *pIncFn = NULL;
481static UMtxAtomicFn *pDecFn = NULL;
73c04bcf 482static const void *gIncDecContext = NULL;
b75a7d8f 483
729e4ab9 484static UMTX gIncDecMutex = NULL;
b75a7d8f
A
485
486U_CAPI int32_t U_EXPORT2
374ca955
A
487umtx_atomic_inc(int32_t *p) {
488 int32_t retVal;
489 if (pIncFn) {
490 retVal = (*pIncFn)(gIncDecContext, p);
491 } else {
4388f060
A
492 #if !ICU_USE_THREADS
493 /* ICU thread support compiled out. */
494 retVal = ++(*p);
495 #elif U_PLATFORM_HAS_WIN32_API
374ca955 496 retVal = InterlockedIncrement((LONG*)p);
73c04bcf
A
497 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
498 retVal = OSAtomicIncrement32Barrier(p);
729e4ab9
A
499 #elif (U_HAVE_GCC_ATOMICS == 1)
500 retVal = __sync_add_and_fetch(p, 1);
4388f060 501 #elif defined (POSIX)
374ca955
A
502 umtx_lock(&gIncDecMutex);
503 retVal = ++(*p);
504 umtx_unlock(&gIncDecMutex);
505 #else
4388f060 506 /* Unknown Platform. */
374ca955
A
507 retVal = ++(*p);
508 #endif
509 }
510 return retVal;
511}
b75a7d8f 512
374ca955
A
513U_CAPI int32_t U_EXPORT2
514umtx_atomic_dec(int32_t *p) {
515 int32_t retVal;
516 if (pDecFn) {
517 retVal = (*pDecFn)(gIncDecContext, p);
518 } else {
4388f060
A
519 #if !ICU_USE_THREADS
520 /* ICU thread support compiled out. */
521 retVal = --(*p);
522 #elif U_PLATFORM_HAS_WIN32_API
374ca955 523 retVal = InterlockedDecrement((LONG*)p);
73c04bcf
A
524 #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
525 retVal = OSAtomicDecrement32Barrier(p);
729e4ab9
A
526 #elif (U_HAVE_GCC_ATOMICS == 1)
527 retVal = __sync_sub_and_fetch(p, 1);
4388f060 528 #elif defined (POSIX)
374ca955
A
529 umtx_lock(&gIncDecMutex);
530 retVal = --(*p);
531 umtx_unlock(&gIncDecMutex);
532 #else
4388f060 533 /* Unknown Platform. */
374ca955
A
534 retVal = --(*p);
535 #endif
536 }
b75a7d8f
A
537 return retVal;
538}
539
b75a7d8f 540
b75a7d8f 541
374ca955
A
542U_CAPI void U_EXPORT2
543u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
544 UErrorCode *status) {
374ca955
A
545 if (U_FAILURE(*status)) {
546 return;
547 }
548 /* Can not set a mutex function to a NULL value */
549 if (ip==NULL || dp==NULL) {
550 *status = U_ILLEGAL_ARGUMENT_ERROR;
551 return;
552 }
553 /* If ICU is not in an initial state, disallow this operation. */
554 if (cmemory_inUse()) {
555 *status = U_INVALID_STATE_ERROR;
556 return;
557 }
558
559 pIncFn = ip;
560 pDecFn = dp;
73c04bcf
A
561 gIncDecContext = context;
562
4388f060 563#if U_DEBUG
73c04bcf
A
564 {
565 int32_t testInt = 0;
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);
570 }
571#endif
b75a7d8f
A
572}
573
b75a7d8f 574
b75a7d8f 575
374ca955
A
576/*
577 * Mutex Cleanup Function
578 *
579 * Destroy the global mutex(es), and reset the mutex function callback pointers.
580 */
581U_CFUNC UBool umtx_cleanup(void) {
729e4ab9
A
582 ICUMutex *thisMutex = NULL;
583 ICUMutex *nextMutex = NULL;
584
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);
588
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.
591 */
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) {
597 umtx_destroy(umtx);
598 }
599 }
600 umtx_destroy(&globalUMTX);
601
374ca955
A
602 pMutexInitFn = NULL;
603 pMutexDestroyFn = NULL;
604 pMutexLockFn = NULL;
605 pMutexUnlockFn = NULL;
606 gMutexContext = NULL;
374ca955
A
607 pIncFn = NULL;
608 pDecFn = NULL;
73c04bcf 609 gIncDecContext = NULL;
374ca955
A
610 gIncDecMutex = NULL;
611
729e4ab9
A
612#if defined (POSIX)
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.
615 */
616 umtx_init(&globalUMTX);
374ca955 617#endif
374ca955
A
618 return TRUE;
619}
b75a7d8f
A
620
621