154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius/*
254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius******************************************************************************
354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*
41b7d32f919554dda9c193b32188251337bc756f1Fredrik Roubert*   Copyright (C) 1997-2015, International Business Machines
554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*   Corporation and others.  All Rights Reserved.
654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*
754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius******************************************************************************
854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*
954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius* File umutex.cpp
1054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*
1154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius* Modification History:
1254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*
1354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*   Date        Name        Description
1454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*   04/02/97    aliu        Creation.
1554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*   04/07/99    srl         updated
1654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*   05/13/99    stephen     Changed to umutex (from cmutex).
1754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
1854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius******************************************************************************
1954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius*/
2054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
2159d709d503bab6e2b61931737e662dd293b40578ccornelius#include "umutex.h"
2259d709d503bab6e2b61931737e662dd293b40578ccornelius
2354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "unicode/utypes.h"
2454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "uassert.h"
2559d709d503bab6e2b61931737e662dd293b40578ccornelius#include "cmemory.h"
2654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
2759d709d503bab6e2b61931737e662dd293b40578ccornelius
2859d709d503bab6e2b61931737e662dd293b40578ccornelius// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
2959d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic UMutex   globalMutex = U_MUTEX_INITIALIZER;
3059d709d503bab6e2b61931737e662dd293b40578ccornelius
3154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius/*
3254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
3354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius * platform independent set of mutex operations.  For internal ICU use only.
3454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius */
3554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
3659d709d503bab6e2b61931737e662dd293b40578ccornelius#if defined(U_USER_MUTEX_CPP)
3759d709d503bab6e2b61931737e662dd293b40578ccornelius// Build time user mutex hook: #include "U_USER_MUTEX_CPP"
3859d709d503bab6e2b61931737e662dd293b40578ccornelius#include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
3954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
4059d709d503bab6e2b61931737e662dd293b40578ccornelius#elif U_PLATFORM_HAS_WIN32_API
4154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
4259d709d503bab6e2b61931737e662dd293b40578ccornelius//-------------------------------------------------------------------------------------------
4359d709d503bab6e2b61931737e662dd293b40578ccornelius//
4459d709d503bab6e2b61931737e662dd293b40578ccornelius//    Windows Specific Definitions
4559d709d503bab6e2b61931737e662dd293b40578ccornelius//
4659d709d503bab6e2b61931737e662dd293b40578ccornelius//        Note: Cygwin (and possibly others) have both WIN32 and POSIX.
4759d709d503bab6e2b61931737e662dd293b40578ccornelius//              Prefer Win32 in these cases.  (Win32 comes ahead in the #if chain)
4859d709d503bab6e2b61931737e662dd293b40578ccornelius//
4959d709d503bab6e2b61931737e662dd293b40578ccornelius//-------------------------------------------------------------------------------------------
5054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
5159d709d503bab6e2b61931737e662dd293b40578ccornelius#if defined U_NO_PLATFORM_ATOMICS
5259d709d503bab6e2b61931737e662dd293b40578ccornelius#error ICU on Win32 requires support for low level atomic operations.
5359d709d503bab6e2b61931737e662dd293b40578ccornelius// Visual Studio, gcc, clang are OK. Shouldn't get here.
5454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#endif
5554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
5654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
5759d709d503bab6e2b61931737e662dd293b40578ccornelius// This function is called when a test of a UInitOnce::fState reveals that
5859d709d503bab6e2b61931737e662dd293b40578ccornelius//   initialization has not completed, that we either need to call the
5959d709d503bab6e2b61931737e662dd293b40578ccornelius//   function on this thread, or wait for some other thread to complete.
6054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius//
6159d709d503bab6e2b61931737e662dd293b40578ccornelius// The actual call to the init function is made inline by template code
6259d709d503bab6e2b61931737e662dd293b40578ccornelius//   that knows the C++ types involved. This function returns TRUE if
6359d709d503bab6e2b61931737e662dd293b40578ccornelius//   the caller needs to call the Init function.
6454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius//
6554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
6659d709d503bab6e2b61931737e662dd293b40578ccorneliusU_NAMESPACE_BEGIN
6754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
6859d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
6959d709d503bab6e2b61931737e662dd293b40578ccornelius    for (;;) {
7059d709d503bab6e2b61931737e662dd293b40578ccornelius        int32_t previousState = InterlockedCompareExchange(
71f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius#if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN) || defined(__clang__)
7259d709d503bab6e2b61931737e662dd293b40578ccornelius           (LONG volatile *) // this is the type given in the API doc for this function.
7359d709d503bab6e2b61931737e662dd293b40578ccornelius#endif
7459d709d503bab6e2b61931737e662dd293b40578ccornelius            &uio.fState,  //  Destination
7559d709d503bab6e2b61931737e662dd293b40578ccornelius            1,            //  Exchange Value
7659d709d503bab6e2b61931737e662dd293b40578ccornelius            0);           //  Compare value
7759d709d503bab6e2b61931737e662dd293b40578ccornelius
7859d709d503bab6e2b61931737e662dd293b40578ccornelius        if (previousState == 0) {
7959d709d503bab6e2b61931737e662dd293b40578ccornelius            return true;   // Caller will next call the init function.
8059d709d503bab6e2b61931737e662dd293b40578ccornelius                           // Current state == 1.
8159d709d503bab6e2b61931737e662dd293b40578ccornelius        } else if (previousState == 2) {
8259d709d503bab6e2b61931737e662dd293b40578ccornelius            // Another thread already completed the initialization.
8359d709d503bab6e2b61931737e662dd293b40578ccornelius            //   We can simply return FALSE, indicating no
8459d709d503bab6e2b61931737e662dd293b40578ccornelius            //   further action is needed by the caller.
8559d709d503bab6e2b61931737e662dd293b40578ccornelius            return FALSE;
8659d709d503bab6e2b61931737e662dd293b40578ccornelius        } else {
8759d709d503bab6e2b61931737e662dd293b40578ccornelius            // Another thread is currently running the initialization.
8859d709d503bab6e2b61931737e662dd293b40578ccornelius            // Wait until it completes.
8959d709d503bab6e2b61931737e662dd293b40578ccornelius            do {
9059d709d503bab6e2b61931737e662dd293b40578ccornelius                Sleep(1);
9159d709d503bab6e2b61931737e662dd293b40578ccornelius                previousState = umtx_loadAcquire(uio.fState);
9259d709d503bab6e2b61931737e662dd293b40578ccornelius            } while (previousState == 1);
9354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
9454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
9554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
9654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
9759d709d503bab6e2b61931737e662dd293b40578ccornelius// This function is called by the thread that ran an initialization function,
9859d709d503bab6e2b61931737e662dd293b40578ccornelius// just after completing the function.
9954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
10059d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
10159d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_storeRelease(uio.fState, 2);
10254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
10354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
10459d709d503bab6e2b61931737e662dd293b40578ccorneliusU_NAMESPACE_END
10554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
10659d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic void winMutexInit(CRITICAL_SECTION *cs) {
10759d709d503bab6e2b61931737e662dd293b40578ccornelius    InitializeCriticalSection(cs);
10859d709d503bab6e2b61931737e662dd293b40578ccornelius    return;
10959d709d503bab6e2b61931737e662dd293b40578ccornelius}
11054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
11154dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusU_CAPI void  U_EXPORT2
11254dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusumtx_lock(UMutex *mutex) {
11354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (mutex == NULL) {
11454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        mutex = &globalMutex;
11554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
11659d709d503bab6e2b61931737e662dd293b40578ccornelius    CRITICAL_SECTION *cs = &mutex->fCS;
11759d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
11859d709d503bab6e2b61931737e662dd293b40578ccornelius    EnterCriticalSection(cs);
11954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
12054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
12154dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusU_CAPI void  U_EXPORT2
12254dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusumtx_unlock(UMutex* mutex)
12354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius{
12454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (mutex == NULL) {
12554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        mutex = &globalMutex;
12654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
12759d709d503bab6e2b61931737e662dd293b40578ccornelius    LeaveCriticalSection(&mutex->fCS);
12854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
12954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
130f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
131f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI void U_EXPORT2
132f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusumtx_condBroadcast(UConditionVar *condition) {
133f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    // We require that the associated mutex be held by the caller,
134f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    //  so access to fWaitCount is protected and safe. No other thread can
135f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    //  call condWait() while we are here.
136f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (condition->fWaitCount == 0) {
137f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        return;
138f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
139f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    ResetEvent(condition->fExitGate);
140f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    SetEvent(condition->fEntryGate);
141f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
142f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
143f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI void U_EXPORT2
144f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusumtx_condSignal(UConditionVar *condition) {
145f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    // Function not implemented. There is no immediate requirement from ICU to have it.
146f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    // Once ICU drops support for Windows XP and Server 2003, ICU Condition Variables will be
147f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    // changed to be thin wrappers on native Windows CONDITION_VARIABLEs, and this function
148f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    // becomes trivial to provide.
149f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    U_ASSERT(FALSE);
150f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
151f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
152f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI void U_EXPORT2
153f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusumtx_condWait(UConditionVar *condition, UMutex *mutex) {
154f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (condition->fEntryGate == NULL) {
155f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // Note: because the associated mutex must be locked when calling
156f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        //       wait, we know that there can not be multiple threads
157f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        //       running here with the same condition variable.
158f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        //       Meaning that lazy initialization is safe.
159f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        U_ASSERT(condition->fExitGate == NULL);
160f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        condition->fEntryGate = CreateEvent(NULL,   // Security Attributes
161f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius                                            TRUE,   // Manual Reset
162f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius                                            FALSE,  // Initially reset
163f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius                                            NULL);  // Name.
164f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        U_ASSERT(condition->fEntryGate != NULL);
165f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        condition->fExitGate = CreateEvent(NULL, TRUE, TRUE, NULL);
166f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        U_ASSERT(condition->fExitGate != NULL);
167f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
168f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
169f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    condition->fWaitCount++;
170f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    umtx_unlock(mutex);
171f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    WaitForSingleObject(condition->fEntryGate, INFINITE);
172f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    umtx_lock(mutex);
173f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    condition->fWaitCount--;
174f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (condition->fWaitCount == 0) {
175f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // All threads that were waiting at the entry gate have woken up
176f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // and moved through. Shut the entry gate and open the exit gate.
177f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        ResetEvent(condition->fEntryGate);
178f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        SetEvent(condition->fExitGate);
179f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    } else {
180f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        umtx_unlock(mutex);
181f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        WaitForSingleObject(condition->fExitGate, INFINITE);
182f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        umtx_lock(mutex);
183f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
184f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
185f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
186f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
18759d709d503bab6e2b61931737e662dd293b40578ccornelius#elif U_PLATFORM_IMPLEMENTS_POSIX
18859d709d503bab6e2b61931737e662dd293b40578ccornelius
18959d709d503bab6e2b61931737e662dd293b40578ccornelius//-------------------------------------------------------------------------------------------
19054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius//
19159d709d503bab6e2b61931737e662dd293b40578ccornelius//  POSIX specific definitions
19254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius//
19359d709d503bab6e2b61931737e662dd293b40578ccornelius//-------------------------------------------------------------------------------------------
19459d709d503bab6e2b61931737e662dd293b40578ccornelius
19559d709d503bab6e2b61931737e662dd293b40578ccornelius# include <pthread.h>
19659d709d503bab6e2b61931737e662dd293b40578ccornelius
19759d709d503bab6e2b61931737e662dd293b40578ccornelius// Each UMutex consists of a pthread_mutex_t.
19859d709d503bab6e2b61931737e662dd293b40578ccornelius// All are statically initialized and ready for use.
19959d709d503bab6e2b61931737e662dd293b40578ccornelius// There is no runtime mutex initialization code needed.
20054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
20154dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusU_CAPI void  U_EXPORT2
20254dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusumtx_lock(UMutex *mutex) {
20354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (mutex == NULL) {
20454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        mutex = &globalMutex;
20554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
20659d709d503bab6e2b61931737e662dd293b40578ccornelius    int sysErr = pthread_mutex_lock(&mutex->fMutex);
20759d709d503bab6e2b61931737e662dd293b40578ccornelius    (void)sysErr;   // Suppress unused variable warnings.
20859d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(sysErr == 0);
20954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
21054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
21159d709d503bab6e2b61931737e662dd293b40578ccornelius
21254dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusU_CAPI void  U_EXPORT2
21354dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusumtx_unlock(UMutex* mutex)
21454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius{
21554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (mutex == NULL) {
21654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        mutex = &globalMutex;
21754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
21859d709d503bab6e2b61931737e662dd293b40578ccornelius    int sysErr = pthread_mutex_unlock(&mutex->fMutex);
21959d709d503bab6e2b61931737e662dd293b40578ccornelius    (void)sysErr;   // Suppress unused variable warnings.
22059d709d503bab6e2b61931737e662dd293b40578ccornelius    U_ASSERT(sysErr == 0);
22154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
22254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
223f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
224f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI void U_EXPORT2
225f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusumtx_condWait(UConditionVar *cond, UMutex *mutex) {
226f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (mutex == NULL) {
227f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        mutex = &globalMutex;
228f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
229f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    int sysErr = pthread_cond_wait(&cond->fCondition, &mutex->fMutex);
230f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    (void)sysErr;
231f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    U_ASSERT(sysErr == 0);
232f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
233f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
234f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI void U_EXPORT2
235f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusumtx_condBroadcast(UConditionVar *cond) {
236f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    int sysErr = pthread_cond_broadcast(&cond->fCondition);
237f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    (void)sysErr;
238f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    U_ASSERT(sysErr == 0);
239f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
240f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
241f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI void U_EXPORT2
242f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusumtx_condSignal(UConditionVar *cond) {
243f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    int sysErr = pthread_cond_signal(&cond->fCondition);
244f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    (void)sysErr;
245f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    U_ASSERT(sysErr == 0);
246f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
247f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
248f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
249f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
25059d709d503bab6e2b61931737e662dd293b40578ccorneliusU_NAMESPACE_BEGIN
25154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
25259d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
25359d709d503bab6e2b61931737e662dd293b40578ccorneliusstatic pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
25454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
25554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
25659d709d503bab6e2b61931737e662dd293b40578ccornelius// This function is called when a test of a UInitOnce::fState reveals that
25759d709d503bab6e2b61931737e662dd293b40578ccornelius//   initialization has not completed, that we either need to call the
25859d709d503bab6e2b61931737e662dd293b40578ccornelius//   function on this thread, or wait for some other thread to complete.
25959d709d503bab6e2b61931737e662dd293b40578ccornelius//
26059d709d503bab6e2b61931737e662dd293b40578ccornelius// The actual call to the init function is made inline by template code
26159d709d503bab6e2b61931737e662dd293b40578ccornelius//   that knows the C++ types involved. This function returns TRUE if
26259d709d503bab6e2b61931737e662dd293b40578ccornelius//   the caller needs to call the Init function.
26359d709d503bab6e2b61931737e662dd293b40578ccornelius//
26459d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API UBool U_EXPORT2
26559d709d503bab6e2b61931737e662dd293b40578ccorneliusumtx_initImplPreInit(UInitOnce &uio) {
26659d709d503bab6e2b61931737e662dd293b40578ccornelius    pthread_mutex_lock(&initMutex);
26759d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t state = uio.fState;
26859d709d503bab6e2b61931737e662dd293b40578ccornelius    if (state == 0) {
26959d709d503bab6e2b61931737e662dd293b40578ccornelius        umtx_storeRelease(uio.fState, 1);
27059d709d503bab6e2b61931737e662dd293b40578ccornelius        pthread_mutex_unlock(&initMutex);
27159d709d503bab6e2b61931737e662dd293b40578ccornelius        return TRUE;   // Caller will next call the init function.
27259d709d503bab6e2b61931737e662dd293b40578ccornelius    } else {
27359d709d503bab6e2b61931737e662dd293b40578ccornelius        while (uio.fState == 1) {
27459d709d503bab6e2b61931737e662dd293b40578ccornelius            // Another thread is currently running the initialization.
27559d709d503bab6e2b61931737e662dd293b40578ccornelius            // Wait until it completes.
27659d709d503bab6e2b61931737e662dd293b40578ccornelius            pthread_cond_wait(&initCondition, &initMutex);
27759d709d503bab6e2b61931737e662dd293b40578ccornelius        }
27859d709d503bab6e2b61931737e662dd293b40578ccornelius        pthread_mutex_unlock(&initMutex);
27959d709d503bab6e2b61931737e662dd293b40578ccornelius        U_ASSERT(uio.fState == 2);
28059d709d503bab6e2b61931737e662dd293b40578ccornelius        return FALSE;
28154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
28259d709d503bab6e2b61931737e662dd293b40578ccornelius}
28354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
28454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
28559d709d503bab6e2b61931737e662dd293b40578ccornelius
28659d709d503bab6e2b61931737e662dd293b40578ccornelius// This function is called by the thread that ran an initialization function,
28759d709d503bab6e2b61931737e662dd293b40578ccornelius// just after completing the function.
28859d709d503bab6e2b61931737e662dd293b40578ccornelius//   Some threads may be waiting on the condition, requiring the broadcast wakeup.
28959d709d503bab6e2b61931737e662dd293b40578ccornelius//   Some threads may be racing to test the fState variable outside of the mutex,
29059d709d503bab6e2b61931737e662dd293b40578ccornelius//   requiring the use of store/release when changing its value.
29159d709d503bab6e2b61931737e662dd293b40578ccornelius
29259d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API void U_EXPORT2
29359d709d503bab6e2b61931737e662dd293b40578ccorneliusumtx_initImplPostInit(UInitOnce &uio) {
29459d709d503bab6e2b61931737e662dd293b40578ccornelius    pthread_mutex_lock(&initMutex);
29559d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_storeRelease(uio.fState, 2);
29659d709d503bab6e2b61931737e662dd293b40578ccornelius    pthread_cond_broadcast(&initCondition);
29759d709d503bab6e2b61931737e662dd293b40578ccornelius    pthread_mutex_unlock(&initMutex);
29854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
29954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
30059d709d503bab6e2b61931737e662dd293b40578ccorneliusU_NAMESPACE_END
30154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
30259d709d503bab6e2b61931737e662dd293b40578ccornelius// End of POSIX specific umutex implementation.
30354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
30459d709d503bab6e2b61931737e662dd293b40578ccornelius#else  // Platform #define chain.
30554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
30659d709d503bab6e2b61931737e662dd293b40578ccornelius#error Unknown Platform
30754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
30859d709d503bab6e2b61931737e662dd293b40578ccornelius#endif  // Platform #define chain.
30954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
31054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
31159d709d503bab6e2b61931737e662dd293b40578ccornelius//-------------------------------------------------------------------------------
31259d709d503bab6e2b61931737e662dd293b40578ccornelius//
31359d709d503bab6e2b61931737e662dd293b40578ccornelius//   Atomic Operations, out-of-line versions.
31459d709d503bab6e2b61931737e662dd293b40578ccornelius//                      These are conditional, only defined if better versions
31559d709d503bab6e2b61931737e662dd293b40578ccornelius//                      were not available for the platform.
31659d709d503bab6e2b61931737e662dd293b40578ccornelius//
31759d709d503bab6e2b61931737e662dd293b40578ccornelius//                      These versions are platform neutral.
31859d709d503bab6e2b61931737e662dd293b40578ccornelius//
31959d709d503bab6e2b61931737e662dd293b40578ccornelius//--------------------------------------------------------------------------------
32054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
32159d709d503bab6e2b61931737e662dd293b40578ccornelius#if defined U_NO_PLATFORM_ATOMICS
32254dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic UMutex   gIncDecMutex = U_MUTEX_INITIALIZER;
32354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
32459d709d503bab6e2b61931737e662dd293b40578ccorneliusU_NAMESPACE_BEGIN
32559d709d503bab6e2b61931737e662dd293b40578ccornelius
32659d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API int32_t U_EXPORT2
32759d709d503bab6e2b61931737e662dd293b40578ccorneliusumtx_atomic_inc(u_atomic_int32_t *p)  {
32854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t retVal;
32959d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_lock(&gIncDecMutex);
33059d709d503bab6e2b61931737e662dd293b40578ccornelius    retVal = ++(*p);
33159d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_unlock(&gIncDecMutex);
33254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return retVal;
33354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
33454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
33559d709d503bab6e2b61931737e662dd293b40578ccornelius
33659d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API int32_t U_EXPORT2
33759d709d503bab6e2b61931737e662dd293b40578ccorneliusumtx_atomic_dec(u_atomic_int32_t *p) {
33854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t retVal;
33959d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_lock(&gIncDecMutex);
34059d709d503bab6e2b61931737e662dd293b40578ccornelius    retVal = --(*p);
34159d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_unlock(&gIncDecMutex);
34254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    return retVal;
34354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
34454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
34559d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API int32_t U_EXPORT2
34659d709d503bab6e2b61931737e662dd293b40578ccorneliusumtx_loadAcquire(u_atomic_int32_t &var) {
34759d709d503bab6e2b61931737e662dd293b40578ccornelius    int32_t val = var;
34859d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_lock(&gIncDecMutex);
34959d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_unlock(&gIncDecMutex);
35059d709d503bab6e2b61931737e662dd293b40578ccornelius    return val;
35159d709d503bab6e2b61931737e662dd293b40578ccornelius}
35259d709d503bab6e2b61931737e662dd293b40578ccornelius
35359d709d503bab6e2b61931737e662dd293b40578ccorneliusU_COMMON_API void U_EXPORT2
35459d709d503bab6e2b61931737e662dd293b40578ccorneliusumtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
35559d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_lock(&gIncDecMutex);
35659d709d503bab6e2b61931737e662dd293b40578ccornelius    umtx_unlock(&gIncDecMutex);
35759d709d503bab6e2b61931737e662dd293b40578ccornelius    var = val;
35859d709d503bab6e2b61931737e662dd293b40578ccornelius}
35954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
36059d709d503bab6e2b61931737e662dd293b40578ccorneliusU_NAMESPACE_END
36159d709d503bab6e2b61931737e662dd293b40578ccornelius#endif
36254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
36359d709d503bab6e2b61931737e662dd293b40578ccornelius//--------------------------------------------------------------------------
36459d709d503bab6e2b61931737e662dd293b40578ccornelius//
36559d709d503bab6e2b61931737e662dd293b40578ccornelius//  Deprecated functions for setting user mutexes.
36659d709d503bab6e2b61931737e662dd293b40578ccornelius//
36759d709d503bab6e2b61931737e662dd293b40578ccornelius//--------------------------------------------------------------------------
36854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
36959d709d503bab6e2b61931737e662dd293b40578ccorneliusU_DEPRECATED void U_EXPORT2
37059d709d503bab6e2b61931737e662dd293b40578ccorneliusu_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
37159d709d503bab6e2b61931737e662dd293b40578ccornelius                    UMtxFn *,  UMtxFn *, UErrorCode *status) {
37259d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_SUCCESS(*status)) {
37359d709d503bab6e2b61931737e662dd293b40578ccornelius        *status = U_UNSUPPORTED_ERROR;
37454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
37559d709d503bab6e2b61931737e662dd293b40578ccornelius    return;
37654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
37754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
37854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
37959d709d503bab6e2b61931737e662dd293b40578ccornelius
38059d709d503bab6e2b61931737e662dd293b40578ccorneliusU_DEPRECATED void U_EXPORT2
38159d709d503bab6e2b61931737e662dd293b40578ccorneliusu_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
38259d709d503bab6e2b61931737e662dd293b40578ccornelius                           UErrorCode *status) {
38359d709d503bab6e2b61931737e662dd293b40578ccornelius    if (U_SUCCESS(*status)) {
38459d709d503bab6e2b61931737e662dd293b40578ccornelius        *status = U_UNSUPPORTED_ERROR;
38559d709d503bab6e2b61931737e662dd293b40578ccornelius    }
38659d709d503bab6e2b61931737e662dd293b40578ccornelius    return;
38754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius}
388