blob: f398a82cef5cfd34606b9f37936a75986246478a [file] [log] [blame]
The Android Open Source Projectcbb10112009-03-03 19:31:44 -08001/*
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"
Mathias Agopianda8ec4b2013-03-19 17:36:57 -070018// #define LOG_NDEBUG 0
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080019
20#include <utils/RefBase.h>
21
22#include <utils/Atomic.h>
23#include <utils/CallStack.h>
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080024#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
Mathias Agopian6d4419d2013-03-18 20:31:18 -070037
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)
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080043#define DEBUG_REFS_CALLSTACK_ENABLED 1
44
Mathias Agopian6d4419d2013-03-18 20:31:18 -070045// 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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080049// 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;
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -070067
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080068#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*/) { }
Mathias Agopianad099652011-08-10 21:07:02 -070080 void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080081 void addWeakRef(const void* /*id*/) { }
82 void removeWeakRef(const void* /*id*/) { }
Mathias Agopianad099652011-08-10 21:07:02 -070083 void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080084 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 {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -080099 }
100
101 ~weakref_impl()
102 {
Mathias Agopianad099652011-08-10 21:07:02 -0700103 bool dumpStack = false;
104 if (!mRetain && mStrongRefs != NULL) {
105 dumpStack = true;
Steve Block1b781ab2012-01-06 19:20:56 +0000106 ALOGE("Strong references remain:");
Mathias Agopianad099652011-08-10 21:07:02 -0700107 ref_entry* refs = mStrongRefs;
108 while (refs) {
109 char inc = refs->ref >= 0 ? '+' : '-';
Steve Blockeb095332011-12-20 16:23:08 +0000110 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
Mathias Agopianad099652011-08-10 21:07:02 -0700111#if DEBUG_REFS_CALLSTACK_ENABLED
Mathias Agopiand34a8ca2013-03-21 17:12:40 -0700112 refs->stack.dump(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700113#endif
114 refs = refs->next;
115 }
116 }
117
118 if (!mRetain && mWeakRefs != NULL) {
119 dumpStack = true;
Steve Block1b781ab2012-01-06 19:20:56 +0000120 ALOGE("Weak references remain!");
Mathias Agopianad099652011-08-10 21:07:02 -0700121 ref_entry* refs = mWeakRefs;
122 while (refs) {
123 char inc = refs->ref >= 0 ? '+' : '-';
Steve Blockeb095332011-12-20 16:23:08 +0000124 ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
Mathias Agopianad099652011-08-10 21:07:02 -0700125#if DEBUG_REFS_CALLSTACK_ENABLED
Mathias Agopiand34a8ca2013-03-21 17:12:40 -0700126 refs->stack.dump(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700127#endif
128 refs = refs->next;
129 }
130 }
131 if (dumpStack) {
Steve Block1b781ab2012-01-06 19:20:56 +0000132 ALOGE("above errors at:");
Mathias Agopiand34a8ca2013-03-21 17:12:40 -0700133 CallStack stack(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700134 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800135 }
136
Mathias Agopianad099652011-08-10 21:07:02 -0700137 void addStrongRef(const void* id) {
Steve Blockeb095332011-12-20 16:23:08 +0000138 //ALOGD_IF(mTrackEnabled,
Mathias Agopianad099652011-08-10 21:07:02 -0700139 // "addStrongRef: RefBase=%p, id=%p", mBase, id);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800140 addRef(&mStrongRefs, id, mStrong);
141 }
142
Mathias Agopianad099652011-08-10 21:07:02 -0700143 void removeStrongRef(const void* id) {
Steve Blockeb095332011-12-20 16:23:08 +0000144 //ALOGD_IF(mTrackEnabled,
Mathias Agopianad099652011-08-10 21:07:02 -0700145 // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
146 if (!mRetain) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800147 removeRef(&mStrongRefs, id);
Mathias Agopianad099652011-08-10 21:07:02 -0700148 } else {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800149 addRef(&mStrongRefs, id, -mStrong);
Mathias Agopianad099652011-08-10 21:07:02 -0700150 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800151 }
152
Mathias Agopianad099652011-08-10 21:07:02 -0700153 void renameStrongRefId(const void* old_id, const void* new_id) {
Steve Blockeb095332011-12-20 16:23:08 +0000154 //ALOGD_IF(mTrackEnabled,
Mathias Agopianad099652011-08-10 21:07:02 -0700155 // "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) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800161 addRef(&mWeakRefs, id, mWeak);
162 }
163
Mathias Agopianad099652011-08-10 21:07:02 -0700164 void removeWeakRef(const void* id) {
165 if (!mRetain) {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800166 removeRef(&mWeakRefs, id);
Mathias Agopianad099652011-08-10 21:07:02 -0700167 } else {
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800168 addRef(&mWeakRefs, id, -mWeak);
Mathias Agopianad099652011-08-10 21:07:02 -0700169 }
170 }
171
172 void renameWeakRefId(const void* old_id, const void* new_id) {
173 renameRefsId(mWeakRefs, old_id, new_id);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800174 }
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 {
Mathias Agopianad099652011-08-10 21:07:02 -0700187 Mutex::Autolock _l(mMutex);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800188 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];
Mathias Agopian6d4419d2013-03-18 20:31:18 -0700199 snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
Mathias Agopian769828d2013-03-06 17:51:15 -0800200 int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800201 if (rc >= 0) {
202 write(rc, text.string(), text.length());
203 close(rc);
Steve Blockeb095332011-12-20 16:23:08 +0000204 ALOGD("STACK TRACE for %p saved in %s", this, name);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800205 }
Steve Block1b781ab2012-01-06 19:20:56 +0000206 else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800207 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);
Mathias Agopianad099652011-08-10 21:07:02 -0700226
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800227 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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800236 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
Mathias Agopianad099652011-08-10 21:07:02 -0700246 ref_entry* const head = *refs;
247 ref_entry* ref = head;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800248 while (ref != NULL) {
249 if (ref->id == id) {
250 *refs = ref->next;
251 delete ref;
252 return;
253 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800254 refs = &ref->next;
255 ref = *refs;
256 }
Mathias Agopianad099652011-08-10 21:07:02 -0700257
Steve Block1b781ab2012-01-06 19:20:56 +0000258 ALOGE("RefBase: removing id %p on RefBase %p"
Mathias Agopianad099652011-08-10 21:07:02 -0700259 "(weakref_type %p) that doesn't exist!",
260 id, mBase, this);
261
262 ref = head;
263 while (ref) {
264 char inc = ref->ref >= 0 ? '+' : '-';
Steve Blockeb095332011-12-20 16:23:08 +0000265 ALOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
Mathias Agopianad099652011-08-10 21:07:02 -0700266 ref = ref->next;
267 }
268
Mathias Agopiand34a8ca2013-03-21 17:12:40 -0700269 CallStack stack(LOG_TAG);
Mathias Agopianad099652011-08-10 21:07:02 -0700270 }
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 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800284 }
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
Mathias Agopianad099652011-08-10 21:07:02 -0700304 mutable Mutex mMutex;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800305 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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800313#endif
314};
315
316// ---------------------------------------------------------------------------
317
318void RefBase::incStrong(const void* id) const
319{
320 weakref_impl* const refs = mRefs;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800321 refs->incWeak(id);
322
323 refs->addStrongRef(id);
324 const int32_t c = android_atomic_inc(&refs->mStrong);
Steve Blockae074452012-01-09 18:35:44 +0000325 ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800326#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000327 ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800328#endif
329 if (c != INITIAL_STRONG_VALUE) {
330 return;
331 }
332
333 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
Mathias Agopianad099652011-08-10 21:07:02 -0700334 refs->mBase->onFirstRef();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800335}
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
Steve Blockeb095332011-12-20 16:23:08 +0000343 ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800344#endif
Steve Blockae074452012-01-09 18:35:44 +0000345 ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800346 if (c == 1) {
Mathias Agopianad099652011-08-10 21:07:02 -0700347 refs->mBase->onLastStrongRef(id);
348 if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700349 delete this;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800350 }
351 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800352 refs->decWeak(id);
353}
354
355void RefBase::forceIncStrong(const void* id) const
356{
357 weakref_impl* const refs = mRefs;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800358 refs->incWeak(id);
359
360 refs->addStrongRef(id);
361 const int32_t c = android_atomic_inc(&refs->mStrong);
Steve Blockae074452012-01-09 18:35:44 +0000362 ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800363 refs);
364#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000365 ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800366#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:
Mathias Agopianad099652011-08-10 21:07:02 -0700373 refs->mBase->onFirstRef();
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800374 }
375}
376
377int32_t RefBase::getStrongCount() const
378{
379 return mRefs->mStrong;
380}
381
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800382RefBase* 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);
Steve Blockae074452012-01-09 18:35:44 +0000392 ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800393}
394
Mathias Agopianad099652011-08-10 21:07:02 -0700395
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800396void 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);
Steve Blockae074452012-01-09 18:35:44 +0000401 ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800402 if (c != 1) return;
Mathias Agopianad099652011-08-10 21:07:02 -0700403
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.
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700412 delete impl->mBase;
Mathias Agopianad099652011-08-10 21:07:02 -0700413 } else {
Steve Blockb37fbe92011-10-20 11:56:00 +0100414 // ALOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800415 delete impl;
416 }
417 } else {
Mathias Agopianad099652011-08-10 21:07:02 -0700418 // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800419 impl->mBase->onLastWeakRef(id);
Mathias Agopianad099652011-08-10 21:07:02 -0700420 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.
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700423 delete impl->mBase;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800424 }
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);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800433 int32_t curCount = impl->mStrong;
Dianne Hackborna729ab12013-03-14 15:26:30 -0700434
435 ALOG_ASSERT(curCount >= 0,
436 "attemptIncStrong called on %p after underflow", this);
437
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800438 while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
Dianne Hackborna729ab12013-03-14 15:26:30 -0700439 // we're in the easy/common case of promoting a weak-reference
440 // from an existing strong reference.
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800441 if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
442 break;
443 }
Dianne Hackborna729ab12013-03-14 15:26:30 -0700444 // the strong count has changed on us, we need to re-assert our
445 // situation.
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800446 curCount = impl->mStrong;
447 }
448
449 if (curCount <= 0 || curCount == INITIAL_STRONG_VALUE) {
Dianne Hackborna729ab12013-03-14 15:26:30 -0700450 // 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 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800482 } else {
Dianne Hackborna729ab12013-03-14 15:26:30 -0700483 // 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);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800494 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800495
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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800506 impl->addStrongRef(id);
507
508#if PRINT_REFS
Steve Blockeb095332011-12-20 16:23:08 +0000509 ALOGD("attemptIncStrong of %p from %p: cnt=%d\n", this, id, curCount);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800510#endif
511
Dianne Hackborna729ab12013-03-14 15:26:30 -0700512 // 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;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800527 }
Dianne Hackborna729ab12013-03-14 15:26:30 -0700528
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800529 return true;
530}
531
532bool RefBase::weakref_type::attemptIncWeak(const void* id)
533{
534 weakref_impl* const impl = static_cast<weakref_impl*>(this);
Mathias Agopianad099652011-08-10 21:07:02 -0700535
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800536 int32_t curCount = impl->mWeak;
Steve Blockae074452012-01-09 18:35:44 +0000537 ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800538 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{
Mathias Agopianad099652011-08-10 21:07:02 -0700565 static_cast<weakref_impl*>(this)->trackMe(enable, retain);
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800566}
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{
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800582}
583
584RefBase::~RefBase()
585{
Mathias Agopianad099652011-08-10 21:07:02 -0700586 if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
587 // we never acquired a strong (and/or weak) reference on this object.
Mathias Agopian9c8fa9e2011-06-15 20:42:47 -0700588 delete mRefs;
Mathias Agopianad099652011-08-10 21:07:02 -0700589 } 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 }
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800600 }
Mathias Agopianad099652011-08-10 21:07:02 -0700601 // for debugging purposes, clear this.
602 const_cast<weakref_impl*&>(mRefs) = NULL;
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800603}
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}
Mathias Agopianad099652011-08-10 21:07:02 -0700626
627// ---------------------------------------------------------------------------
628
Mathias Agopian6cd548c2013-03-18 22:27:41 -0700629void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
Mathias Agopianad099652011-08-10 21:07:02 -0700630#if DEBUG_REFS
Mathias Agopianad099652011-08-10 21:07:02 -0700631 for (size_t i=0 ; i<n ; i++) {
Mathias Agopian6cd548c2013-03-18 22:27:41 -0700632 renamer(i);
Mathias Agopianad099652011-08-10 21:07:02 -0700633 }
634#endif
635}
636
Mathias Agopian6cd548c2013-03-18 22:27:41 -0700637void 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
The Android Open Source Projectcbb10112009-03-03 19:31:44 -0800650}; // namespace android