]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/mutex.cpp
ICU-491.11.2.tar.gz
[apple/icu.git] / icuSources / common / mutex.cpp
index fa2dbd00662fb8f2c80a7176754596665053703f..e1e502d4ad90974fbf87e0b47e4dae2a814c4927 100644 (file)
 /*
 /*
- **********************************************************************
- *   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 "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