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     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     SharedObject() :
66             totalRefCount(0),
67             softRefCount(0),
68             hardRefCount(0),
69             cachePtr(NULL) {}
70 
71     /** Initializes totalRefCount, softRefCount to 0. */
72     SharedObject(const SharedObject &other) :
73             UObject(other),
74             totalRefCount(0),
75             softRefCount(0),
76             hardRefCount(0),
77             cachePtr(NULL) {}
78 
79     virtual ~SharedObject();
80 
81     /**
82      * Increments the number of references to this object. Thread-safe.
83      */
84     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     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     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     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     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     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     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     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     void registerWithCache(const UnifiedCacheBase *ptr) const {
167         cachePtr = ptr;
168     }
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     static T *copyOnWrite(const T *&ptr) {
183         const T *p = ptr;
184         if(p->getRefCount() <= 1) { return const_cast<T *>(p); }
185         T *p2 = new T(*p);
186         if(p2 == NULL) { return NULL; }
187         p->removeRef();
188         ptr = p2;
189         p2->addRef();
190         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     static void copyPtr(const T *src, const T *&dest) {
203         if(src != dest) {
204             if(dest != NULL) { dest->removeRef(); }
205             dest = src;
206             if(src != NULL) { src->addRef(); }
207         }
208     }
209 
210     /**
211      * Equivalent to copyPtr(NULL, dest).
212      */
213     template<typename T>
214     static void clearPtr(const T *&ptr) {
215         if (ptr != NULL) {
216             ptr->removeRef();
217             ptr = NULL;
218         }
219     }
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
237