]>
Commit | Line | Data |
---|---|---|
57a6839d A |
1 | /* |
2 | ****************************************************************************** | |
2ca993e8 | 3 | * Copyright (C) 2015-2016, International Business Machines |
57a6839d A |
4 | * Corporation and others. All Rights Reserved. |
5 | ****************************************************************************** | |
6 | * sharedobject.h | |
7 | */ | |
8 | ||
9 | #ifndef __SHAREDOBJECT_H__ | |
10 | #define __SHAREDOBJECT_H__ | |
11 | ||
12 | ||
13 | #include "unicode/uobject.h" | |
14 | #include "umutex.h" | |
15 | ||
16 | U_NAMESPACE_BEGIN | |
17 | ||
2ca993e8 A |
18 | /** |
19 | * Base class for unified cache exposing enough methods to SharedObject | |
20 | * instances to allow their addRef() and removeRef() methods to | |
21 | * update cache metrics. No other part of ICU, except for SharedObject, | |
22 | * should directly call the methods of this base class. | |
23 | */ | |
24 | class U_COMMON_API UnifiedCacheBase : public UObject { | |
25 | public: | |
26 | UnifiedCacheBase() { } | |
27 | ||
28 | /** | |
29 | * Called by addRefWhileHoldingCacheLock() when the hard reference count | |
30 | * of its instance goes from 0 to 1. | |
31 | */ | |
32 | virtual void incrementItemsInUse() const = 0; | |
33 | ||
34 | /** | |
35 | * Called by removeRef() when the hard reference count of its instance | |
36 | * drops from 1 to 0. | |
37 | */ | |
38 | virtual void decrementItemsInUseWithLockingAndEviction() const = 0; | |
39 | ||
40 | /** | |
41 | * Called by removeRefWhileHoldingCacheLock() when the hard reference | |
42 | * count of its instance drops from 1 to 0. | |
43 | */ | |
44 | virtual void decrementItemsInUse() const = 0; | |
45 | virtual ~UnifiedCacheBase(); | |
46 | private: | |
47 | UnifiedCacheBase(const UnifiedCacheBase &); | |
48 | UnifiedCacheBase &operator=(const UnifiedCacheBase &); | |
49 | }; | |
50 | ||
57a6839d A |
51 | /** |
52 | * Base class for shared, reference-counted, auto-deleted objects. | |
53 | * Subclasses can be immutable. | |
54 | * If they are mutable, then they must implement their copy constructor | |
55 | * so that copyOnWrite() works. | |
56 | * | |
57 | * Either stack-allocate, use LocalPointer, or use addRef()/removeRef(). | |
58 | * Sharing requires reference-counting. | |
59 | */ | |
60 | class U_COMMON_API SharedObject : public UObject { | |
61 | public: | |
b331163b | 62 | /** Initializes totalRefCount, softRefCount to 0. */ |
2ca993e8 A |
63 | SharedObject() : |
64 | totalRefCount(0), | |
65 | softRefCount(0), | |
66 | hardRefCount(0), | |
67 | cachePtr(NULL) {} | |
b331163b A |
68 | |
69 | /** Initializes totalRefCount, softRefCount to 0. */ | |
2ca993e8 A |
70 | SharedObject(const SharedObject &other) : |
71 | UObject(other), | |
72 | totalRefCount(0), | |
73 | softRefCount(0), | |
74 | hardRefCount(0), | |
75 | cachePtr(NULL) {} | |
57a6839d | 76 | |
57a6839d A |
77 | virtual ~SharedObject(); |
78 | ||
79 | /** | |
80 | * Increments the number of references to this object. Thread-safe. | |
81 | */ | |
2ca993e8 A |
82 | void addRef() const { addRef(FALSE); } |
83 | ||
84 | /** | |
85 | * Increments the number of references to this object. | |
86 | * Must be called only from within the internals of UnifiedCache and | |
87 | * only while the cache global mutex is held. | |
88 | */ | |
89 | void addRefWhileHoldingCacheLock() const { addRef(TRUE); } | |
57a6839d A |
90 | |
91 | /** | |
2ca993e8 A |
92 | * Increments the number of soft references to this object. |
93 | * Must be called only from within the internals of UnifiedCache and | |
94 | * only while the cache global mutex is held. | |
b331163b A |
95 | */ |
96 | void addSoftRef() const; | |
97 | ||
98 | /** | |
99 | * Decrements the number of references to this object. Thread-safe. | |
57a6839d | 100 | */ |
2ca993e8 | 101 | void removeRef() const { removeRef(FALSE); } |
57a6839d A |
102 | |
103 | /** | |
2ca993e8 A |
104 | * Decrements the number of references to this object. |
105 | * Must be called only from within the internals of UnifiedCache and | |
106 | * only while the cache global mutex is held. | |
107 | */ | |
108 | void removeRefWhileHoldingCacheLock() const { removeRef(TRUE); } | |
109 | ||
110 | /** | |
111 | * Decrements the number of soft references to this object. | |
112 | * Must be called only from within the internals of UnifiedCache and | |
113 | * only while the cache global mutex is held. | |
b331163b A |
114 | */ |
115 | void removeSoftRef() const; | |
116 | ||
117 | /** | |
118 | * Returns the reference counter including soft references. | |
119 | * Uses a memory barrier. | |
57a6839d A |
120 | */ |
121 | int32_t getRefCount() const; | |
122 | ||
b331163b | 123 | /** |
2ca993e8 A |
124 | * Returns the count of soft references only. |
125 | * Must be called only from within the internals of UnifiedCache and | |
126 | * only while the cache global mutex is held. | |
127 | */ | |
128 | int32_t getSoftRefCount() const { return softRefCount; } | |
129 | ||
130 | /** | |
131 | * Returns the count of hard references only. Uses a memory barrier. | |
b331163b A |
132 | * Used for testing the cache. Regular clients won't need this. |
133 | */ | |
2ca993e8 A |
134 | int32_t getHardRefCount() const; |
135 | ||
136 | /** | |
137 | * If noHardReferences() == TRUE then this object has no hard references. | |
138 | * Must be called only from within the internals of UnifiedCache. | |
139 | */ | |
140 | inline UBool noHardReferences() const { return getHardRefCount() == 0; } | |
b331163b A |
141 | |
142 | /** | |
2ca993e8 A |
143 | * If hasHardReferences() == TRUE then this object has hard references. |
144 | * Must be called only from within the internals of UnifiedCache. | |
b331163b | 145 | */ |
2ca993e8 A |
146 | inline UBool hasHardReferences() const { return getHardRefCount() != 0; } |
147 | ||
148 | /** | |
149 | * If noSoftReferences() == TRUE then this object has no soft references. | |
150 | * Must be called only from within the internals of UnifiedCache and | |
151 | * only while the cache global mutex is held. | |
152 | */ | |
153 | UBool noSoftReferences() const { return (softRefCount == 0); } | |
b331163b A |
154 | |
155 | /** | |
156 | * Deletes this object if it has no references or soft references. | |
157 | */ | |
57a6839d A |
158 | void deleteIfZeroRefCount() const; |
159 | ||
2ca993e8 A |
160 | /** |
161 | * @internal For UnifedCache use only to register this object with itself. | |
162 | * Must be called before this object is exposed to multiple threads. | |
163 | */ | |
164 | void registerWithCache(const UnifiedCacheBase *ptr) const { | |
165 | cachePtr = ptr; | |
166 | } | |
167 | ||
57a6839d A |
168 | /** |
169 | * Returns a writable version of ptr. | |
170 | * If there is exactly one owner, then ptr itself is returned as a | |
171 | * non-const pointer. | |
172 | * If there are multiple owners, then ptr is replaced with a | |
173 | * copy-constructed clone, | |
174 | * and that is returned. | |
175 | * Returns NULL if cloning failed. | |
176 | * | |
177 | * T must be a subclass of SharedObject. | |
178 | */ | |
179 | template<typename T> | |
180 | static T *copyOnWrite(const T *&ptr) { | |
181 | const T *p = ptr; | |
182 | if(p->getRefCount() <= 1) { return const_cast<T *>(p); } | |
183 | T *p2 = new T(*p); | |
184 | if(p2 == NULL) { return NULL; } | |
185 | p->removeRef(); | |
186 | ptr = p2; | |
187 | p2->addRef(); | |
188 | return p2; | |
189 | } | |
190 | ||
191 | /** | |
192 | * Makes dest an owner of the object pointed to by src while adjusting | |
193 | * reference counts and deleting the previous object dest pointed to | |
194 | * if necessary. Before this call is made, dest must either be NULL or | |
b331163b | 195 | * be included in the reference count of the object it points to. |
57a6839d A |
196 | * |
197 | * T must be a subclass of SharedObject. | |
198 | */ | |
199 | template<typename T> | |
200 | static void copyPtr(const T *src, const T *&dest) { | |
201 | if(src != dest) { | |
202 | if(dest != NULL) { dest->removeRef(); } | |
203 | dest = src; | |
204 | if(src != NULL) { src->addRef(); } | |
205 | } | |
206 | } | |
207 | ||
208 | /** | |
b331163b | 209 | * Equivalent to copyPtr(NULL, dest). |
57a6839d A |
210 | */ |
211 | template<typename T> | |
212 | static void clearPtr(const T *&ptr) { | |
213 | if (ptr != NULL) { | |
214 | ptr->removeRef(); | |
215 | ptr = NULL; | |
216 | } | |
217 | } | |
218 | ||
219 | private: | |
b331163b | 220 | mutable u_atomic_int32_t totalRefCount; |
2ca993e8 A |
221 | |
222 | // Any thread modifying softRefCount must hold the global cache mutex | |
223 | mutable int32_t softRefCount; | |
224 | ||
225 | mutable u_atomic_int32_t hardRefCount; | |
226 | mutable const UnifiedCacheBase *cachePtr; | |
227 | void addRef(UBool withCacheLock) const; | |
228 | void removeRef(UBool withCacheLock) const; | |
229 | ||
57a6839d A |
230 | }; |
231 | ||
232 | U_NAMESPACE_END | |
233 | ||
234 | #endif |