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