• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 * Copyright (C) 2015, International Business Machines
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 
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 UnifiedCacheBase : public UObject {
25 public:
UnifiedCacheBase()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 
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:
62     /** Initializes totalRefCount, softRefCount to 0. */
SharedObject()63     SharedObject() :
64             totalRefCount(0),
65             softRefCount(0),
66             hardRefCount(0),
67             cachePtr(NULL) {}
68 
69     /** Initializes totalRefCount, softRefCount to 0. */
SharedObject(const SharedObject & other)70     SharedObject(const SharedObject &other) :
71             UObject(other),
72             totalRefCount(0),
73             softRefCount(0),
74             hardRefCount(0),
75             cachePtr(NULL) {}
76 
77     virtual ~SharedObject();
78 
79     /**
80      * Increments the number of references to this object. Thread-safe.
81      */
addRef()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      */
addRefWhileHoldingCacheLock()89     void addRefWhileHoldingCacheLock() const { addRef(TRUE); }
90 
91     /**
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.
95      */
96     void addSoftRef() const;
97 
98     /**
99      * Decrements the number of references to this object. Thread-safe.
100      */
removeRef()101     void removeRef() const { removeRef(FALSE); }
102 
103     /**
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      */
removeRefWhileHoldingCacheLock()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.
114      */
115     void removeSoftRef() const;
116 
117     /**
118      * Returns the reference counter including soft references.
119      * Uses a memory barrier.
120      */
121     int32_t getRefCount() const;
122 
123     /**
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      */
getSoftRefCount()128     int32_t getSoftRefCount() const { return softRefCount; }
129 
130     /**
131      * Returns the count of hard references only. Uses a memory barrier.
132      * Used for testing the cache. Regular clients won't need this.
133      */
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      */
noHardReferences()140     inline UBool noHardReferences() const { return getHardRefCount() == 0; }
141 
142     /**
143      * If hasHardReferences() == TRUE then this object has hard references.
144      * Must be called only from within the internals of UnifiedCache.
145      */
hasHardReferences()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      */
noSoftReferences()153     UBool noSoftReferences() const { return (softRefCount == 0); }
154 
155     /**
156      * Deletes this object if it has no references or soft references.
157      */
158     void deleteIfZeroRefCount() const;
159 
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      */
registerWithCache(const UnifiedCacheBase * ptr)164     void registerWithCache(const UnifiedCacheBase *ptr) const {
165         cachePtr = ptr;
166     }
167 
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>
copyOnWrite(const T * & ptr)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
195      * be included in the reference count of the object it points to.
196      *
197      * T must be a subclass of SharedObject.
198      */
199     template<typename T>
copyPtr(const T * src,const T * & dest)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     /**
209      * Equivalent to copyPtr(NULL, dest).
210      */
211     template<typename T>
clearPtr(const T * & ptr)212     static void clearPtr(const T *&ptr) {
213         if (ptr != NULL) {
214             ptr->removeRef();
215             ptr = NULL;
216         }
217     }
218 
219 private:
220     mutable u_atomic_int32_t totalRefCount;
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 
230 };
231 
232 U_NAMESPACE_END
233 
234 #endif
235