• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getInstance(InstantiatorFn * instantiator,const void * context,void * & duplicate,UErrorCode & errorCode)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  */
getInstance(InstantiatorFn * instantiator,const void * context,void * & duplicate,UErrorCode & errorCode)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 
reset()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