X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/729e4ab9bc6618bc3d8a898e575df7f4019e29ca..ba516feee23ef0c2b810ac6365e88f33807caaa8:/icuSources/common/mutex.cpp?ds=sidebyside diff --git a/icuSources/common/mutex.cpp b/icuSources/common/mutex.cpp index 8da3c7e0..e1e502d4 100644 --- a/icuSources/common/mutex.cpp +++ b/icuSources/common/mutex.cpp @@ -1,7 +1,7 @@ /* ******************************************************************************* * -* Copyright (C) 2008-2010, International Business Machines +* Copyright (C) 2008-2011, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* @@ -13,6 +13,7 @@ #include "unicode/utypes.h" #include "mutex.h" +#include "uassert.h" U_NAMESPACE_BEGIN @@ -23,22 +24,49 @@ void *SimpleSingleton::getInstance(InstantiatorFn *instantiator, const void *con if(U_FAILURE(errorCode)) { return NULL; } - void *instance; - UMTX_CHECK(NULL, fInstance, instance); + // 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 { - instance=instantiator(context, errorCode); - Mutex mutex; - if(fInstance==NULL && U_SUCCESS(errorCode)) { - fInstance=instance; - } else { - duplicate=instance; - } - return fInstance; + duplicate=instance; } + return fInstance; } +/* + * 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. + * + * fInstance changes at most once. + * fErrorCode changes at most twice (intial->failed->succeeded). + */ void *TriStateSingleton::getInstance(InstantiatorFn *instantiator, const void *context, void *&duplicate, UErrorCode &errorCode) { @@ -46,37 +74,58 @@ void *TriStateSingleton::getInstance(InstantiatorFn *instantiator, const void *c if(U_FAILURE(errorCode)) { return NULL; } - int8_t haveInstance; - UMTX_CHECK(NULL, fHaveInstance, haveInstance); - if(haveInstance>0) { - return fInstance; // instance was created - } else if(haveInstance<0) { - errorCode=fErrorCode; // instance creation failed + // 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; - } else /* haveInstance==0 */ { - void *instance=instantiator(context, errorCode); - Mutex mutex; - if(fHaveInstance==0) { - if(U_SUCCESS(errorCode)) { - fInstance=instance; - instance=NULL; - fHaveInstance=1; - } else { - fErrorCode=errorCode; - fHaveInstance=-1; - } - } else { - errorCode=fErrorCode; - } + } + + // 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; - return fInstance; + if(fInstance==NULL && U_SUCCESS(fErrorCode) && U_FAILURE(errorCode)) { + // instance creation newly failed + fErrorCode=errorCode; + // Completed state transition: initial->failed. + } } + return fInstance; } void TriStateSingleton::reset() { fInstance=NULL; fErrorCode=U_ZERO_ERROR; - fHaveInstance=0; } #if UCONFIG_NO_SERVICE