Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2005 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "RefBase"
     18 
     19 #include <utils/RefBase.h>
     20 
     21 #include <utils/Atomic.h>
     22 #include <utils/CallStack.h>
     23 #include <utils/KeyedVector.h>
     24 #include <utils/Log.h>
     25 #include <utils/threads.h>
     26 
     27 #include <stdlib.h>
     28 #include <stdio.h>
     29 #include <typeinfo>
     30 #include <sys/types.h>
     31 #include <sys/stat.h>
     32 #include <fcntl.h>
     33 #include <unistd.h>
     34 
     35 // compile with refcounting debugging enabled
     36 #define DEBUG_REFS                      0
     37 #define DEBUG_REFS_ENABLED_BY_DEFAULT   1
     38 #define DEBUG_REFS_CALLSTACK_ENABLED    1
     39 
     40 // log all reference counting operations
     41 #define PRINT_REFS                      0
     42 
     43 // ---------------------------------------------------------------------------
     44 
     45 namespace android {
     46 
     47 #define INITIAL_STRONG_VALUE (1<<28)
     48 
     49 // ---------------------------------------------------------------------------
     50 
     51 class RefBase::weakref_impl : public RefBase::weakref_type
     52 {
     53 public:
     54     volatile int32_t    mStrong;
     55     volatile int32_t    mWeak;
     56     RefBase* const      mBase;
     57     volatile int32_t    mFlags;
     58 
     59 
     60 #if !DEBUG_REFS
     61 
     62     weakref_impl(RefBase* base)
     63         : mStrong(INITIAL_STRONG_VALUE)
     64         , mWeak(0)
     65         , mBase(base)
     66         , mFlags(0)
     67     {
     68     }
     69 
     70     void addStrongRef(const void* /*id*/) { }
     71     void removeStrongRef(const void* /*id*/) { }
     72     void addWeakRef(const void* /*id*/) { }
     73     void removeWeakRef(const void* /*id*/) { }
     74     void printRefs() const { }
     75     void trackMe(bool, bool) { }
     76 
     77 #else
     78 
     79     weakref_impl(RefBase* base)
     80         : mStrong(INITIAL_STRONG_VALUE)
     81         , mWeak(0)
     82         , mBase(base)
     83         , mFlags(0)
     84         , mStrongRefs(NULL)
     85         , mWeakRefs(NULL)
     86         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
     87         , mRetain(false)
     88     {
     89         //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
     90     }
     91 
     92     ~weakref_impl()
     93     {
     94         LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!");
     95         LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!");
     96     }
     97 
     98     void addStrongRef(const void* id)
     99     {
    100         addRef(&mStrongRefs, id, mStrong);
    101     }
    102 
    103     void removeStrongRef(const void* id)
    104     {
    105         if (!mRetain)
    106             removeRef(&mStrongRefs, id);
    107         else
    108             addRef(&mStrongRefs, id, -mStrong);
    109     }
    110 
    111     void addWeakRef(const void* id)
    112     {
    113         addRef(&mWeakRefs, id, mWeak);
    114     }
    115 
    116     void removeWeakRef(const void* id)
    117     {
    118         if (!mRetain)
    119             removeRef(&mWeakRefs, id);
    120         else
    121             addRef(&mWeakRefs, id, -mWeak);
    122     }
    123 
    124     void trackMe(bool track, bool retain)
    125     {
    126         mTrackEnabled = track;
    127         mRetain = retain;
    128     }
    129 
    130     void printRefs() const
    131     {
    132         String8 text;
    133 
    134         {
    135             AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex);
    136 
    137             char buf[128];
    138             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
    139             text.append(buf);
    140             printRefsLocked(&text, mStrongRefs);
    141             sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
    142             text.append(buf);
    143             printRefsLocked(&text, mWeakRefs);
    144         }
    145 
    146         {
    147             char name[100];
    148             snprintf(name, 100, "/data/%p.stack", this);
    149             int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
    150             if (rc >= 0) {
    151                 write(rc, text.string(), text.length());
    152                 close(rc);
    153                 LOGD("STACK TRACE for %p saved in %s", this, name);
    154             }
    155             else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
    156                       name, strerror(errno));
    157         }
    158     }
    159 
    160 private:
    161     struct ref_entry
    162     {
    163         ref_entry* next;
    164         const void* id;
    165 #if DEBUG_REFS_CALLSTACK_ENABLED
    166         CallStack stack;
    167 #endif
    168         int32_t ref;
    169     };
    170 
    171     void addRef(ref_entry** refs, const void* id, int32_t mRef)
    172     {
    173         if (mTrackEnabled) {
    174             AutoMutex _l(mMutex);
    175             ref_entry* ref = new ref_entry;
    176             // Reference count at the time of the snapshot, but before the
    177             // update.  Positive value means we increment, negative--we
    178             // decrement the reference count.
    179             ref->ref = mRef;
    180             ref->id = id;
    181 #if DEBUG_REFS_CALLSTACK_ENABLED
    182             ref->stack.update(2);
    183 #endif
    184 
    185             ref->next = *refs;
    186             *refs = ref;
    187         }
    188     }
    189 
    190     void removeRef(ref_entry** refs, const void* id)
    191     {
    192         if (mTrackEnabled) {
    193             AutoMutex _l(mMutex);
    194 
    195             ref_entry* ref = *refs;
    196             while (ref != NULL) {
    197                 if (ref->id == id) {
    198                     *refs = ref->next;
    199                     delete ref;
    200                     return;
    201                 }
    202 
    203                 refs = &ref->next;
    204                 ref = *refs;
    205             }
    206 
    207             LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!",
    208                              id, mBase, this);
    209         }
    210     }
    211 
    212     void printRefsLocked(String8* out, const ref_entry* refs) const
    213     {
    214         char buf[128];
    215         while (refs) {
    216             char inc = refs->ref >= 0 ? '+' : '-';
    217             sprintf(buf, "\t%c ID %p (ref %d):\n",
    218                     inc, refs->id, refs->ref);
    219             out->append(buf);
    220 #if DEBUG_REFS_CALLSTACK_ENABLED
    221             out->append(refs->stack.toString("\t\t"));
    222 #else
    223             out->append("\t\t(call stacks disabled)");
    224 #endif
    225             refs = refs->next;
    226         }
    227     }
    228 
    229     Mutex mMutex;
    230     ref_entry* mStrongRefs;
    231     ref_entry* mWeakRefs;
    232 
    233     bool mTrackEnabled;
    234     // Collect stack traces on addref and removeref, instead of deleting the stack references
    235     // on removeref that match the address ones.
    236     bool mRetain;
    237 
    238 #if 0
    239     void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
    240     {
    241         AutoMutex _l(mMutex);
    242         ssize_t i = refs->indexOfKey(id);
    243         if (i >= 0) {
    244             ++(refs->editValueAt(i));
    245         } else {
    246             i = refs->add(id, 1);
    247         }
    248     }
    249 
    250     void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
    251     {
    252         AutoMutex _l(mMutex);
    253         ssize_t i = refs->indexOfKey(id);
    254         LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
    255         if (i >= 0) {
    256             int32_t val = --(refs->editValueAt(i));
    257             if (val == 0) {
    258                 refs->removeItemsAt(i);
    259             }
    260         }
    261     }
    262 
    263     void printRefs(const KeyedVector<const void*, int32_t>& refs)
    264     {
    265         const size_t N=refs.size();
    266         for (size_t i=0; i<N; i++) {
    267             printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
    268         }
    269     }
    270 
    271     mutable Mutex mMutex;
    272     KeyedVector<const void*, int32_t> mStrongRefs;
    273     KeyedVector<const void*, int32_t> mWeakRefs;
    274 #endif
    275 
    276 #endif
    277 };
    278 
    279 // ---------------------------------------------------------------------------
    280 
    281 void RefBase::incStrong(const void* id) const
    282 {
    283     weakref_impl* const refs = mRefs;
    284     refs->addWeakRef(id);
    285     refs->incWeak(id);
    286 
    287     refs->addStrongRef(id);
    288     const int32_t c = android_atomic_inc(&refs->mStrong);
    289     LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
    290 #if PRINT_REFS
    291     LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
    292 #endif
    293     if (c != INITIAL_STRONG_VALUE)  {
    294         return;
    295     }
    296 
    297     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    298     const_cast<RefBase*>(this)->onFirstRef();
    299 }
    300 
    301 void RefBase::decStrong(const void* id) const
    302 {
    303     weakref_impl* const refs = mRefs;
    304     refs->removeStrongRef(id);
    305     const int32_t c = android_atomic_dec(&refs->mStrong);
    306 #if PRINT_REFS
    307     LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
    308 #endif
    309     LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
    310     if (c == 1) {
    311         const_cast<RefBase*>(this)->onLastStrongRef(id);
    312         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
    313             delete this;
    314         }
    315     }
    316     refs->removeWeakRef(id);
    317     refs->decWeak(id);
    318 }
    319 
    320 void RefBase::forceIncStrong(const void* id) const
    321 {
    322     weakref_impl* const refs = mRefs;
    323     refs->addWeakRef(id);
    324     refs->incWeak(id);
    325 
    326     refs->addStrongRef(id);
    327     const int32_t c = android_atomic_inc(&refs->mStrong);
    328     LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
    329                refs);
    330 #if PRINT_REFS
    331     LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
    332 #endif
    333 
    334     switch (c) {
    335     case INITIAL_STRONG_VALUE:
    336         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    337         // fall through...
    338     case 0:
    339         const_cast<RefBase*>(this)->onFirstRef();
    340     }
    341 }
    342 
    343 int32_t RefBase::getStrongCount() const
    344 {
    345     return mRefs->mStrong;
    346 }
    347 
    348 
    349 
    350 RefBase* RefBase::weakref_type::refBase() const
    351 {
    352     return static_cast<const weakref_impl*>(this)->mBase;
    353 }
    354 
    355 void RefBase::weakref_type::incWeak(const void* id)
    356 {
    357     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    358     impl->addWeakRef(id);
    359     const int32_t c = android_atomic_inc(&impl->mWeak);
    360     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
    361 }
    362 
    363 void RefBase::weakref_type::decWeak(const void* id)
    364 {
    365     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    366     impl->removeWeakRef(id);
    367     const int32_t c = android_atomic_dec(&impl->mWeak);
    368     LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
    369     if (c != 1) return;
    370 
    371     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
    372         if (impl->mStrong == INITIAL_STRONG_VALUE)
    373             delete impl->mBase;
    374         else {
    375 //            LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
    376             delete impl;
    377         }
    378     } else {
    379         impl->mBase->onLastWeakRef(id);
    380         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
    381             delete impl->mBase;
    382         }
    383     }
    384 }
    385 
    386 bool RefBase::weakref_type::attemptIncStrong(const void* id)
    387 {
    388     incWeak(id);
    389 
    390     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    391 
    392     int32_t curCount = impl->mStrong;
    393     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
    394                this);
    395     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
    396         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
    397             break;
    398         }
    399         curCount = impl->mStrong;
    400     }
    401 
    402     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
    403         bool allow;
    404         if (curCount == INITIAL_STRONG_VALUE) {
    405             // Attempting to acquire first strong reference...  this is allowed
    406             // if the object does NOT have a longer lifetime (meaning the
    407             // implementation doesn't need to see this), or if the implementation
    408             // allows it to happen.
    409             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
    410                   || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
    411         } else {
    412             // Attempting to revive the object...  this is allowed
    413             // if the object DOES have a longer lifetime (so we can safely
    414             // call the object with only a weak ref) and the implementation
    415             // allows it to happen.
    416             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
    417                   && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
    418         }
    419         if (!allow) {
    420             decWeak(id);
    421             return false;
    422         }
    423         curCount = android_atomic_inc(&impl->mStrong);
    424 
    425         // If the strong reference count has already been incremented by
    426         // someone else, the implementor of onIncStrongAttempted() is holding
    427         // an unneeded reference.  So call onLastStrongRef() here to remove it.
    428         // (No, this is not pretty.)  Note that we MUST NOT do this if we
    429         // are in fact acquiring the first reference.
    430         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
    431             impl->mBase->onLastStrongRef(id);
    432         }
    433     }
    434 
    435     impl->addWeakRef(id);
    436     impl->addStrongRef(id);
    437 
    438 #if PRINT_REFS
    439     LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
    440 #endif
    441 
    442     if (curCount == INITIAL_STRONG_VALUE) {
    443         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
    444         impl->mBase->onFirstRef();
    445     }
    446 
    447     return true;
    448 }
    449 
    450 bool RefBase::weakref_type::attemptIncWeak(const void* id)
    451 {
    452     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    453 
    454     int32_t curCount = impl->mWeak;
    455     LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
    456                this);
    457     while (curCount > 0) {
    458         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
    459             break;
    460         }
    461         curCount = impl->mWeak;
    462     }
    463 
    464     if (curCount > 0) {
    465         impl->addWeakRef(id);
    466     }
    467 
    468     return curCount > 0;
    469 }
    470 
    471 int32_t RefBase::weakref_type::getWeakCount() const
    472 {
    473     return static_cast<const weakref_impl*>(this)->mWeak;
    474 }
    475 
    476 void RefBase::weakref_type::printRefs() const
    477 {
    478     static_cast<const weakref_impl*>(this)->printRefs();
    479 }
    480 
    481 void RefBase::weakref_type::trackMe(bool enable, bool retain)
    482 {
    483     static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
    484 }
    485 
    486 RefBase::weakref_type* RefBase::createWeak(const void* id) const
    487 {
    488     mRefs->incWeak(id);
    489     return mRefs;
    490 }
    491 
    492 RefBase::weakref_type* RefBase::getWeakRefs() const
    493 {
    494     return mRefs;
    495 }
    496 
    497 RefBase::RefBase()
    498     : mRefs(new weakref_impl(this))
    499 {
    500 //    LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
    501 }
    502 
    503 RefBase::~RefBase()
    504 {
    505 //    LOGV("Destroying RefBase %p (refs %p)\n", this, mRefs);
    506     if (mRefs->mWeak == 0) {
    507 //        LOGV("Freeing refs %p of old RefBase %p\n", mRefs, this);
    508         delete mRefs;
    509     }
    510 }
    511 
    512 void RefBase::extendObjectLifetime(int32_t mode)
    513 {
    514     android_atomic_or(mode, &mRefs->mFlags);
    515 }
    516 
    517 void RefBase::onFirstRef()
    518 {
    519 }
    520 
    521 void RefBase::onLastStrongRef(const void* /*id*/)
    522 {
    523 }
    524 
    525 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
    526 {
    527     return (flags&FIRST_INC_STRONG) ? true : false;
    528 }
    529 
    530 void RefBase::onLastWeakRef(const void* /*id*/)
    531 {
    532 }
    533 
    534 }; // namespace android
    535