1 /* 2 ******************************************************************************* 3 * 4 * Copyright (C) 2008-2011, International Business Machines 5 * Corporation and others. All Rights Reserved. 6 * 7 ******************************************************************************* 8 * file name: mutex.cpp 9 * encoding: US-ASCII 10 * tab size: 8 (not used) 11 * indentation:4 12 */ 13 14 #include "unicode/utypes.h" 15 #include "mutex.h" 16 #include "uassert.h" 17 18 U_NAMESPACE_BEGIN 19 20 void *SimpleSingleton::getInstance(InstantiatorFn *instantiator, const void *context, 21 void *&duplicate, 22 UErrorCode &errorCode) { 23 duplicate=NULL; 24 if(U_FAILURE(errorCode)) { 25 return NULL; 26 } 27 // TODO: With atomicops.h: void *instance = (void*)Acquire_Load(&fInstance); 28 // and remove UMTX_ACQUIRE_BARRIER below. 29 void *instance=ANNOTATE_UNPROTECTED_READ(fInstance); 30 UMTX_ACQUIRE_BARRIER; 31 ANNOTATE_HAPPENS_AFTER(&fInstance); 32 if(instance!=NULL) { 33 return instance; 34 } 35 36 // Attempt to create the instance. 37 // If a race occurs, then the losing thread will assign its new instance 38 // to the "duplicate" parameter, and the caller deletes it. 39 instance=instantiator(context, errorCode); 40 UMTX_RELEASE_BARRIER; // Release-barrier before fInstance=instance; 41 Mutex mutex; 42 if(fInstance==NULL && U_SUCCESS(errorCode)) { 43 U_ASSERT(instance!=NULL); 44 ANNOTATE_HAPPENS_BEFORE(&fInstance); 45 // TODO: With atomicops.h: Release_Store(&fInstance, (AtomicWord)instance); 46 // and remove UMTX_RELEASE_BARRIER above. 47 fInstance=instance; 48 } else { 49 duplicate=instance; 50 } 51 return fInstance; 52 } 53 54 /* 55 * Three states: 56 * 57 * Initial state: Instance creation not attempted yet. 58 * fInstance=NULL && U_SUCCESS(fErrorCode) 59 * 60 * Instance creation succeeded: 61 * fInstance!=NULL && U_SUCCESS(fErrorCode) 62 * 63 * Instance creation failed: 64 * fInstance=NULL && U_FAILURE(fErrorCode) 65 * We will not attempt again to create the instance. 66 * 67 * fInstance changes at most once. 68 * fErrorCode changes at most twice (intial->failed->succeeded). 69 */ 70 void *TriStateSingleton::getInstance(InstantiatorFn *instantiator, const void *context, 71 void *&duplicate, 72 UErrorCode &errorCode) { 73 duplicate=NULL; 74 if(U_FAILURE(errorCode)) { 75 return NULL; 76 } 77 // TODO: With atomicops.h: void *instance = (void*)Acquire_Load(&fInstance); 78 // and remove UMTX_ACQUIRE_BARRIER below. 79 void *instance=ANNOTATE_UNPROTECTED_READ(fInstance); 80 UMTX_ACQUIRE_BARRIER; 81 ANNOTATE_HAPPENS_AFTER(&fInstance); 82 if(instance!=NULL) { 83 // instance was created 84 return instance; 85 } 86 87 // The read access to fErrorCode is thread-unsafe, but harmless because 88 // at worst multiple threads race to each create a new instance, 89 // and all losing threads delete their duplicates. 90 UErrorCode localErrorCode=ANNOTATE_UNPROTECTED_READ(fErrorCode); 91 if(U_FAILURE(localErrorCode)) { 92 // instance creation failed 93 errorCode=localErrorCode; 94 return NULL; 95 } 96 97 // First attempt to create the instance. 98 // If a race occurs, then the losing thread will assign its new instance 99 // to the "duplicate" parameter, and the caller deletes it. 100 instance=instantiator(context, errorCode); 101 UMTX_RELEASE_BARRIER; // Release-barrier before fInstance=instance; 102 Mutex mutex; 103 if(fInstance==NULL && U_SUCCESS(errorCode)) { 104 // instance creation newly succeeded 105 U_ASSERT(instance!=NULL); 106 ANNOTATE_HAPPENS_BEFORE(&fInstance); 107 // TODO: With atomicops.h: Release_Store(&fInstance, (AtomicWord)instance); 108 // and remove UMTX_RELEASE_BARRIER above. 109 fInstance=instance; 110 // Set fErrorCode on the off-chance that a previous instance creation failed. 111 fErrorCode=errorCode; 112 // Completed state transition: initial->succeeded, or failed->succeeded. 113 } else { 114 // Record a duplicate if we lost the race, or 115 // if we got an instance but its creation failed anyway. 116 duplicate=instance; 117 if(fInstance==NULL && U_SUCCESS(fErrorCode) && U_FAILURE(errorCode)) { 118 // instance creation newly failed 119 fErrorCode=errorCode; 120 // Completed state transition: initial->failed. 121 } 122 } 123 return fInstance; 124 } 125 126 void TriStateSingleton::reset() { 127 fInstance=NULL; 128 fErrorCode=U_ZERO_ERROR; 129 } 130 131 #if UCONFIG_NO_SERVICE 132 133 /* If UCONFIG_NO_SERVICE, then there is no invocation of Mutex elsewhere in 134 common, so add one here to force an export */ 135 static Mutex *aMutex = 0; 136 137 /* UCONFIG_NO_SERVICE */ 138 #endif 139 140 U_NAMESPACE_END 141