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