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: UnifiedCacheBase()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. */ SharedObject()65 SharedObject() : 66 totalRefCount(0), 67 softRefCount(0), 68 hardRefCount(0), 69 cachePtr(NULL) {} 70 71 /** Initializes totalRefCount, softRefCount to 0. */ SharedObject(const SharedObject & other)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 */ addRef()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 */ addRefWhileHoldingCacheLock()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 */ removeRef()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 */ removeRefWhileHoldingCacheLock()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 */ getSoftRefCount()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 */ noHardReferences()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 */ hasHardReferences()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 */ noSoftReferences()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 */ registerWithCache(const UnifiedCacheBase * ptr)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> copyOnWrite(const T * & ptr)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> copyPtr(const T * src,const T * & dest)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> clearPtr(const T * & ptr)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