OSDN Git Service

bb6c1255f38af53b1e64271d9e86e6e1d638e0f0
[android-x86/frameworks-base.git] / libs / utils / RefBase.cpp
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/Log.h>
24 #include <utils/threads.h>
25 #include <utils/TextOutput.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_FATAL_SANITY_CHECKS  0
38 #define DEBUG_REFS_ENABLED_BY_DEFAULT   1
39 #define DEBUG_REFS_CALLSTACK_ENABLED    1
40
41 // log all reference counting operations
42 #define PRINT_REFS                      0
43
44 // ---------------------------------------------------------------------------
45
46 namespace android {
47
48 #define INITIAL_STRONG_VALUE (1<<28)
49
50 // ---------------------------------------------------------------------------
51
52 class RefBase::weakref_impl : public RefBase::weakref_type
53 {
54 public:
55     volatile int32_t    mStrong;
56     volatile int32_t    mWeak;
57     RefBase* const      mBase;
58     volatile int32_t    mFlags;
59
60
61 #if !DEBUG_REFS
62
63     weakref_impl(RefBase* base)
64         : mStrong(INITIAL_STRONG_VALUE)
65         , mWeak(0)
66         , mBase(base)
67         , mFlags(0)
68     {
69     }
70
71     void addStrongRef(const void* /*id*/) { }
72     void removeStrongRef(const void* /*id*/) { }
73     void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
74     void addWeakRef(const void* /*id*/) { }
75     void removeWeakRef(const void* /*id*/) { }
76     void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
77     void printRefs() const { }
78     void trackMe(bool, bool) { }
79
80 #else
81
82     weakref_impl(RefBase* base)
83         : mStrong(INITIAL_STRONG_VALUE)
84         , mWeak(0)
85         , mBase(base)
86         , mFlags(0)
87         , mStrongRefs(NULL)
88         , mWeakRefs(NULL)
89         , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
90         , mRetain(false)
91     {
92     }
93     
94     ~weakref_impl()
95     {
96         bool dumpStack = false;
97         if (!mRetain && mStrongRefs != NULL) {
98             dumpStack = true;
99 #if DEBUG_REFS_FATAL_SANITY_CHECKS
100             LOG_ALWAYS_FATAL("Strong references remain!");
101 #else
102             LOGE("Strong references remain:");
103 #endif
104             ref_entry* refs = mStrongRefs;
105             while (refs) {
106                 char inc = refs->ref >= 0 ? '+' : '-';
107                 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
108 #if DEBUG_REFS_CALLSTACK_ENABLED
109                 refs->stack.dump();
110 #endif;
111                 refs = refs->next;
112             }
113         }
114
115         if (!mRetain && mWeakRefs != NULL) {
116             dumpStack = true;
117 #if DEBUG_REFS_FATAL_SANITY_CHECKS
118             LOG_ALWAYS_FATAL("Weak references remain:");
119 #else
120             LOGE("Weak references remain!");
121 #endif
122             ref_entry* refs = mWeakRefs;
123             while (refs) {
124                 char inc = refs->ref >= 0 ? '+' : '-';
125                 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
126 #if DEBUG_REFS_CALLSTACK_ENABLED
127                 refs->stack.dump();
128 #endif;
129                 refs = refs->next;
130             }
131         }
132         if (dumpStack) {
133             LOGE("above errors at:");
134             CallStack stack;
135             stack.update();
136             stack.dump();
137         }
138     }
139
140     void addStrongRef(const void* id) {
141         //LOGD_IF(mTrackEnabled,
142         //        "addStrongRef: RefBase=%p, id=%p", mBase, id);
143         addRef(&mStrongRefs, id, mStrong);
144     }
145
146     void removeStrongRef(const void* id) {
147         //LOGD_IF(mTrackEnabled,
148         //        "removeStrongRef: RefBase=%p, id=%p", mBase, id);
149         if (!mRetain) {
150             removeRef(&mStrongRefs, id);
151         } else {
152             addRef(&mStrongRefs, id, -mStrong);
153         }
154     }
155
156     void renameStrongRefId(const void* old_id, const void* new_id) {
157         //LOGD_IF(mTrackEnabled,
158         //        "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
159         //        mBase, old_id, new_id);
160         renameRefsId(mStrongRefs, old_id, new_id);
161     }
162
163     void addWeakRef(const void* id) {
164         addRef(&mWeakRefs, id, mWeak);
165     }
166
167     void removeWeakRef(const void* id) {
168         if (!mRetain) {
169             removeRef(&mWeakRefs, id);
170         } else {
171             addRef(&mWeakRefs, id, -mWeak);
172         }
173     }
174
175     void renameWeakRefId(const void* old_id, const void* new_id) {
176         renameRefsId(mWeakRefs, old_id, new_id);
177     }
178
179     void trackMe(bool track, bool retain)
180     { 
181         mTrackEnabled = track;
182         mRetain = retain;
183     }
184
185     void printRefs() const
186     {
187         String8 text;
188
189         {
190             Mutex::Autolock _l(const_cast<weakref_impl*>(this)->mMutex);
191             char buf[128];
192             sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
193             text.append(buf);
194             printRefsLocked(&text, mStrongRefs);
195             sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
196             text.append(buf);
197             printRefsLocked(&text, mWeakRefs);
198         }
199
200         {
201             char name[100];
202             snprintf(name, 100, "/data/%p.stack", this);
203             int rc = open(name, O_RDWR | O_CREAT | O_APPEND);
204             if (rc >= 0) {
205                 write(rc, text.string(), text.length());
206                 close(rc);
207                 LOGD("STACK TRACE for %p saved in %s", this, name);
208             }
209             else LOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
210                       name, strerror(errno));
211         }
212     }
213
214 private:
215     struct ref_entry
216     {
217         ref_entry* next;
218         const void* id;
219 #if DEBUG_REFS_CALLSTACK_ENABLED
220         CallStack stack;
221 #endif
222         int32_t ref;
223     };
224
225     void addRef(ref_entry** refs, const void* id, int32_t mRef)
226     {
227         if (mTrackEnabled) {
228             AutoMutex _l(mMutex);
229
230             ref_entry* ref = new ref_entry;
231             // Reference count at the time of the snapshot, but before the
232             // update.  Positive value means we increment, negative--we
233             // decrement the reference count.
234             ref->ref = mRef;
235             ref->id = id;
236 #if DEBUG_REFS_CALLSTACK_ENABLED
237             ref->stack.update(2);
238 #endif
239             ref->next = *refs;
240             *refs = ref;
241         }
242     }
243
244     void removeRef(ref_entry** refs, const void* id)
245     {
246         if (mTrackEnabled) {
247             AutoMutex _l(mMutex);
248             
249             ref_entry* const head = *refs;
250             ref_entry* ref = head;
251             while (ref != NULL) {
252                 if (ref->id == id) {
253                     *refs = ref->next;
254                     delete ref;
255                     return;
256                 }
257                 refs = &ref->next;
258                 ref = *refs;
259             }
260
261 #if DEBUG_REFS_FATAL_SANITY_CHECKS
262             LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
263                     "(weakref_type %p) that doesn't exist!",
264                     id, mBase, this);
265 #endif
266
267             LOGE("RefBase: removing id %p on RefBase %p"
268                     "(weakref_type %p) that doesn't exist!",
269                     id, mBase, this);
270
271             ref = head;
272             while (ref) {
273                 char inc = ref->ref >= 0 ? '+' : '-';
274                 LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
275                 ref = ref->next;
276             }
277
278             CallStack stack;
279             stack.update();
280             stack.dump();
281         }
282     }
283
284     void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
285     {
286         if (mTrackEnabled) {
287             AutoMutex _l(mMutex);
288             ref_entry* ref = r;
289             while (ref != NULL) {
290                 if (ref->id == old_id) {
291                     ref->id = new_id;
292                 }
293                 ref = ref->next;
294             }
295         }
296     }
297
298     void printRefsLocked(String8* out, const ref_entry* refs) const
299     {
300         char buf[128];
301         while (refs) {
302             char inc = refs->ref >= 0 ? '+' : '-';
303             sprintf(buf, "\t%c ID %p (ref %d):\n", 
304                     inc, refs->id, refs->ref);
305             out->append(buf);
306 #if DEBUG_REFS_CALLSTACK_ENABLED
307             out->append(refs->stack.toString("\t\t"));
308 #else
309             out->append("\t\t(call stacks disabled)");
310 #endif
311             refs = refs->next;
312         }
313     }
314
315     Mutex mMutex;
316     ref_entry* mStrongRefs;
317     ref_entry* mWeakRefs;
318
319     bool mTrackEnabled;
320     // Collect stack traces on addref and removeref, instead of deleting the stack references
321     // on removeref that match the address ones.
322     bool mRetain;
323
324 #endif
325 };
326
327 // ---------------------------------------------------------------------------
328
329 void RefBase::incStrong(const void* id) const
330 {
331     weakref_impl* const refs = mRefs;
332     refs->incWeak(id);
333     
334     refs->addStrongRef(id);
335     const int32_t c = android_atomic_inc(&refs->mStrong);
336     LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
337 #if PRINT_REFS
338     LOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
339 #endif
340     if (c != INITIAL_STRONG_VALUE)  {
341         return;
342     }
343
344     android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
345     const_cast<RefBase*>(this)->onFirstRef();
346 }
347
348 void RefBase::decStrong(const void* id) const
349 {
350     weakref_impl* const refs = mRefs;
351     refs->removeStrongRef(id);
352     const int32_t c = android_atomic_dec(&refs->mStrong);
353 #if PRINT_REFS
354     LOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
355 #endif
356     LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
357     if (c == 1) {
358         const_cast<RefBase*>(this)->onLastStrongRef(id);
359         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
360             delete this;
361         }
362     }
363     refs->decWeak(id);
364 }
365
366 void RefBase::forceIncStrong(const void* id) const
367 {
368     weakref_impl* const refs = mRefs;
369     refs->incWeak(id);
370     
371     refs->addStrongRef(id);
372     const int32_t c = android_atomic_inc(&refs->mStrong);
373     LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
374                refs);
375 #if PRINT_REFS
376     LOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
377 #endif
378
379     switch (c) {
380     case INITIAL_STRONG_VALUE:
381         android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
382         // fall through...
383     case 0:
384         const_cast<RefBase*>(this)->onFirstRef();
385     }
386 }
387
388 int32_t RefBase::getStrongCount() const
389 {
390     return mRefs->mStrong;
391 }
392
393
394
395 RefBase* RefBase::weakref_type::refBase() const
396 {
397     return static_cast<const weakref_impl*>(this)->mBase;
398 }
399
400 void RefBase::weakref_type::incWeak(const void* id)
401 {
402     weakref_impl* const impl = static_cast<weakref_impl*>(this);
403     impl->addWeakRef(id);
404     const int32_t c = android_atomic_inc(&impl->mWeak);
405     LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
406 }
407
408 void RefBase::weakref_type::decWeak(const void* id)
409 {
410     weakref_impl* const impl = static_cast<weakref_impl*>(this);
411     impl->removeWeakRef(id);
412     const int32_t c = android_atomic_dec(&impl->mWeak);
413     LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
414     if (c != 1) return;
415     
416     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
417         if (impl->mStrong == INITIAL_STRONG_VALUE)
418             delete impl->mBase;
419         else {
420             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
421             delete impl;
422         }
423     } else {
424         impl->mBase->onLastWeakRef(id);
425         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
426             delete impl->mBase;
427         }
428     }
429 }
430
431 bool RefBase::weakref_type::attemptIncStrong(const void* id)
432 {
433     incWeak(id);
434     
435     weakref_impl* const impl = static_cast<weakref_impl*>(this);
436     
437     int32_t curCount = impl->mStrong;
438     LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
439                this);
440     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
441         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
442             break;
443         }
444         curCount = impl->mStrong;
445     }
446     
447     if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
448         bool allow;
449         if (curCount == INITIAL_STRONG_VALUE) {
450             // Attempting to acquire first strong reference...  this is allowed
451             // if the object does NOT have a longer lifetime (meaning the
452             // implementation doesn't need to see this), or if the implementation
453             // allows it to happen.
454             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK
455                   || impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
456         } else {
457             // Attempting to revive the object...  this is allowed
458             // if the object DOES have a longer lifetime (so we can safely
459             // call the object with only a weak ref) and the implementation
460             // allows it to happen.
461             allow = (impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK
462                   && impl->mBase->onIncStrongAttempted(FIRST_INC_STRONG, id);
463         }
464         if (!allow) {
465             decWeak(id);
466             return false;
467         }
468         curCount = android_atomic_inc(&impl->mStrong);
469
470         // If the strong reference count has already been incremented by
471         // someone else, the implementor of onIncStrongAttempted() is holding
472         // an unneeded reference.  So call onLastStrongRef() here to remove it.
473         // (No, this is not pretty.)  Note that we MUST NOT do this if we
474         // are in fact acquiring the first reference.
475         if (curCount > 0 && curCount < INITIAL_STRONG_VALUE) {
476             impl->mBase->onLastStrongRef(id);
477         }
478     }
479     
480     impl->addStrongRef(id);
481
482 #if PRINT_REFS
483     LOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
484 #endif
485
486     if (curCount == INITIAL_STRONG_VALUE) {
487         android_atomic_add(-INITIAL_STRONG_VALUE, &impl->mStrong);
488         impl->mBase->onFirstRef();
489     }
490     
491     return true;
492 }
493
494 bool RefBase::weakref_type::attemptIncWeak(const void* id)
495 {
496     weakref_impl* const impl = static_cast<weakref_impl*>(this);
497
498     int32_t curCount = impl->mWeak;
499     LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
500                this);
501     while (curCount > 0) {
502         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
503             break;
504         }
505         curCount = impl->mWeak;
506     }
507
508     if (curCount > 0) {
509         impl->addWeakRef(id);
510     }
511
512     return curCount > 0;
513 }
514
515 int32_t RefBase::weakref_type::getWeakCount() const
516 {
517     return static_cast<const weakref_impl*>(this)->mWeak;
518 }
519
520 void RefBase::weakref_type::printRefs() const
521 {
522     static_cast<const weakref_impl*>(this)->printRefs();
523 }
524
525 void RefBase::weakref_type::trackMe(bool enable, bool retain)
526 {
527     static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
528 }
529
530 RefBase::weakref_type* RefBase::createWeak(const void* id) const
531 {
532     mRefs->incWeak(id);
533     return mRefs;
534 }
535
536 RefBase::weakref_type* RefBase::getWeakRefs() const
537 {
538     return mRefs;
539 }
540
541 RefBase::RefBase()
542     : mRefs(new weakref_impl(this))
543 {
544 }
545
546 RefBase::~RefBase()
547 {
548     if (mRefs->mWeak == 0) {
549         delete mRefs;
550     }
551 }
552
553 void RefBase::extendObjectLifetime(int32_t mode)
554 {
555     android_atomic_or(mode, &mRefs->mFlags);
556 }
557
558 void RefBase::onFirstRef()
559 {
560 }
561
562 void RefBase::onLastStrongRef(const void* /*id*/)
563 {
564 }
565
566 bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
567 {
568     return (flags&FIRST_INC_STRONG) ? true : false;
569 }
570
571 void RefBase::onLastWeakRef(const void* /*id*/)
572 {
573 }
574
575 // ---------------------------------------------------------------------------
576
577 void RefBase::moveReferences(void* dst, void const* src, size_t n,
578         const ReferenceConverterBase& caster)
579 {
580 #if DEBUG_REFS
581     const size_t itemSize = caster.getReferenceTypeSize();
582     for (size_t i=0 ; i<n ; i++) {
583         void*       d = reinterpret_cast<void      *>(intptr_t(dst) + i*itemSize);
584         void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
585         RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
586         ref->mRefs->renameStrongRefId(s, d);
587         ref->mRefs->renameWeakRefId(s, d);
588     }
589 #endif
590 }
591
592 // ---------------------------------------------------------------------------
593
594 TextOutput& printStrongPointer(TextOutput& to, const void* val)
595 {
596     to << "sp<>(" << val << ")";
597     return to;
598 }
599
600 TextOutput& printWeakPointer(TextOutput& to, const void* val)
601 {
602     to << "wp<>(" << val << ")";
603     return to;
604 }
605
606
607 }; // namespace android