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
18U_NAMESPACE_BEGIN
19
20void *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 */
70void *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
126void 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 */
135static Mutex *aMutex = 0;
136
137/* UCONFIG_NO_SERVICE */
138#endif
139
140U_NAMESPACE_END
141