/* ******************************************************************************* * * 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 "uassert.h" 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; } /* * 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) { 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; } 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; /* UCONFIG_NO_SERVICE */ #endif U_NAMESPACE_END