rsObjectBase.cpp revision d216dafa216f3329577ab624cdc5a5d1860ec035
1/*
2 * Copyright (C) 2009 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#include "rsObjectBase.h"
18#include "rsContext.h"
19
20using namespace android;
21using namespace android::renderscript;
22
23pthread_mutex_t ObjectBase::gObjectInitMutex = PTHREAD_MUTEX_INITIALIZER;
24
25ObjectBase::ObjectBase(Context *rsc) {
26    mUserRefCount = 0;
27    mSysRefCount = 0;
28    mRSC = rsc;
29    mNext = NULL;
30    mPrev = NULL;
31    mDH = NULL;
32
33#if RS_OBJECT_DEBUG
34    mDH = new DebugHelper();
35#endif
36
37    rsAssert(rsc);
38    add();
39    //ALOGV("ObjectBase %p con", this);
40}
41
42ObjectBase::~ObjectBase() {
43    //ALOGV("~ObjectBase %p  ref %i,%i", this, mUserRefCount, mSysRefCount);
44#if RS_OBJECT_DEBUG
45    mDH->dump();
46    delete mDH;
47    mDH = NULL;
48#endif
49
50    if (mPrev || mNext) {
51        // While the normal practice is to call remove before we call
52        // delete.  Its possible for objects without a re-use list
53        // for avoiding duplication to be created on the stack.  In those
54        // cases we need to remove ourself here.
55        asyncLock();
56        remove();
57        asyncUnlock();
58    }
59
60    rsAssert(!mUserRefCount);
61    rsAssert(!mSysRefCount);
62}
63
64void ObjectBase::dumpLOGV(const char *op) const {
65    if (mName.size()) {
66        ALOGV("%s RSobj %p, name %s, refs %i,%i  links %p,%p,%p",
67             op, this, mName.string(), mUserRefCount, mSysRefCount, mNext, mPrev, mRSC);
68    } else {
69        ALOGV("%s RSobj %p, no-name, refs %i,%i  links %p,%p,%p",
70             op, this, mUserRefCount, mSysRefCount, mNext, mPrev, mRSC);
71    }
72}
73
74void ObjectBase::incUserRef() const {
75    __sync_fetch_and_add(&mUserRefCount, 1);
76    //ALOGV("ObjectBase %p incU ref %i, %i", this, mUserRefCount, mSysRefCount);
77}
78
79void ObjectBase::incSysRef() const {
80    __sync_fetch_and_add(&mSysRefCount, 1);
81    //ALOGV("ObjectBase %p incS ref %i, %i", this, mUserRefCount, mSysRefCount);
82}
83
84void ObjectBase::preDestroy() const {
85}
86
87bool ObjectBase::freeChildren() {
88    return false;
89}
90
91bool ObjectBase::checkDelete(const ObjectBase *ref) {
92    if (!ref) {
93        return false;
94    }
95
96    asyncLock();
97    // This lock protects us against the non-RS threads changing
98    // the ref counts.  At this point we should be the only thread
99    // working on them.
100    if (ref->mUserRefCount || ref->mSysRefCount) {
101        asyncUnlock();
102        return false;
103    }
104
105    ref->remove();
106    // At this point we can unlock because there should be no possible way
107    // for another thread to reference this object.
108    ref->preDestroy();
109    asyncUnlock();
110    delete ref;
111    return true;
112}
113
114bool ObjectBase::decUserRef() const {
115    rsAssert(mUserRefCount > 0);
116#if RS_OBJECT_DEBUG
117    //ALOGV("ObjectBase %p decU ref %i, %i", this, mUserRefCount, mSysRefCount);
118    if (mUserRefCount <= 0) {
119        mDH->dump();
120    }
121#endif
122
123
124    if ((__sync_fetch_and_sub(&mUserRefCount, 1) <= 1)) {
125        __sync_synchronize();
126        if (mSysRefCount <= 0) {
127            return checkDelete(this);
128        }
129    }
130    return false;
131}
132
133bool ObjectBase::zeroUserRef() const {
134    //ALOGV("ObjectBase %p zeroU ref %i, %i", this, mUserRefCount, mSysRefCount);
135    __sync_and_and_fetch(&mUserRefCount, 0);
136    if ((__sync_fetch_and_sub(&mUserRefCount, 1) <= 1)) {
137        __sync_synchronize();
138        if (mSysRefCount <= 0) {
139            return checkDelete(this);
140        }
141    }
142    return false;
143}
144
145bool ObjectBase::decSysRef() const {
146    //ALOGV("ObjectBase %p decS ref %i, %i", this, mUserRefCount, mSysRefCount);
147    rsAssert(mSysRefCount > 0);
148    if ((__sync_fetch_and_sub(&mSysRefCount, 1) <= 1)) {
149        __sync_synchronize();
150        if (mUserRefCount <= 0) {
151            return checkDelete(this);
152        }
153    }
154    return false;
155}
156
157void ObjectBase::setName(const char *name) {
158    mName.setTo(name);
159}
160
161void ObjectBase::setName(const char *name, uint32_t len) {
162    mName.setTo(name, len);
163}
164
165void ObjectBase::asyncLock() {
166    pthread_mutex_lock(&gObjectInitMutex);
167}
168
169void ObjectBase::asyncUnlock() {
170    pthread_mutex_unlock(&gObjectInitMutex);
171}
172
173void ObjectBase::add() const {
174    asyncLock();
175
176    rsAssert(!mNext);
177    rsAssert(!mPrev);
178    //ALOGV("calling add  rsc %p", mRSC);
179    mNext = mRSC->mObjHead;
180    if (mRSC->mObjHead) {
181        mRSC->mObjHead->mPrev = this;
182    }
183    mRSC->mObjHead = this;
184
185    asyncUnlock();
186}
187
188void ObjectBase::remove() const {
189    //ALOGV("calling remove  rsc %p", mRSC);
190    if (!mRSC) {
191        rsAssert(!mPrev);
192        rsAssert(!mNext);
193        return;
194    }
195
196    if (mRSC->mObjHead == this) {
197        mRSC->mObjHead = mNext;
198    }
199    if (mPrev) {
200        mPrev->mNext = mNext;
201    }
202    if (mNext) {
203        mNext->mPrev = mPrev;
204    }
205    mPrev = NULL;
206    mNext = NULL;
207}
208
209void ObjectBase::zeroAllUserRef(Context *rsc) {
210    if (rsc->props.mLogObjects) {
211        ALOGV("Forcing release of all outstanding user refs.");
212    }
213
214    // This operation can be slow, only to be called during context cleanup.
215    const ObjectBase * o = rsc->mObjHead;
216    while (o) {
217        //ALOGE("o %p", o);
218        if (o->zeroUserRef()) {
219            // deleted the object and possibly others, restart from head.
220            o = rsc->mObjHead;
221            //ALOGE("o head %p", o);
222        } else {
223            o = o->mNext;
224            //ALOGE("o next %p", o);
225        }
226    }
227
228    if (rsc->props.mLogObjects) {
229        ALOGV("Objects remaining.");
230        dumpAll(rsc);
231    }
232}
233
234void ObjectBase::freeAllChildren(Context *rsc) {
235    if (rsc->props.mLogObjects) {
236        ALOGV("Forcing release of all child objects.");
237    }
238
239    // This operation can be slow, only to be called during context cleanup.
240    ObjectBase * o = (ObjectBase *)rsc->mObjHead;
241    while (o) {
242        if (o->freeChildren()) {
243            // deleted ref to self and possibly others, restart from head.
244            o = (ObjectBase *)rsc->mObjHead;
245        } else {
246            o = (ObjectBase *)o->mNext;
247        }
248    }
249
250    if (rsc->props.mLogObjects) {
251        ALOGV("Objects remaining.");
252        dumpAll(rsc);
253    }
254}
255
256void ObjectBase::dumpAll(Context *rsc) {
257    asyncLock();
258
259    ALOGV("Dumping all objects");
260    const ObjectBase * o = rsc->mObjHead;
261    while (o) {
262        ALOGV(" Object %p", o);
263        o->dumpLOGV("  ");
264        o = o->mNext;
265    }
266
267    asyncUnlock();
268}
269
270bool ObjectBase::isValid(const Context *rsc, const ObjectBase *obj) {
271    asyncLock();
272
273    const ObjectBase * o = rsc->mObjHead;
274    while (o) {
275        if (o == obj) {
276            asyncUnlock();
277            return true;
278        }
279        o = o->mNext;
280    }
281    asyncUnlock();
282    return false;
283}
284
285