Home | History | Annotate | Download | only in common
      1 // Copyright (C) 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