Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1997-2009, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *
      9 * File umutex.c
     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 
     21 #include "unicode/utypes.h"
     22 #include "uassert.h"
     23 #include "ucln_cmn.h"
     24 
     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 
     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)
     33 #if defined(__STRICT_ANSI__)
     34 #define UPRV_REMAP_INLINE
     35 #define inline
     36 #endif
     37 #include <libkern/OSAtomic.h>
     38 #define USE_MAC_OS_ATOMIC_INCREMENT 1
     39 #if defined(UPRV_REMAP_INLINE)
     40 #undef inline
     41 #undef UPRV_REMAP_INLINE
     42 #endif
     43 #endif
     44 #endif
     45 
     46 /* Assume POSIX, and modify as necessary below */
     47 #define POSIX
     48 
     49 #if defined(U_WINDOWS)
     50 #undef POSIX
     51 #endif
     52 #if defined(macintosh)
     53 #undef POSIX
     54 #endif
     55 #if defined(OS2)
     56 #undef POSIX
     57 #endif
     58 
     59 #if defined(POSIX) && (ICU_USE_THREADS==1)
     60 # include <pthread.h> /* must be first, so that we get the multithread versions of things. */
     61 
     62 #endif /* POSIX && (ICU_USE_THREADS==1) */
     63 
     64 #ifdef U_WINDOWS
     65 # define WIN32_LEAN_AND_MEAN
     66 # define VC_EXTRALEAN
     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 
     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
     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  *
     87  *
     88  *   The solution for the global mutex init is platform dependent.
     89  *   On POSIX systems, plain C-style initialization can be used on a mutex, with the
     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
     97  *   swap it in as the global mutex while avoid problems with race conditions.
     98  */
     99 
    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  */
    106 
    107 
    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)
    117 
    118 
    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)
    127 
    128 
    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)
    142 #endif
    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 
    155 #endif
    156 
    157 /*  Forward declarations */
    158 static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval);
    159 typedef 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  */
    168 struct 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 };
    187 
    188 
    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)
    196 static UMTX  globalUMTX;
    197 static ICUMutex globalMutex = {&globalUMTX, FALSE, NULL, 0, PLATFORM_MUTEX_INITIALIZER, NULL};
    198 static UMTX  globalUMTX = &globalMutex;
    199 #else
    200 static 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  */
    212 static ICUMutex *mutexListHead;
    213 
    214 
    215 /*
    216  *  User mutex implementation functions.  If non-null, call back to these rather than
    217  *  directly using the system (Posix or Windows) APIs.  See u_setMutexFunctions().
    218  *    (declarations are in uclean.h)
    219  */
    220 static UMtxInitFn    *pMutexInitFn    = NULL;
    221 static UMtxFn        *pMutexDestroyFn = NULL;
    222 static UMtxFn        *pMutexLockFn    = NULL;
    223 static UMtxFn        *pMutexUnlockFn  = NULL;
    224 static const void    *gMutexContext   = NULL;
    225 
    226 
    227 /*
    228  *   umtx_lock
    229  */
    230 U_CAPI void  U_EXPORT2
    231 umtx_lock(UMTX *mutex)
    232 {
    233     ICUMutex *m;
    234 
    235     if (mutex == NULL) {
    236         mutex = &globalUMTX;
    237     }
    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          */
    243         umtx_init(mutex);
    244         m = (ICUMutex *)*mutex;
    245     }
    246     U_ASSERT(m->owner == mutex);
    247 
    248     if (pMutexLockFn != NULL) {
    249         (*pMutexLockFn)(gMutexContext, &m->userMutex);
    250     } else {
    251         PLATFORM_MUTEX_LOCK(&m->platformMutex);
    252     }
    253 
    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
    260 }
    261 
    262 
    263 
    264 /*
    265  * umtx_unlock
    266  */
    267 U_CAPI void  U_EXPORT2
    268 umtx_unlock(UMTX* mutex)
    269 {
    270     ICUMutex *m;
    271     if(mutex == NULL) {
    272         mutex = &globalUMTX;
    273     }
    274     m = (ICUMutex *)*mutex;
    275     if (m == NULL) {
    276         U_ASSERT(FALSE);  /* This mutex is not initialized.     */
    277         return;
    278     }
    279     U_ASSERT(m->owner == mutex);
    280 
    281 #if defined (U_DEBUG)
    282     m->recursionCount--;
    283     U_ASSERT(m->recursionCount == 0);  /* Detect unlock of an already unlocked mutex */
    284 #endif
    285 
    286     if (pMutexUnlockFn) {
    287         (*pMutexUnlockFn)(gMutexContext, &m->userMutex);
    288     } else {
    289         PLATFORM_MUTEX_UNLOCK(&m->platformMutex);
    290     }
    291 }
    292 
    293 
    294 /* umtx_ct   Allocate and initialize a new ICUMutex.
    295  *           If a non-null pointer is supplied, initialize an existing ICU Mutex.
    296  */
    297 static ICUMutex *umtx_ct(ICUMutex *m) {
    298     if (m == NULL) {
    299         m = (ICUMutex *)uprv_malloc(sizeof(ICUMutex));
    300         m->heapAllocated = TRUE;
    301     }
    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);
    311     }
    312     return m;
    313 }
    314 
    315 
    316 /* umtx_dt   Delete a ICUMutex.  Destroy the underlying OS Platform mutex.
    317  *           Does not touch the linked list of ICU Mutexes.
    318  */
    319 static 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     }
    326 
    327     if (m->heapAllocated) {
    328         uprv_free(m);
    329     }
    330 }
    331 
    332 
    333 U_CAPI void  U_EXPORT2
    334 umtx_init(UMTX *mutex) {
    335     ICUMutex *m = NULL;
    336     void *originalValue;
    337 
    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     }
    348 #endif
    349 
    350     m = umtx_ct(m);
    351     originalValue = SYNC_COMPARE_AND_SWAP(mutex, NULL, m);
    352     if (originalValue != NULL) {
    353         umtx_dt(m);
    354         return;
    355     }
    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;
    368 }
    369 
    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  */
    378 U_CAPI void  U_EXPORT2
    379 umtx_destroy(UMTX *mutex) {
    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;
    388     }
    389 
    390     m = (ICUMutex *)*mutex;
    391     if (m == NULL) {  /* Mutex not initialized, or already destroyed.  */
    392         return;
    393     }
    394 
    395     U_ASSERT(m->owner == mutex);
    396     if (m->owner != mutex) {
    397         return;
    398     }
    399 
    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;
    410         }
    411     }
    412     umtx_unlock(NULL);
    413 
    414     umtx_dt(m);        /* Delete the internal ICUMutex   */
    415     *mutex = NULL;     /* Clear the caller's UMTX        */
    416 }
    417 
    418 
    419 
    420 U_CAPI void U_EXPORT2
    421 u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
    422                     UErrorCode *status) {
    423     if (U_FAILURE(*status)) {
    424         return;
    425     }
    426 
    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     }
    432 
    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     }
    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);
    443 
    444     /* Swap in the mutex function pointers.  */
    445     pMutexInitFn    = i;
    446     pMutexDestroyFn = d;
    447     pMutexLockFn    = l;
    448     pMutexUnlockFn  = u;
    449     gMutexContext   = context;
    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  */
    469 static 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;
    487 }
    488 
    489 
    490 
    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.  */
    500 static UMtxAtomicFn  *pIncFn = NULL;
    501 static UMtxAtomicFn  *pDecFn = NULL;
    502 static const void *gIncDecContext  = NULL;
    503 
    504 static UMTX    gIncDecMutex = NULL;
    505 
    506 U_CAPI int32_t U_EXPORT2
    507 umtx_atomic_inc(int32_t *p)  {
    508     int32_t retVal;
    509     if (pIncFn) {
    510         retVal = (*pIncFn)(gIncDecContext, p);
    511     } else {
    512         #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
    513             retVal = InterlockedIncrement((LONG*)p);
    514         #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
    515             retVal = OSAtomicIncrement32Barrier(p);
    516         #elif (U_HAVE_GCC_ATOMICS == 1)
    517             retVal = __sync_add_and_fetch(p, 1);
    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 }
    529 
    530 U_CAPI int32_t U_EXPORT2
    531 umtx_atomic_dec(int32_t *p) {
    532     int32_t retVal;
    533     if (pDecFn) {
    534         retVal = (*pDecFn)(gIncDecContext, p);
    535     } else {
    536         #if defined (U_WINDOWS) && ICU_USE_THREADS == 1
    537             retVal = InterlockedDecrement((LONG*)p);
    538         #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
    539             retVal = OSAtomicDecrement32Barrier(p);
    540         #elif (U_HAVE_GCC_ATOMICS == 1)
    541             retVal = __sync_sub_and_fetch(p, 1);
    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     }
    551     return retVal;
    552 }
    553 
    554 
    555 
    556 U_CAPI void U_EXPORT2
    557 u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
    558                                 UErrorCode *status) {
    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;
    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
    586 }
    587 
    588 
    589 
    590 /*
    591  *  Mutex Cleanup Function
    592  *
    593  *      Destroy the global mutex(es), and reset the mutex function callback pointers.
    594  */
    595 U_CFUNC UBool umtx_cleanup(void) {
    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 
    616     pMutexInitFn    = NULL;
    617     pMutexDestroyFn = NULL;
    618     pMutexLockFn    = NULL;
    619     pMutexUnlockFn  = NULL;
    620     gMutexContext   = NULL;
    621     pIncFn          = NULL;
    622     pDecFn          = NULL;
    623     gIncDecContext  = NULL;
    624     gIncDecMutex    = NULL;
    625 
    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);
    631 #endif
    632     return TRUE;
    633 }
    634 
    635 
    636