Home | History | Annotate | Download | only in common
      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:
     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. */
     63     SharedObject() :
     64             totalRefCount(0),
     65             softRefCount(0),
     66             hardRefCount(0),
     67             cachePtr(NULL) {}
     68 
     69     /** Initializes totalRefCount, softRefCount to 0. */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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>
    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>
    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>
    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