X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b75a7d8f3b4adbae880cab104ce2c6a50eee4db2..ba516feee23ef0c2b810ac6365e88f33807caaa8:/icuSources/common/mutex.cpp?ds=sidebyside diff --git a/icuSources/common/mutex.cpp b/icuSources/common/mutex.cpp index fa2dbd00..e1e502d4 100644 --- a/icuSources/common/mutex.cpp +++ b/icuSources/common/mutex.cpp @@ -1,34 +1,140 @@ /* - ********************************************************************** - * Copyright (C) 1997-2002, International Business Machines - * Corporation and others. All Rights Reserved. - ********************************************************************** +******************************************************************************* +* +* Copyright (C) 2008-2011, International Business Machines +* Corporation and others. All Rights Reserved. +* +******************************************************************************* +* file name: mutex.cpp +* encoding: US-ASCII +* tab size: 8 (not used) +* indentation:4 */ +#include "unicode/utypes.h" #include "mutex.h" -#include "ucln_cmn.h" +#include "uassert.h" -/* Initialize the global mutex only when we can use it. */ -#if (ICU_USE_THREADS == 1) +U_NAMESPACE_BEGIN + +void *SimpleSingleton::getInstance(InstantiatorFn *instantiator, const void *context, + void *&duplicate, + UErrorCode &errorCode) { + duplicate=NULL; + if(U_FAILURE(errorCode)) { + return NULL; + } + // TODO: With atomicops.h: void *instance = (void*)Acquire_Load(&fInstance); + // and remove UMTX_ACQUIRE_BARRIER below. + void *instance=ANNOTATE_UNPROTECTED_READ(fInstance); + UMTX_ACQUIRE_BARRIER; + ANNOTATE_HAPPENS_AFTER(&fInstance); + if(instance!=NULL) { + return instance; + } + + // Attempt to create the instance. + // If a race occurs, then the losing thread will assign its new instance + // to the "duplicate" parameter, and the caller deletes it. + instance=instantiator(context, errorCode); + UMTX_RELEASE_BARRIER; // Release-barrier before fInstance=instance; + Mutex mutex; + if(fInstance==NULL && U_SUCCESS(errorCode)) { + U_ASSERT(instance!=NULL); + ANNOTATE_HAPPENS_BEFORE(&fInstance); + // TODO: With atomicops.h: Release_Store(&fInstance, (AtomicWord)instance); + // and remove UMTX_RELEASE_BARRIER above. + fInstance=instance; + } else { + duplicate=instance; + } + return fInstance; +} /* - * NOTE: This function replicates functionality from the start - * u_init(). Any changes must be made in both places. - * TODO: combine them. + * Three states: + * + * Initial state: Instance creation not attempted yet. + * fInstance=NULL && U_SUCCESS(fErrorCode) + * + * Instance creation succeeded: + * fInstance!=NULL && U_SUCCESS(fErrorCode) + * + * Instance creation failed: + * fInstance=NULL && U_FAILURE(fErrorCode) + * We will not attempt again to create the instance. * - * This function runs only during C++ static initialization. + * fInstance changes at most once. + * fErrorCode changes at most twice (intial->failed->succeeded). */ -static int GlobalMutexInitialize() -{ - UErrorCode status = U_ZERO_ERROR; - - umtx_init(NULL); - ucnv_init(&status); - ures_init(&status); - return 0; +void *TriStateSingleton::getInstance(InstantiatorFn *instantiator, const void *context, + void *&duplicate, + UErrorCode &errorCode) { + duplicate=NULL; + if(U_FAILURE(errorCode)) { + return NULL; + } + // TODO: With atomicops.h: void *instance = (void*)Acquire_Load(&fInstance); + // and remove UMTX_ACQUIRE_BARRIER below. + void *instance=ANNOTATE_UNPROTECTED_READ(fInstance); + UMTX_ACQUIRE_BARRIER; + ANNOTATE_HAPPENS_AFTER(&fInstance); + if(instance!=NULL) { + // instance was created + return instance; + } + + // The read access to fErrorCode is thread-unsafe, but harmless because + // at worst multiple threads race to each create a new instance, + // and all losing threads delete their duplicates. + UErrorCode localErrorCode=ANNOTATE_UNPROTECTED_READ(fErrorCode); + if(U_FAILURE(localErrorCode)) { + // instance creation failed + errorCode=localErrorCode; + return NULL; + } + + // First attempt to create the instance. + // If a race occurs, then the losing thread will assign its new instance + // to the "duplicate" parameter, and the caller deletes it. + instance=instantiator(context, errorCode); + UMTX_RELEASE_BARRIER; // Release-barrier before fInstance=instance; + Mutex mutex; + if(fInstance==NULL && U_SUCCESS(errorCode)) { + // instance creation newly succeeded + U_ASSERT(instance!=NULL); + ANNOTATE_HAPPENS_BEFORE(&fInstance); + // TODO: With atomicops.h: Release_Store(&fInstance, (AtomicWord)instance); + // and remove UMTX_RELEASE_BARRIER above. + fInstance=instance; + // Set fErrorCode on the off-chance that a previous instance creation failed. + fErrorCode=errorCode; + // Completed state transition: initial->succeeded, or failed->succeeded. + } else { + // Record a duplicate if we lost the race, or + // if we got an instance but its creation failed anyway. + duplicate=instance; + if(fInstance==NULL && U_SUCCESS(fErrorCode) && U_FAILURE(errorCode)) { + // instance creation newly failed + fErrorCode=errorCode; + // Completed state transition: initial->failed. + } + } + return fInstance; } -static int initializesGlobalMutex = GlobalMutexInitialize(); +void TriStateSingleton::reset() { + fInstance=NULL; + fErrorCode=U_ZERO_ERROR; +} + +#if UCONFIG_NO_SERVICE + +/* If UCONFIG_NO_SERVICE, then there is no invocation of Mutex elsewhere in + common, so add one here to force an export */ +static Mutex *aMutex = 0; -#endif /* ICU_USE_THREADS==1 */ +/* UCONFIG_NO_SERVICE */ +#endif +U_NAMESPACE_END