]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/umutex.cpp
ICU-59173.0.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.cpp
index a7299a5cfd1603721fb58d7b3f5608d3d03131da..77c17782677e91fae6ea44792d1cd09c02d5f188 100644 (file)
@@ -1,7 +1,9 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 ******************************************************************************
 *
-*   Copyright (C) 1997-2012, International Business Machines
+*   Copyright (C) 1997-2016, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 ******************************************************************************
 ******************************************************************************
 */
 
+#include "umutex.h"
+
 #include "unicode/utypes.h"
 #include "uassert.h"
-#include "ucln_cmn.h"
+#include "cmemory.h"
+
+
+// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
+static UMutex   globalMutex = U_MUTEX_INITIALIZER;
 
 /*
  * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
  * platform independent set of mutex operations.  For internal ICU use only.
  */
 
-#if U_PLATFORM_HAS_WIN32_API
-    /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
-#   undef POSIX
-#elif U_PLATFORM_IMPLEMENTS_POSIX
-#   define POSIX
-#else
-#   undef POSIX
-#endif
-
-#if defined(POSIX)
-# include <pthread.h> /* must be first, so that we get the multithread versions of things. */
-#endif /* POSIX */
-
-#if U_PLATFORM_HAS_WIN32_API
-# define WIN32_LEAN_AND_MEAN
-# define VC_EXTRALEAN
-# define NOUSER
-# define NOSERVICE
-# define NOIME
-# define NOMCX
-# include <windows.h>
-#endif
-
-#include "umutex.h"
-#include "cmemory.h"
+#if defined(U_USER_MUTEX_CPP)
+// Build time user mutex hook: #include "U_USER_MUTEX_CPP"
+#include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
 
-#if U_PLATFORM_HAS_WIN32_API
-#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
-            InterlockedCompareExchangePointer(dest, newval, oldval)
-
-#elif defined(POSIX)
-#if (U_HAVE_GCC_ATOMICS == 1)
-#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
-            __sync_val_compare_and_swap(dest, oldval, newval)
-#else
-#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
-            mutexed_compare_and_swap(dest, newval, oldval)
-#endif
+#elif U_PLATFORM_USES_ONLY_WIN32_API
 
-#else   
-// Unknown platform.  Note that user can still set mutex functions at run time.
-#define SYNC_COMPARE_AND_SWAP(dest, oldval, newval) \
-            mutexed_compare_and_swap(dest, newval, oldval)
+#if defined U_NO_PLATFORM_ATOMICS
+#error ICU on Win32 requires support for low level atomic operations.
+// Visual Studio, gcc, clang are OK. Shouldn't get here.
 #endif
 
-static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval);
 
-// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
-static UMutex   globalMutex = U_MUTEX_INITIALIZER;
-
-// Implementation mutex. Used for compare & swap when no intrinsic is available, and
-// for safe initialization of user defined mutexes.
-static UMutex   implMutex = U_MUTEX_INITIALIZER;      
-
-// List of all user mutexes that have been initialized.
-// Used to allow us to destroy them when cleaning up ICU.
-// Normal platform mutexes are not kept track of in this way - they survive until the process is shut down.
-// Normal platfrom mutexes don't allocate storage, so not cleaning them up won't trigger memory leak complaints.
+// This function is called when a test of a UInitOnce::fState reveals that
+//   initialization has not completed, that we either need to call the
+//   function on this thread, or wait for some other thread to complete.
 //
-// Note: putting this list in allocated memory would be awkward to arrange, because memory allocations
-//       are used as a flag to indicate that ICU has been initialized, and setting other ICU 
-//       override functions will no longer work.
+// The actual call to the init function is made inline by template code
+//   that knows the C++ types involved. This function returns TRUE if
+//   the caller needs to call the Init function.
 //
