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