RefBase.cpp revision d98e07fdf9c338589f263c47ce5c844ed43efad5
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
54namespace android {
55
56#define INITIAL_STRONG_VALUE (1<<28)
57
58// ---------------------------------------------------------------------------
59
60class RefBase::weakref_impl : public RefBase::weakref_type
61{
62public:
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
211private:
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
318void 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
337void 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
355void 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
377int32_t RefBase::getStrongCount() const
378{
379    return mRefs->mStrong;
380}
381
382RefBase* RefBase::weakref_type::refBase() const
383{
384    return static_cast<const weakref_impl*>(this)->mBase;
385}
386
387void 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
396void 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
428bool 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
532bool 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
553int32_t RefBase::weakref_type::getWeakCount() const
554{
555    return static_cast<const weakref_impl*>(this)->mWeak;
556}
557
558void RefBase::weakref_type::printRefs() const
559{
560    static_cast<const weakref_impl*>(this)->printRefs();
561}
562
563void RefBase::weakref_type::trackMe(bool enable, bool retain)
564{
565    static_cast<weakref_impl*>(this)->trackMe(enable, retain);
566}
567
568RefBase::weakref_type* RefBase::createWeak(const void* id) const
569{
570    mRefs->incWeak(id);
571    return mRefs;
572}
573
574RefBase::weakref_type* RefBase::getWeakRefs() const
575{
576    return mRefs;
577}
578
579RefBase::RefBase()
580    : mRefs(new weakref_impl(this))
581{
582}
583
584RefBase::~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
605void RefBase::extendObjectLifetime(int32_t mode)
606{
607    android_atomic_or(mode, &mRefs->mFlags);
608}
609
610void RefBase::onFirstRef()
611{
612}
613
614void RefBase::onLastStrongRef(const void* /*id*/)
615{
616}
617
618bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
619{
620    return (flags&FIRST_INC_STRONG) ? true : false;
621}
622
623void RefBase::onLastWeakRef(const void* /*id*/)
624{
625}
626
627// ---------------------------------------------------------------------------
628
629void 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
637void 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
644void 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