-static const int MUTEX_LIST_LIMIT = 100;
-static UMutex *gMutexList[MUTEX_LIST_LIMIT];
-static int gMutexListSize = 0;
-
-
-/*
- *  User mutex implementation functions.  If non-null, call back to these rather than
- *  directly using the system (Posix or Windows) APIs.  See u_setMutexFunctions().
- *    (declarations are in uclean.h)
- */
-static UMtxInitFn    *pMutexInitFn    = NULL;
-static UMtxFn        *pMutexDestroyFn = NULL;
-static UMtxFn        *pMutexLockFn    = NULL;
-static UMtxFn        *pMutexUnlockFn  = NULL;
-static const void    *gMutexContext   = NULL;
-
 
-// Clean up (undo) the effects of u_setMutexFunctions().
-//
-static void usrMutexCleanup() {
-    if (pMutexDestroyFn != NULL) {
-        for (int i = 0; i < gMutexListSize; i++) {
-            UMutex *m = gMutexList[i];
-            U_ASSERT(m->fInitialized);
-            (*pMutexDestroyFn)(gMutexContext, &m->fUserMutex);
-            m->fInitialized = FALSE;
+U_NAMESPACE_BEGIN
+
+U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
+    for (;;) {
+        int32_t previousState = InterlockedCompareExchange(
+            (LONG volatile *) // this is the type given in the API doc for this function.
+                &uio.fState,  //  Destination
+            1,            //  Exchange Value
+            0);           //  Compare value
+
+        if (previousState == 0) {
+            return true;   // Caller will next call the init function.
+                           // Current state == 1.
+        } else if (previousState == 2) {
+            // Another thread already completed the initialization.
+            //   We can simply return FALSE, indicating no
+            //   further action is needed by the caller.
+            return FALSE;
+        } else {
+            // Another thread is currently running the initialization.
+            // Wait until it completes.
+            do {
+                Sleep(1);
+                previousState = umtx_loadAcquire(uio.fState);
+            } while (previousState == 1);
         }
-        (*pMutexDestroyFn)(gMutexContext, &globalMutex.fUserMutex);
-        (*pMutexDestroyFn)(gMutexContext, &implMutex.fUserMutex);
     }
-    gMutexListSize  = 0;
-    pMutexInitFn    = NULL;
-    pMutexDestroyFn = NULL;
-    pMutexLockFn    = NULL;
-    pMutexUnlockFn  = NULL;
-    gMutexContext   = NULL;
 }
 
+// This function is called by the thread that ran an initialization function,
+// just after completing the function.
 
-/*
- * User mutex lock.
- *
- * User mutexes need to be initialized before they can be used. We use the impl mutex
- * to synchronize the initialization check. This could be sped up on platforms that
- * support alternate ways to safely check the initialization flag.
- *
- */
-static void usrMutexLock(UMutex *mutex) {
-    UErrorCode status = U_ZERO_ERROR;
-    if (!(mutex == &implMutex || mutex == &globalMutex)) {
-        umtx_lock(&implMutex);
-        if (!mutex->fInitialized) {
-            (*pMutexInitFn)(gMutexContext, &mutex->fUserMutex, &status);
-            U_ASSERT(U_SUCCESS(status));
-            mutex->fInitialized = TRUE;
-            U_ASSERT(gMutexListSize < MUTEX_LIST_LIMIT);
-            if (gMutexListSize < MUTEX_LIST_LIMIT) {
-                gMutexList[gMutexListSize] = mutex;
-                ++gMutexListSize;
-            }
-        }
-        umtx_unlock(&implMutex);
-    }
-    (*pMutexLockFn)(gMutexContext, &mutex->fUserMutex);
+U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
+    umtx_storeRelease(uio.fState, 2);
 }
-        
-
 
-#if defined(POSIX)
+U_NAMESPACE_END
 
-//
-// POSIX implementation of UMutex.
-//
-// Each UMutex has a corresponding pthread_mutex_t.
-// All are statically initialized and ready for use.
-// There is no runtime mutex initialization code needed.
+static void winMutexInit(CRITICAL_SECTION *cs) {
+    InitializeCriticalSection(cs);
+    return;
+}
 
 U_CAPI void  U_EXPORT2
 umtx_lock(UMutex *mutex) {
     if (mutex == NULL) {
         mutex = &globalMutex;
     }
-    if (pMutexLockFn) {
-        usrMutexLock(mutex);
-    } else {
-        #if U_DEBUG
-            // #if to avoid unused variable warnings in non-debug builds.
-            int sysErr = pthread_mutex_lock(&mutex->fMutex);
-            U_ASSERT(sysErr == 0);
-        #else
-            pthread_mutex_lock(&mutex->fMutex);
-        #endif
-    }
+    CRITICAL_SECTION *cs = &mutex->fCS;
+    umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
+    EnterCriticalSection(cs);
 }
 
-
 U_CAPI void  U_EXPORT2
 umtx_unlock(UMutex* mutex)
 {
     if (mutex == NULL) {
         mutex = &globalMutex;
     }
-    if (pMutexUnlockFn) {
-        (*pMutexUnlockFn)(gMutexContext, &mutex->fUserMutex);
+    LeaveCriticalSection(&mutex->fCS);
+}
+
+
+U_CAPI void U_EXPORT2
+umtx_condBroadcast(UConditionVar *condition) {
+    // We require that the associated mutex be held by the caller,
+    //  so access to fWaitCount is protected and safe. No other thread can
+    //  call condWait() while we are here.
+    if (condition->fWaitCount == 0) {
+        return;
+    }
+    ResetEvent(condition->fExitGate);
+    SetEvent(condition->fEntryGate);
+}
+
+U_CAPI void U_EXPORT2
+umtx_condSignal(UConditionVar *condition) {
+    // Function not implemented. There is no immediate requirement from ICU to have it.
+    // Once ICU drops support for Windows XP and Server 2003, ICU Condition Variables will be
+    // changed to be thin wrappers on native Windows CONDITION_VARIABLEs, and this function
+    // becomes trivial to provide.
+    U_ASSERT(FALSE);
+}
+
+U_CAPI void U_EXPORT2
+umtx_condWait(UConditionVar *condition, UMutex *mutex) {
+    if (condition->fEntryGate == NULL) {
+        // Note: because the associated mutex must be locked when calling
+        //       wait, we know that there can not be multiple threads
+        //       running here with the same condition variable.
+        //       Meaning that lazy initialization is safe.
+        U_ASSERT(condition->fExitGate == NULL);
+        condition->fEntryGate = CreateEvent(NULL,   // Security Attributes
+                                            TRUE,   // Manual Reset
+                                            FALSE,  // Initially reset
+                                            NULL);  // Name.
+        U_ASSERT(condition->fEntryGate != NULL);
+        condition->fExitGate = CreateEvent(NULL, TRUE, TRUE, NULL);
+        U_ASSERT(condition->fExitGate != NULL);
+    }
+
+    condition->fWaitCount++;
+    umtx_unlock(mutex);
+    WaitForSingleObject(condition->fEntryGate, INFINITE); 
+    umtx_lock(mutex);
+    condition->fWaitCount--;
+    if (condition->fWaitCount == 0) {
+        // All threads that were waiting at the entry gate have woken up
+        // and moved through. Shut the entry gate and open the exit gate.
+        ResetEvent(condition->fEntryGate);
+        SetEvent(condition->fExitGate);
     } else {
-        #if U_DEBUG
-            // #if to avoid unused variable warnings in non-debug builds.
-            int sysErr = pthread_mutex_unlock(&mutex->fMutex);
-            U_ASSERT(sysErr == 0);
-        #else
-            pthread_mutex_unlock(&mutex->fMutex);
-        #endif
+        umtx_unlock(mutex);
+        WaitForSingleObject(condition->fExitGate, INFINITE);
+        umtx_lock(mutex);
     }
 }
 
-#elif U_PLATFORM_HAS_WIN32_API
-//
-// Windows implementation of UMutex.
+
+#elif U_PLATFORM_IMPLEMENTS_POSIX
+
+//-------------------------------------------------------------------------------------------
 //
-// Each UMutex has a corresponding Windows CRITICAL_SECTION.
-// CRITICAL_SECTIONS must be initialized before use. This is done
-//   with a InitOnceExcuteOnce operation.
+//  POSIX specific definitions
 //
-// InitOnceExecuteOnce was introduced with Windows Vista. For now ICU
-// must support Windows XP, so we roll our own. ICU will switch to the
-// native Windows InitOnceExecuteOnce when possible.
-
-typedef UBool (*U_PINIT_ONCE_FN) (
-  U_INIT_ONCE     *initOnce,
-  void            *parameter,
-  void            **context
-);
-
-UBool u_InitOnceExecuteOnce(
-  U_INIT_ONCE     *initOnce,
-  U_PINIT_ONCE_FN initFn,
-  void            *parameter,
-  void            **context) {
-      for (;;) {
-          long previousState = InterlockedCompareExchange( 
-              &initOnce->fState,  //  Destination,
-              1,                  //  Exchange Value
-              0);                 //  Compare value
-          if (previousState == 2) {
-              // Initialization was already completed.
-              if (context != NULL) {
-                  *context = initOnce->fContext;
-              }
-              return TRUE;
-          }
-          if (previousState == 1) {
-              // Initialization is in progress in some other thread.
-              // Loop until it completes.
-              Sleep(1);
-              continue;
-          }
-           
-          // Initialization needed. Execute the callback function to do it.
-          U_ASSERT(previousState == 0);
-          U_ASSERT(initOnce->fState == 1);
-          UBool success = (*initFn)(initOnce, parameter, &initOnce->fContext);
-          U_ASSERT(success); // ICU is not supporting the failure case.
-
-          // Assign the state indicating that initialization has completed.
-          // Using InterlockedCompareExchange to do it ensures that all
-          // threads will have a consistent view of memory.
-          previousState = InterlockedCompareExchange(&initOnce->fState, 2, 1);
-          U_ASSERT(previousState == 1);
-          // Next loop iteration will see the initialization and return.
-      }
-};
-
-static UBool winMutexInit(U_INIT_ONCE *initOnce, void *param, void **context) {
-    UMutex *mutex = static_cast<UMutex *>(param);
-    U_ASSERT(sizeof(CRITICAL_SECTION) <= sizeof(mutex->fCS));
-    InitializeCriticalSection((CRITICAL_SECTION *)mutex->fCS);
-    return TRUE;
-}
+//-------------------------------------------------------------------------------------------
+
+# include <pthread.h>
+
+// Each UMutex consists of a pthread_mutex_t.
+// All are statically initialized and ready for use.
+// There is no runtime mutex initialization code needed.
 
-/*
- *   umtx_lock
- */
 U_CAPI void  U_EXPORT2
 umtx_lock(UMutex *mutex) {
     if (mutex == NULL) {
         mutex = &globalMutex;
     }
-    if (pMutexLockFn) {
-        usrMutexLock(mutex);
-    } else {
-        u_InitOnceExecuteOnce(&mutex->fInitOnce, winMutexInit, mutex, NULL);
-        EnterCriticalSection((CRITICAL_SECTION *)mutex->fCS);
-    }
+    int sysErr = pthread_mutex_lock(&mutex->fMutex);
+    (void)sysErr;   // Suppress unused variable warnings.
+    U_ASSERT(sysErr == 0);
 }
 
+
 U_CAPI void  U_EXPORT2
 umtx_unlock(UMutex* mutex)
 {
     if (mutex == NULL) {
         mutex = &globalMutex;
     }
-    if (pMutexUnlockFn) {
-        (*pMutexUnlockFn)(gMutexContext, &mutex->fUserMutex);
-    } else {
-        LeaveCriticalSection((CRITICAL_SECTION *)mutex->fCS);
+    int sysErr = pthread_mutex_unlock(&mutex->fMutex);
+    (void)sysErr;   // Suppress unused variable warnings.
+    U_ASSERT(sysErr == 0);
+}
+
+
+U_CAPI void U_EXPORT2
+umtx_condWait(UConditionVar *cond, UMutex *mutex) {
+    if (mutex == NULL) {
+        mutex = &globalMutex;
     }
+    int sysErr = pthread_cond_wait(&cond->fCondition, &mutex->fMutex);
+    (void)sysErr;
+    U_ASSERT(sysErr == 0);
 }
 
-#endif  // Windows Implementation
+U_CAPI void U_EXPORT2
+umtx_condBroadcast(UConditionVar *cond) {
+    int sysErr = pthread_cond_broadcast(&cond->fCondition);
+    (void)sysErr;
+    U_ASSERT(sysErr == 0);
+}
 
+U_CAPI void U_EXPORT2
+umtx_condSignal(UConditionVar *cond) {
+    int sysErr = pthread_cond_signal(&cond->fCondition);
+    (void)sysErr;
+    U_ASSERT(sysErr == 0);
+}
 
-U_CAPI void U_EXPORT2 
-u_setMutexFunctions(const void *context, UMtxInitFn *i, UMtxFn *d, UMtxFn *l, UMtxFn *u,
-                    UErrorCode *status) {
-    if (U_FAILURE(*status)) {
-        return;
-    }
 
-    /* Can not set a mutex function to a NULL value  */
-    if (i==NULL || d==NULL || l==NULL || u==NULL) {
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
-    }
 
-    /* If ICU is not in an initial state, disallow this operation. */
-    if (cmemory_inUse()) {
-        *status = U_INVALID_STATE_ERROR;
-        return;
-    }
+U_NAMESPACE_BEGIN
+
+static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
 
-    // Clean up any previously set user mutex functions.
-    // It's possible to call u_setMutexFunctions() more than once without without explicitly cleaning up,
-    // and the last call should take. Kind of a corner case, but it worked once, there is a test for
-    // it, so we keep it working. The global and impl mutexes will have been created by the
-    // previous u_setMutexFunctions(), and now need to be destroyed.
-
-    usrMutexCleanup();
-    
-    /* Swap in the mutex function pointers.  */
-    pMutexInitFn    = i;
-    pMutexDestroyFn = d;
-    pMutexLockFn    = l;
-    pMutexUnlockFn  = u;
-    gMutexContext   = context;
-    gMutexListSize  = 0;
-
-    /* Initialize the global and impl mutexes. Safe to do at this point because
-     * u_setMutexFunctions must be done in a single-threaded envioronment. Not thread safe.
-     */
-    (*pMutexInitFn)(gMutexContext, &globalMutex.fUserMutex, status);
-    globalMutex.fInitialized = TRUE;
-    (*pMutexInitFn)(gMutexContext, &implMutex.fUserMutex, status);
-    implMutex.fInitialized = TRUE;
+
+// This function is called when a test of a UInitOnce::fState reveals that
+//   initialization has not completed, that we either need to call the
+//   function on this thread, or wait for some other thread to complete.
+//
+// The actual call to the init function is made inline by template code
+//   that knows the C++ types involved. This function returns TRUE if
+//   the caller needs to call the Init function.
+//
+U_COMMON_API UBool U_EXPORT2
+umtx_initImplPreInit(UInitOnce &uio) {
+    pthread_mutex_lock(&initMutex);
+    int32_t state = uio.fState;
+    if (state == 0) {
+        umtx_storeRelease(uio.fState, 1);
+        pthread_mutex_unlock(&initMutex);
+        return TRUE;   // Caller will next call the init function.
+    } else {
+        while (uio.fState == 1) {
+            // Another thread is currently running the initialization.
+            // Wait until it completes.
+            pthread_cond_wait(&initCondition, &initMutex);
+        }
+        pthread_mutex_unlock(&initMutex);
+        U_ASSERT(uio.fState == 2);
+        return FALSE;
+    }
 }
 
 
 
-/*   synchronized compare and swap function, for use when OS or compiler built-in
- *   equivalents aren't available.
- */
-static void *mutexed_compare_and_swap(void **dest, void *newval, void *oldval) {
-    umtx_lock(&implMutex);
-    void *temp = *dest;
-    if (temp == oldval) {
-        *dest = newval;
-    }
-    umtx_unlock(&implMutex);
-    
-    return temp;
+// This function is called by the thread that ran an initialization function,
+// just after completing the function.
+//   Some threads may be waiting on the condition, requiring the broadcast wakeup.
+//   Some threads may be racing to test the fState variable outside of the mutex,
+//   requiring the use of store/release when changing its value.
+
+U_COMMON_API void U_EXPORT2
+umtx_initImplPostInit(UInitOnce &uio) {
+    pthread_mutex_lock(&initMutex);
+    umtx_storeRelease(uio.fState, 2);
+    pthread_cond_broadcast(&initCondition);
+    pthread_mutex_unlock(&initMutex);
 }
 
+U_NAMESPACE_END
 
+// End of POSIX specific umutex implementation.
 
-/*-----------------------------------------------------------------
- *
- *  Atomic Increment and Decrement
- *     umtx_atomic_inc
- *     umtx_atomic_dec
- *
- *----------------------------------------------------------------*/
+#else  // Platform #define chain.
 
-/* Pointers to user-supplied inc/dec functions.  Null if no funcs have been set.  */
-static UMtxAtomicFn  *pIncFn = NULL;
-static UMtxAtomicFn  *pDecFn = NULL;
-static const void *gIncDecContext  = NULL;
+#error Unknown Platform
 
-#if defined (POSIX) && (U_HAVE_GCC_ATOMICS == 0)
+#endif  // Platform #define chain.
+
+
+//-------------------------------------------------------------------------------
+//
+//   Atomic Operations, out-of-line versions.
+//                      These are conditional, only defined if better versions
+//                      were not available for the platform.
+//
+//                      These versions are platform neutral.
+//
+//--------------------------------------------------------------------------------
+
+#if defined U_NO_PLATFORM_ATOMICS
 static UMutex   gIncDecMutex = U_MUTEX_INITIALIZER;
-#endif
 
-U_CAPI int32_t U_EXPORT2
-umtx_atomic_inc(int32_t *p)  {
+U_NAMESPACE_BEGIN
+
+U_COMMON_API int32_t U_EXPORT2
+umtx_atomic_inc(u_atomic_int32_t *p)  {
     int32_t retVal;
-    if (pIncFn) {
-        retVal = (*pIncFn)(gIncDecContext, p);
-    } else {
-        #if U_PLATFORM_HAS_WIN32_API
-            retVal = InterlockedIncrement((LONG*)p);
-        #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
-            retVal = OSAtomicIncrement32Barrier(p);
-        #elif (U_HAVE_GCC_ATOMICS == 1)
-            retVal = __sync_add_and_fetch(p, 1);
-        #elif defined (POSIX)
-            umtx_lock(&gIncDecMutex);
-            retVal = ++(*p);
-            umtx_unlock(&gIncDecMutex);
-        #else
-            /* Unknown Platform. */
-            retVal = ++(*p);
-        #endif
-    }
+    umtx_lock(&gIncDecMutex);
+    retVal = ++(*p);
+    umtx_unlock(&gIncDecMutex);
     return retVal;
 }
 
-U_CAPI int32_t U_EXPORT2
-umtx_atomic_dec(int32_t *p) {
+
+U_COMMON_API int32_t U_EXPORT2
+umtx_atomic_dec(u_atomic_int32_t *p) {
     int32_t retVal;
-    if (pDecFn) {
-        retVal = (*pDecFn)(gIncDecContext, p);
-    } else {
-        #if U_PLATFORM_HAS_WIN32_API
-            retVal = InterlockedDecrement((LONG*)p);
-        #elif defined(USE_MAC_OS_ATOMIC_INCREMENT)
-            retVal = OSAtomicDecrement32Barrier(p);
-        #elif (U_HAVE_GCC_ATOMICS == 1)
-            retVal = __sync_sub_and_fetch(p, 1);
-        #elif defined (POSIX)
-            umtx_lock(&gIncDecMutex);
-            retVal = --(*p);
-            umtx_unlock(&gIncDecMutex);
-        #else
-            /* Unknown Platform. */
-            retVal = --(*p);
-        #endif
-    }
+    umtx_lock(&gIncDecMutex);
+    retVal = --(*p);
+    umtx_unlock(&gIncDecMutex);
     return retVal;
 }
 
+U_COMMON_API int32_t U_EXPORT2
+umtx_loadAcquire(u_atomic_int32_t &var) {
+    umtx_lock(&gIncDecMutex);
+    int32_t val = var;
+    umtx_unlock(&gIncDecMutex);
+    return val;
+}
 
+U_COMMON_API void U_EXPORT2
+umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
+    umtx_lock(&gIncDecMutex);
+    var = val;
+    umtx_unlock(&gIncDecMutex);
+}
 
-U_CAPI void U_EXPORT2
-u_setAtomicIncDecFunctions(const void *context, UMtxAtomicFn *ip, UMtxAtomicFn *dp,
-                                UErrorCode *status) {
-    if (U_FAILURE(*status)) {
-        return;
-    }
-    /* Can not set a mutex function to a NULL value  */
-    if (ip==NULL || dp==NULL) {
-        *status = U_ILLEGAL_ARGUMENT_ERROR;
-        return;
-    }
-    /* If ICU is not in an initial state, disallow this operation. */
-    if (cmemory_inUse()) {
-        *status = U_INVALID_STATE_ERROR;
-        return;
-    }
+U_NAMESPACE_END
+#endif
 
-    pIncFn = ip;
-    pDecFn = dp;
-    gIncDecContext = context;
-
-#if U_DEBUG
-    {
-        int32_t   testInt = 0;
-        U_ASSERT(umtx_atomic_inc(&testInt) == 1);     /* Sanity Check.    Do the functions work at all? */
-        U_ASSERT(testInt == 1);
-        U_ASSERT(umtx_atomic_dec(&testInt) == 0);
-        U_ASSERT(testInt == 0);
+//--------------------------------------------------------------------------
+//
+//  Deprecated functions for setting user mutexes.
+//
+//--------------------------------------------------------------------------
+
+U_DEPRECATED void U_EXPORT2
+u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
+                    UMtxFn *,  UMtxFn *, UErrorCode *status) {
+    if (U_SUCCESS(*status)) {
+        *status = U_UNSUPPORTED_ERROR;
     }
-#endif
+    return;
 }
 
 
-/*
- *  Mutex Cleanup Function
- *      Reset the mutex function callback pointers.
- *      Called from the global ICU u_cleanup() function.
- */
-U_CFUNC UBool umtx_cleanup(void) {
-    /* Extra, do-nothing function call to suppress compiler warnings on platforms where
-     *   mutexed_compare_and_swap is not otherwise used.  */
-    void *pv = &globalMutex;
-    mutexed_compare_and_swap(&pv, NULL, NULL);
-    usrMutexCleanup();
-           
-    pIncFn          = NULL;
-    pDecFn          = NULL;
-    gIncDecContext  = NULL;
-
-    return TRUE;
+
+U_DEPRECATED void U_EXPORT2
+u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
+                           UErrorCode *status) {
+    if (U_SUCCESS(*status)) {
+        *status = U_UNSUPPORTED_ERROR;
+    }
+    return;
 }