Home | History | Annotate | Download | only in libutils
      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 // #define LOG_NDEBUG 0
     19 
     20 #include <utils/RefBase.h>
     21 
     22 #include <utils/Atomic.h>
     23 #include <utils/CallStack.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 
     38 // whether ref-tracking is enabled by default, if not, trackMe(true, false)
     39 // needs to be called explicitly
     40 #define DEBUG_REFS_ENABLED_BY_DEFAULT   0
     41 
     42 // whether callstack are collected (significantly slows things down)
     43 #define DEBUG_REFS_CALLSTACK_ENABLED    1
     44 
     45 // folder where stack traces are saved when DEBUG_REFS is enabled
     46 // this folder needs to exist and be writable
     47 #define DEBUG_REFS_CALLSTACK_PATH       "/data/debug"
     48 
     49 // log all reference counting operations
     50 #define PRINT_REFS                      0
     51 
     52 // ---------------------------------------------------------------------------
     53 
     54 namespace android {
     55 
     56 #define INITIAL_STRONG_VALUE (1<<28)
     57 
     58 // ---------------------------------------------------------------------------
     59 
     60 class RefBase::weakref_impl : public RefBase::weakref_type
     61 {
     62 public:
     63     volatile int32_t    mStrong;
     64     volatile int32_t    mWeak;
     65     RefBase* const      mBase;
     66     volatile int32_t    mFlags;
     67 
     68 #if !DEBUG_REFS
     69 
     70     weakref_impl(RefBase* base)
     71         : mStrong(INITIAL_STRONG_VALUE)
     72         , mWeak(0)
     73         , mBase(base)
     74         , mFlags(0)
     75     {
     76     }
     77 
     78     void addStrongRef(const void* /*id*/) { }
     79     void removeStrongRef(const void* /*id*/) { }
     80     void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
     81     void addWeakRef(const void* /*id*/) { }
     82     void removeWeakRef(const void* /*id*/) { }
     83     void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
     84     void printRefs() const { }
     85     void trackMe(bool, bool) { }
     86 
     87 #else
     88 
     89     weakref_impl(RefBase* base)
     90         : mStrong(INITIAL_STRONG_VALUE)
     91         , mWeak(0)
     92         , mBase(base)
     93         , mFlags(0)
     94         , mStrongRefs(NULL)
     95         , mWeakRefs(NULL)
     96         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
     97         , mRetain(false)
     98     {
     99     }
    100 
    101     ~weakref_impl()
    102     {
    103         bool dumpStack = false;
    104         if (!mRetain && mStrongRefs != NULL) {
    105             dumpStack = true;
    106             ALOGE("Strong references remain:");
    107             ref_entry* refs = mStrongRefs;
    108             while (refs) {
    109                 char inc = refs->ref >= 0 ? '+' : '-';
    110                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
    111 #if DEBUG_REFS_CALLSTACK_ENABLED
    112                 refs->stack.dump(LOG_TAG);
    113 #endif
    114                 refs = refs->next;
    115             }
    116         }
    117 
    118         if (!mRetain && mWeakRefs != NULL) {
    119             dumpStack = true;
    120             ALOGE("Weak references remain!");
    121             ref_entry* refs = mWeakRefs;
    122             while (refs) {
    123                 char inc = refs->ref >= 0 ? '+' : '-';
    124                 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
    125 #if DEBUG_REFS_CALLSTACK_ENABLED
    126                 refs->stack.dump(LOG_TAG);
    127 #endif
    128                 refs = refs->next;
    129             }
    130         }
    131         if (dumpStack) {
    132             ALOGE("above errors at:");
    133             CallStack stack(LOG_TAG);
    134         }
    135     }
    136 
    137     void addStrongRef(const void* id) {
    138         //ALOGD_IF(mTrackEnabled,
    139         //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
    140         addRef(&mStrongRefs, id, mStrong);
    141     }
    142 
    143     void removeStrongRef(const void* id) {
    144         //ALOGD_IF(mTrackEnabled,
    145         //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
    146         if (!mRetain) {
    147             removeRef(&mStrongRefs, id);
    148         } else {
    149             addRef(&mStrongRefs, id, -mStrong);
    150         }
    151     }
    152 
    153     void renameStrongRefId(const void* old_id, const void* new_id) {
    154         //ALOGD_IF(mTrackEnabled,
    155         //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
    156         //        mBase, old_id, new_id);
    157         renameRefsId(mStrongRefs, old_id, new_id);
    158     }
    159 
    160     void addWeakRef(const void* id) {
    161         addRef(&mWeakRefs, id, mWeak);
    162     }
    163 
    164     void removeWeakRef(const void* id) {
    165         if (!mRetain) {
    166             removeRef(&mWeakRefs, id);
    167         } else {
    168             addRef(&mWeakRefs, id, -mWeak);
    169         }
    170     }
    171 
    172     void renameWeakRefId(const void* old_id, const void* new_id) {
    173         renameRefsId(mWeakRefs, old_id, new_id);
    174     }
    175 
    176     void trackMe(bool track, bool retain)
    177     {
    178         mTrackEnabled = track;
    179         mRetain = retain;
    180     }
    181 
    182     void printRefs() const
    183     {
    184         String8 text;
    185 
    186         {
    187             Mutex::Autolock _l(mMutex);
    188             char buf[128];
    189             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
    190             text.append(buf);
    191             printRefsLocked(&text, mStrongRefs);
    192             sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
    193             text.append(buf);
    194             printRefsLocked(&text, mWeakRefs);
    195         }
    196 
    197         {
    198             char name[100];
    199             snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
    200             int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
    201             if (rc >= 0) {
    202                 write(rc, text.string(), text.length());
    203                 close(rc);
    204                 ALOGD("STACK TRACE for %p saved in %s", this, name);
    205             }
    206             else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
    207                       name, strerror(errno));
    208         }
    209     }
    210 
    211 private:
    212     struct ref_entry
    213     {
    214         ref_entry* next;
    215         const void* id;
    216 #if DEBUG_REFS_CALLSTACK_ENABLED
    217         CallStack stack;
    218 #endif
    219         int32_t ref;
    220     };
    221 
    222     void addRef(ref_entry** refs, const void* id, int32_t mRef)
    223     {
    224         if (mTrackEnabled) {
    225             AutoMutex _l(mMutex);
    226 
    227             ref_entry* ref = new ref_entry;
    228             // Reference count at the time of the snapshot, but before the
    229             // update.  Positive value means we increment, negative--we
    230             // decrement the reference count.
    231             ref->ref = mRef;
    232             ref->id = id;
    233 #if DEBUG_REFS_CALLSTACK_ENABLED
    234             ref->stack.update(2);
    235 #endif
    236             ref->next = *refs;
    237             *refs = ref;
    238         }
    239     }
    240 
    241     void removeRef(ref_entry** refs, const void* id)
    242     {
    243         if (mTrackEnabled) {
    244             AutoMutex _l(mMutex);
    245 
    246             ref_entry* const head = *refs;
    247             ref_entry* ref = head;
    248             while (ref != NULL) {
    249                 if (ref->id == id) {
    250                     *refs = ref->next;
    251                     delete ref;
    252                     return;
    253                 }
    254                 refs = &ref->next;
    255                 ref = *refs;
    256             }
    257 
    258             ALOGE("RefBase: removing id %p on RefBase %p"
    259                     "(weakref_type %p) that doesn't exist!",
    260                     id, mBase, this);
    261 
    262             ref = head;
    263             while (ref) {
    264                 char inc = ref->ref >= 0 ? '+' : '-';
    265                 ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
    266                 ref = ref->next;
    267             }
    268 
    269             CallStack stack(LOG_TAG);
    270         }
    271     }
    272 
    273     void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
    274     {
    275         if (mTrackEnabled) {
    276             AutoMutex _l(mMutex);
    277             ref_entry* ref = r;
    278             while (ref != NULL) {
    279                 if (ref->id == old_id) {
    280                     ref->id = new_id;
    281                 }
    282                 ref = ref->next;
    283             }
    284         }
    285     }
    286 
    287     void printRefsLocked(String8* out, const ref_entry* refs) const
    288     {
    289         char buf[128];
    290         while (refs) {
    291             char inc = refs->ref >= 0 ? '+' : '-';
    292             sprintf(buf, "\t%c ID %p (ref %d):\n",
    293                     inc, refs->id, refs->ref);
    294             out->append(buf);
    295 #if DEBUG_REFS_CALLSTACK_ENABLED
    296             out->append(refs->stack.toString("\t\t"));
    297 #else
    298             out->append("\t\t(call stacks disabled)");
    299 #endif
    300             refs = refs->next;
    301         }
    302     }
    303 
    304     mutable Mutex mMutex;
    305     ref_entry* mStrongRefs;
    306     ref_entry* mWeakRefs;
    307 
    308     bool mTrackEnabled;
    309     // Collect stack traces on addref and removeref, instead of deleting the stack references
    310     // on removeref that match the address ones.
    311     bool mRetain;
    312 
    313 #endif
    314 };
    315 
    316 // ---------------------------------------------------------------------------
    317 
    318 void RefBase::incStrong(const void* id) const
    319 {
    320     weakref_impl* const refs = mRefs;
    321     refs->incWeak(id);
    322 
    323     refs->addStrongRef(id);
    324     const int32_t c = android_atomic_inc(&refs->mStrong);
    325     ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
    326 #if PRINT_REFS
    327     ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
    328 #endif
    329     if (c != INITIAL_STRONG_VALUE)  {
    330         return;
    331     }
    332 
    333     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    334     refs->mBase->onFirstRef();
    335 }
    336 
    337 void RefBase::decStrong(const void* id) const
    338 {
    339     weakref_impl* const refs = mRefs;
    340     refs->removeStrongRef(id);
    341     const int32_t c = android_atomic_dec(&refs->mStrong);
    342 #if PRINT_REFS
    343     ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
    344 #endif
    345     ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
    346     if (c == 1) {
    347         refs->mBase->onLastStrongRef(id);
    348         if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
    349             delete this;
    350         }
    351     }
    352     refs->decWeak(id);
    353 }
    354 
    355 void RefBase::forceIncStrong(const void* id) const
    356 {
    357     weakref_impl* const refs = mRefs;
    358     refs->incWeak(id);
    359 
    360     refs->addStrongRef(id);
    361     const int32_t c = android_atomic_inc(&refs->mStrong);
    362     ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
    363                refs);
    364 #if PRINT_REFS
    365     ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
    366 #endif
    367 
    368     switch (c) {
    369     case INITIAL_STRONG_VALUE:
    370         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
    371         // fall through...
    372     case 0:
    373         refs->mBase->onFirstRef();
    374     }
    375 }
    376 
    377 int32_t RefBase::getStrongCount() const
    378 {
    379     return mRefs->mStrong;
    380 }
    381 
    382 RefBase* RefBase::weakref_type::refBase() const
    383 {
    384     return static_cast<const weakref_impl*>(this)->mBase;
    385 }
    386 
    387 void RefBase::weakref_type::incWeak(const void* id)
    388 {
    389     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    390     impl->addWeakRef(id);
    391     const int32_t c = android_atomic_inc(&impl->mWeak);
    392     ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
    393 }
    394 
    395 
    396 void RefBase::weakref_type::decWeak(const void* id)
    397 {
    398     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    399     impl->removeWeakRef(id);
    400     const int32_t c = android_atomic_dec(&impl->mWeak);
    401     ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
    402     if (c != 1) return;
    403 
    404     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
    405         // This is the regular lifetime case. The object is destroyed
    406         // when the last strong reference goes away. Since weakref_impl
    407         // outlive the object, it is not destroyed in the dtor, and
    408         // we'll have to do it here.
    409         if (impl->mStrong == INITIAL_STRONG_VALUE) {
    410             // Special case: we never had a strong reference, so we need to
    411             // destroy the object now.
    412             delete impl->mBase;
    413         } else {
    414             // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
    415             delete impl;
    416         }
    417     } else {
    418         // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
    419         impl->mBase->onLastWeakRef(id);
    420         if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
    421             // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
    422             // is gone, we can destroy the object.
    423             delete impl->mBase;
    424         }
    425     }
    426 }
    427 
    428 bool RefBase::weakref_type::attemptIncStrong(const void* id)
    429 {
    430     incWeak(id);
    431 
    432     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    433     int32_t curCount = impl->mStrong;
    434 
    435     ALOG_ASSERT(curCount >= 0,
    436             "attemptIncStrong called on %p after underflow", this);
    437 
    438     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
    439         // we're in the easy/common case of promoting a weak-reference
    440         // from an existing strong reference.
    441         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
    442             break;
    443         }
    444         // the strong count has changed on us, we need to re-assert our
    445         // situation.
    446         curCount = impl->mStrong;
    447     }
    448 
    449     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
    450         // we're now in the harder case of either:
    451         // - there never was a strong reference on us
    452         // - or, all strong references have been released
    453         if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
    454             // this object has a "normal" life-time, i.e.: it gets destroyed
    455             // when the last strong reference goes away
    456             if (curCount <= 0) {
    457                 // the last strong-reference got released, the object cannot
    458                 // be revived.
    459                 decWeak(id);
    460                 return false;
    461             }
    462 
    463             // here, curCount == INITIAL_STRONG_VALUE, which means
    464             // there never was a strong-reference, so we can try to
    465             // promote this object; we need to do that atomically.
    466             while (curCount > 0) {
    467                 if (android_atomic_cmpxchg(curCount, curCount + 1,
    468                         &impl->mStrong) == 0) {
    469                     break;
    470                 }
    471                 // the strong count has changed on us, we need to re-assert our
    472                 // situation (e.g.: another thread has inc/decStrong'ed us)
    473                 curCount = impl->mStrong;
    474             }
    475 
    476             if (curCount <= 0) {
    477                 // promote() failed, some other thread destroyed us in the
    478                 // meantime (i.e.: strong count reached zero).
    479                 decWeak(id);
    480                 return false;
    481             }
    482         } else {
    483             // this object has an "extended" life-time, i.e.: it can be
    484             // revived from a weak-reference only.
    485             // Ask the object's implementation if it agrees to be revived
    486             if (!impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id)) {
    487                 // it didn't so give-up.
    488                 decWeak(id);
    489                 return false;
    490             }
    491             // grab a strong-reference, which is always safe due to the
    492             // extended life-time.
    493             curCount = android_atomic_inc(&impl->mStrong);
    494         }
    495 
    496         // If the strong reference count has already been incremented by
    497         // someone else, the implementor of onIncStrongAttempted() is holding
    498         // an unneeded reference.  So call onLastStrongRef() here to remove it.
    499         // (No, this is not pretty.)  Note that we MUST NOT do this if we
    500         // are in fact acquiring the first reference.
    501         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
    502             impl->mBase->onLastStrongRef(id);
    503         }
    504     }
    505 
    506     impl->addStrongRef(id);
    507 
    508 #if PRINT_REFS
    509     ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
    510 #endif
    511 
    512     // now we need to fix-up the count if it was INITIAL_STRONG_VALUE
    513     // this must be done safely, i.e.: handle the case where several threads
    514     // were here in attemptIncStrong().
    515     curCount = impl->mStrong;
    516     while (curCount >= INITIAL_STRONG_VALUE) {
    517         ALOG_ASSERT(curCount > INITIAL_STRONG_VALUE,
    518                 "attemptIncStrong in %p underflowed to INITIAL_STRONG_VALUE",
    519                 this);
    520         if (android_atomic_cmpxchg(curCount, curCount-INITIAL_STRONG_VALUE,
    521                 &impl->mStrong) == 0) {
    522             break;
    523         }
    524         // the strong-count changed on us, we need to re-assert the situation,
    525         // for e.g.: it's possible the fix-up happened in another thread.
    526         curCount = impl->mStrong;
    527     }
    528 
    529     return true;
    530 }
    531 
    532 bool RefBase::weakref_type::attemptIncWeak(const void* id)
    533 {
    534     weakref_impl* const impl = static_cast<weakref_impl*>(this);
    535 
    536     int32_t curCount = impl->mWeak;
    537     ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
    538                this);
    539     while (curCount > 0) {
    540         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
    541             break;
    542         }
    543         curCount = impl->mWeak;
    544     }
    545 
    546     if (curCount > 0) {
    547         impl->addWeakRef(id);
    548     }
    549 
    550     return curCount > 0;
    551 }
    552 
    553 int32_t RefBase::weakref_type::getWeakCount() const
    554 {
    555     return static_cast<const weakref_impl*>(this)->mWeak;
    556 }
    557 
    558 void RefBase::weakref_type::printRefs() const
    559 {
    560     static_cast<const weakref_impl*>(this)->printRefs();
    561 }
    562 
    563 void RefBase::weakref_type::trackMe(bool enable, bool retain)
    564 {
    565     static_cast<weakref_impl*>(this)->trackMe(enable, retain);
    566 }
    567 
    568 RefBase::weakref_type* RefBase::createWeak(const void* id) const
    569 {
    570     mRefs->incWeak(id);
    571     return mRefs;
    572 }
    573 
    574 RefBase::weakref_type* RefBase::getWeakRefs() const
    575 {
    576     return mRefs;
    577 }
    578 
    579 RefBase::RefBase()
    580     : mRefs(new weakref_impl(this))
    581 {
    582 }
    583 
    584 RefBase::~RefBase()
    585 {
    586     if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
    587         // we never acquired a strong (and/or weak) reference on this object.
    588         delete mRefs;
    589     } else {
    590         // life-time of this object is extended to WEAK or FOREVER, in
    591         // which case weakref_impl doesn't out-live the object and we
    592         // can free it now.
    593         if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
    594             // It's possible that the weak count is not 0 if the object
    595             // re-acquired a weak reference in its destructor
    596             if (mRefs->mWeak == 0) {
    597                 delete mRefs;
    598             }
    599         }
    600     }
    601     // for debugging purposes, clear this.
    602     const_cast<weakref_impl*&>(mRefs) = NULL;
    603 }
    604 
    605 void RefBase::extendObjectLifetime(int32_t mode)
    606 {
    607     android_atomic_or(mode, &mRefs->mFlags);
    608 }
    609 
    610 void RefBase::onFirstRef()
    611 {
    612 }
    613 
    614 void RefBase::onLastStrongRef(const void* /*id*/)
    615 {
    616 }
    617 
    618 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
    619 {
    620     return (flags&FIRST_INC_STRONG) ? true : false;
    621 }
    622 
    623 void RefBase::onLastWeakRef(const void* /*id*/)
    624 {
    625 }
    626 
    627 // ---------------------------------------------------------------------------
    628 
    629 void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
    630 #if DEBUG_REFS
    631     for (size_t i=0 ; i<n ; i++) {
    632         renamer(i);
    633     }
    634 #endif
    635 }
    636 
    637 void RefBase::renameRefId(weakref_type* ref,
    638         const void* old_id, const void* new_id) {
    639     weakref_impl* const impl = static_cast<weakref_impl*>(ref);
    640     impl->renameStrongRefId(old_id, new_id);
    641     impl->renameWeakRefId(old_id, new_id);
    642 }
    643 
    644 void RefBase::renameRefId(RefBase* ref,
    645         const void* old_id, const void* new_id) {
    646     ref->mRefs->renameStrongRefId(old_id, new_id);
    647     ref->mRefs->renameWeakRefId(old_id, new_id);
    648 }
    649 
    650 }; // namespace android
    651