Home | History | Annotate | Download | only in common
      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