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